Skip to content

Commit

Permalink
Content guards for Pulp (RedHatInsights#2652)
Browse files Browse the repository at this point in the history
  • Loading branch information
lzap authored Jul 24, 2024
1 parent bc46b1d commit 26864ff
Show file tree
Hide file tree
Showing 15 changed files with 22,415 additions and 12,600 deletions.
11 changes: 6 additions & 5 deletions cmd/pulpcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,29 @@ func fixtureCreate(ctx context.Context, c *pulp.PulpService, orgID, tarFilename
fmt.Println("Repository created", *repo.PulpHref)
fmt.Println("--------------------------------")

hcg, err := c.HeaderGuardReadOrCreate(ctx, pulp.JQOrgID, orgID)
cg, err := c.ContentGuardEnsure(ctx, orgID)
if err != nil {
panic(err)
}
fmt.Println("Header guard found or created", *hcg.PulpHref)
fmt.Println("Content guard found or created", *cg.PulpHref, (*cg.Guards)[0], (*cg.Guards)[1])
fmt.Println("--------------------------------")

dist, err := c.DistributionsCreate(ctx, resourceName, resourceName, *repo.PulpHref, *hcg.PulpHref)
dist, err := c.DistributionsCreate(ctx, resourceName, resourceName, *repo.PulpHref, *cg.PulpHref)
if err != nil {
panic(err)
}
fmt.Println("Distribution created", *dist.PulpHref)
fmt.Println("--------------------------------")

repoImported, err := c.RepositoriesImport(ctx, pulp.ScanUUID(*repo.PulpHref), "repo", *artifact.PulpHref)
repoImported, err := c.RepositoriesImport(ctx, pulp.ScanUUID(repo.PulpHref), "repo", *artifact.PulpHref)
if err != nil {
panic(err)
}
fmt.Println("Repository imported", *repoImported.PulpHref)
fmt.Println("--------------------------------")

fmt.Printf("curl -L --proxy http://squid.xxxx.redhat.com:3128 --cert /etc/pki/consumer/cert.pem --key /etc/pki/consumer/key.pem https://cert.console.stage.redhat.com/api/pulp-content/%s/%s/\n", c.Domain(), resourceName)
fmt.Printf("curl -L --proxy http://squid.xxxx.redhat.com:3128 -u edge-content-dev:XXXX https://pulp.stage.xxxx.net/api/pulp-content/%s/%s/\n", c.Domain(), resourceName)
fmt.Println("--------------------------------")
}

Expand All @@ -91,7 +92,7 @@ func main() {
if err != nil {
panic(err)
}
fmt.Println("Created domain:", pulp.ScanUUID(*createdDomain.PulpHref), ", please update the domainHref in the test source!")
fmt.Println("Created domain:", pulp.ScanUUID(createdDomain.PulpHref), ", please update the domainHref in the test source!")
return
}

Expand Down
6 changes: 6 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type EdgeConfig struct {
PulpURL string `json:"pulp_url,omitempty"`
PulpUsername string `json:"pulp_username,omitempty"`
PulpPassword string `json:"pulp_password,omitempty"`
PulpContentUsername string `json:"pulp_content_username,omitempty"`
PulpContentPassword string `json:"pulp_content_password,omitempty"`
PulpIdentityName string `json:"pulp_identity_name,omitempty"`
PulpProxyURL string `json:"pulp_proxy_url,omitempty"`
PulpOauth2URL string `json:"pulp_oauth2_url,omitempty"`
Expand Down Expand Up @@ -185,6 +187,8 @@ func CreateEdgeAPIConfig() (*EdgeConfig, error) {
options.SetDefault("PulpURL", "http://pulp-service:8080")
options.SetDefault("PulpUsername", "edge-api-dev")
options.SetDefault("PulpPassword", "")
options.SetDefault("PulpContentUsername", "edge-content-dev")
options.SetDefault("PulpContentPassword", "")
options.SetDefault("PulpIdentityName", "edge-api-dev")
options.SetDefault("PulpProxyURL", "")
options.SetDefault("PulpOauth2URL", "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token")
Expand Down Expand Up @@ -297,6 +301,8 @@ func CreateEdgeAPIConfig() (*EdgeConfig, error) {
PulpURL: options.GetString("PulpURL"),
PulpUsername: options.GetString("PulpUsername"),
PulpPassword: options.GetString("PulpPassword"),
PulpContentUsername: options.GetString("PulpContentUsername"),
PulpContentPassword: options.GetString("PulpContentPassword"),
PulpIdentityName: options.GetString("PulpIdentityName"),
PulpProxyURL: options.GetString("PulpProxyURL"),
PulpOauth2URL: options.GetString("PulpOauth2URL"),
Expand Down
2 changes: 1 addition & 1 deletion pkg/clients/pulp/artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ func (ps *PulpService) ArtifactsList(ctx context.Context, sha256 string) ([]Arti
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

if resp.JSON200.Count >= DefaultPageSize {
if resp.JSON200.Count > DefaultPageSize {
return nil, fmt.Errorf("default page size too small: %d", resp.JSON200.Count)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/clients/pulp/distributions.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (ps *PulpService) DistributionsCreate(ctx context.Context, name, basePath,
return nil, err
}

result, err := ps.DistributionsRead(ctx, ScanUUID(href))
result, err := ps.DistributionsRead(ctx, ScanUUID(&href))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/clients/pulp/domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (ps *PulpService) DomainsList(ctx context.Context, nameFilter string) ([]Do
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

if resp.JSON200.Count >= DefaultPageSize {
if resp.JSON200.Count > DefaultPageSize {
return nil, fmt.Errorf("default page size too small: %d", resp.JSON200.Count)
}

Expand Down
163 changes: 163 additions & 0 deletions pkg/clients/pulp/guards_composite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package pulp

import (
"context"
"errors"
"fmt"

"github.com/google/uuid"
"github.com/redhatinsights/edge-api/pkg/ptr"
"github.com/sirupsen/logrus"
)

func compositeGuardName(orgID string) string {
return "EDGE_COMP_ORGID=" + orgID
}

// CompositeGuardCreate creates a new composite guard with the given orgID, headerHref, and rbacHref.
func (ps *PulpService) CompositeGuardCreate(ctx context.Context, orgID, headerHref, rbacHref string) (*CompositeContentGuardResponse, error) {
req := ContentguardsCoreCompositeCreateJSONRequestBody{
Name: compositeGuardName(orgID),
Guards: ptr.To([]string{headerHref, rbacHref}),
Description: ptr.To("EDGE"),
}
resp, err := ps.cwr.ContentguardsCoreCompositeCreateWithResponse(ctx, ps.dom, req, addAuthenticationHeader)

if err != nil {
return nil, err
}

if resp.JSON201 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

return resp.JSON201, nil
}

// CompositeGuardRead returns the composite guard with the given ID.
func (ps *PulpService) CompositeGuardRead(ctx context.Context, id uuid.UUID) (*CompositeContentGuardResponse, error) {
req := ContentguardsCoreCompositeReadParams{}
resp, err := ps.cwr.ContentguardsCoreCompositeReadWithResponse(ctx, ps.dom, id, &req, addAuthenticationHeader)

if err != nil {
return nil, err
}

if resp.JSON200 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

return resp.JSON200, nil
}

// CompositeGuardReadByOrgID returns the composite guard for the given orgID.
func (ps *PulpService) CompositeGuardReadByOrgID(ctx context.Context, orgID string) (*CompositeContentGuardResponse, error) {
hgl, err := ps.CompositeGuardList(ctx, orgID)
if err != nil {
return nil, err
}

if len(hgl) == 0 {
return nil, fmt.Errorf("composite guard not found for orgID %s: %w", orgID, ErrRecordNotFound)
}

id := ScanUUID(hgl[0].PulpHref)
return ps.CompositeGuardRead(ctx, id)
}

// CompositeGuardEnsure ensures that the composite guard is created and returns it. The method is idempotent.
func (ps *PulpService) CompositeGuardEnsure(ctx context.Context, orgID, headerHref, rbacHref string) (*CompositeContentGuardResponse, error) {
cg, err := ps.CompositeGuardReadByOrgID(ctx, compositeGuardName(orgID))
// nolint: gocritic
if errors.Is(err, ErrRecordNotFound) {
cg, err = ps.CompositeGuardCreate(ctx, orgID, headerHref, rbacHref)
if err != nil {
return nil, err
}

return cg, nil
} else if err != nil {
return nil, err
} else if cg == nil {
return nil, fmt.Errorf("unexpected nil guard")
}

gs := ptr.FromOrEmpty(cg.Guards)
if !(len(gs) == 2 && (gs[0] != headerHref && gs[1] != rbacHref) || (gs[1] != headerHref && gs[0] != rbacHref)) {
logrus.WithContext(ctx).Warnf("unexpected Composite Content Guard: %v, deleting it", gs)
err = ps.CompositeGuardDelete(ctx, ScanUUID(cg.PulpHref))
if err != nil {
return nil, err
}

cg, err = ps.CompositeGuardCreate(ctx, orgID, headerHref, rbacHref)
if err != nil {
return nil, err
}
}
return cg, nil
}

// ContentGuardEnsure ensures that the header and RBAC guards are created and returns the composite guard. If it finds
// that the composite guard is not created or the guards are not the same as the ones provided, it will delete it
// and recreate it. This method is idempotent and will not create the guards if they already exist.
func (ps *PulpService) ContentGuardEnsure(ctx context.Context, orgID string) (*CompositeContentGuardResponse, error) {
hcg, err := ps.HeaderGuardEnsure(ctx, orgID)
if err != nil {
return nil, err
}

rcg, err := ps.RbacGuardEnsure(ctx)
if err != nil {
return nil, err
}

ccg, err := ps.CompositeGuardEnsure(ctx, orgID, *hcg.PulpHref, *rcg.PulpHref)
if err != nil {
return nil, err
}

return ccg, nil
}

// CompositeGuardDelete deletes the composite guard with the given ID.
func (ps *PulpService) CompositeGuardDelete(ctx context.Context, id uuid.UUID) error {
resp, err := ps.cwr.ContentguardsCoreCompositeDelete(ctx, ps.dom, id, addAuthenticationHeader)

if err != nil {
return err
}
resp.Body.Close()

if resp.StatusCode != 204 {
return fmt.Errorf("unexpected response: %d", resp.StatusCode)
}

return nil
}

// CompositeGuardList returns a list of composite guards with the given name filter.
func (ps *PulpService) CompositeGuardList(ctx context.Context, nameFilter string) ([]CompositeContentGuardResponse, error) {
req := ContentguardsCoreCompositeListParams{
Limit: &DefaultPageSize,
}
if nameFilter != "" {
req.Name = &nameFilter
}

resp, err := ps.cwr.ContentguardsCoreCompositeListWithResponse(ctx, ps.dom, &req, addAuthenticationHeader)

if err != nil {
return nil, err
}

if resp.JSON200 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

if resp.JSON200.Count > DefaultPageSize {
return nil, fmt.Errorf("default page size too small: %d", resp.JSON200.Count)
}

return resp.JSON200.Results, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ import (
"fmt"

"github.com/google/uuid"
"github.com/redhatinsights/edge-api/pkg/ptr"
"github.com/sirupsen/logrus"
)

const JQOrgID = ".identity.org_id"

func formatName(name string) string {
return "ORGID=" + name
func headerGuardName(orgID string) string {
return "EDGE_HEADER_ORGID=" + orgID
}

func (ps *PulpService) HeaderGuardCreate(ctx context.Context, jq, orgID string) (*HeaderContentGuardResponse, error) {
// HeaderGuardCreate creates a new header guard for the given orgID.
func (ps *PulpService) HeaderGuardCreate(ctx context.Context, orgID string) (*HeaderContentGuardResponse, error) {
req := ContentguardsCoreHeaderCreateJSONRequestBody{
Name: formatName(orgID),
Name: headerGuardName(orgID),
HeaderName: "x-rh-identity",
HeaderValue: orgID,
JqFilter: &jq,
JqFilter: ptr.To(JQOrgID),
Description: ptr.To("EDGE"),
}
resp, err := ps.cwr.ContentguardsCoreHeaderCreateWithResponse(ctx, ps.dom, req, addAuthenticationHeader)

Expand All @@ -34,6 +38,7 @@ func (ps *PulpService) HeaderGuardCreate(ctx context.Context, jq, orgID string)
return resp.JSON201, nil
}

// HeaderGuardRead returns the header guard with the given ID.
func (ps *PulpService) HeaderGuardRead(ctx context.Context, id uuid.UUID) (*HeaderContentGuardResponse, error) {
req := ContentguardsCoreHeaderReadParams{}
resp, err := ps.cwr.ContentguardsCoreHeaderReadWithResponse(ctx, ps.dom, id, &req, addAuthenticationHeader)
Expand All @@ -49,6 +54,7 @@ func (ps *PulpService) HeaderGuardRead(ctx context.Context, id uuid.UUID) (*Head
return resp.JSON200, nil
}

// HeaderGuardReadByOrgID returns the header guard for the given orgID.
func (ps *PulpService) HeaderGuardReadByOrgID(ctx context.Context, orgID string) (*HeaderContentGuardResponse, error) {
hgl, err := ps.HeaderGuardList(ctx, orgID)
if err != nil {
Expand All @@ -59,26 +65,43 @@ func (ps *PulpService) HeaderGuardReadByOrgID(ctx context.Context, orgID string)
return nil, fmt.Errorf("header guard not found for orgID %s: %w", orgID, ErrRecordNotFound)
}

id := ScanUUID(*hgl[0].PulpHref)
id := ScanUUID(hgl[0].PulpHref)
return ps.HeaderGuardRead(ctx, id)
}

func (ps *PulpService) HeaderGuardReadOrCreate(ctx context.Context, jq, orgID string) (*HeaderContentGuardResponse, error) {
hg, err := ps.HeaderGuardReadByOrgID(ctx, formatName(orgID))
// HeaderGuardEnsure ensures that the header guard is created and returns it. The method is idempotent.
func (ps *PulpService) HeaderGuardEnsure(ctx context.Context, orgID string) (*HeaderContentGuardResponse, error) {
cg, err := ps.HeaderGuardReadByOrgID(ctx, headerGuardName(orgID))
// nolint: gocritic
if errors.Is(err, ErrRecordNotFound) {
hg, err = ps.HeaderGuardCreate(ctx, jq, orgID)
cg, err = ps.HeaderGuardCreate(ctx, orgID)
if err != nil {
return nil, err
}

return hg, nil
return cg, nil
} else if err != nil {
return nil, err
} else if cg == nil {
return nil, fmt.Errorf("unexpected nil guard")
}

return hg, nil
if cg.JqFilter == nil || *cg.JqFilter != JQOrgID {
logrus.WithContext(ctx).Warnf("unexpected Header Content Guard: %s, expected: %s, deleting it", ptr.FromOrEmpty(cg.JqFilter), JQOrgID)
err = ps.HeaderGuardDelete(ctx, ScanUUID(cg.PulpHref))
if err != nil {
return nil, err
}

cg, err = ps.HeaderGuardCreate(ctx, orgID)
if err != nil {
return nil, err
}
}
return cg, nil
}

// HeaderGuardDelete deletes the header guard with the given ID.
func (ps *PulpService) HeaderGuardDelete(ctx context.Context, id uuid.UUID) error {
resp, err := ps.cwr.ContentguardsCoreHeaderDelete(ctx, ps.dom, id, addAuthenticationHeader)

Expand All @@ -94,6 +117,7 @@ func (ps *PulpService) HeaderGuardDelete(ctx context.Context, id uuid.UUID) erro
return nil
}

// HeaderGuardList returns a list of header guards with the given name filter.
func (ps *PulpService) HeaderGuardList(ctx context.Context, nameFilter string) ([]HeaderContentGuardResponse, error) {
req := ContentguardsCoreHeaderListParams{
Limit: &DefaultPageSize,
Expand All @@ -112,7 +136,7 @@ func (ps *PulpService) HeaderGuardList(ctx context.Context, nameFilter string) (
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

if resp.JSON200.Count >= DefaultPageSize {
if resp.JSON200.Count > DefaultPageSize {
return nil, fmt.Errorf("default page size too small: %d", resp.JSON200.Count)
}

Expand Down
Loading

0 comments on commit 26864ff

Please sign in to comment.