Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace wif models and client with sdk #643

Merged
merged 6 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 70 additions & 55 deletions cmd/ocm/gcp/create-wif-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import (
"strings"

"github.com/googleapis/gax-go/v2/apierror"
alphaocm "github.com/openshift-online/ocm-cli/pkg/alpha_ocm"

"cloud.google.com/go/iam/admin/apiv1/adminpb"
"github.com/openshift-online/ocm-cli/pkg/gcp"
"github.com/openshift-online/ocm-cli/pkg/models"
"github.com/openshift-online/ocm-cli/pkg/ocm"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/pkg/errors"

"github.com/spf13/cobra"
Expand All @@ -31,17 +31,11 @@ var (
Project: "",
TargetDir: "",
}

//nolint:lll
impersonatorServiceAccount = "projects/sda-ccs-3/serviceAccounts/[email protected]"
impersonatorEmail = "[email protected]"
)

const (
poolDescription = "Created by the OLM CLI"
roleDescription = "Created by the OLM CLI"

openShiftAudience = "openshift"
)

// NewCreateWorkloadIdentityConfiguration provides the "gcp create wif-config" subcommand
Expand Down Expand Up @@ -76,26 +70,27 @@ func createWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) {
}

log.Println("Creating workload identity configuration...")
wifConfig, err := createWorkloadIdentityConfiguration(models.WifConfigInput{
DisplayName: CreateWifConfigOpts.Name,
ProjectId: CreateWifConfigOpts.Project,
})
wifConfig, err := createWorkloadIdentityConfiguration(CreateWifConfigOpts.Name, CreateWifConfigOpts.Project)
if err != nil {
log.Fatalf("failed to create WIF config: %v", err)
}

poolSpec := gcp.WorkloadIdentityPoolSpec{
PoolName: wifConfig.Status.WorkloadIdentityPoolData.PoolId,
ProjectId: wifConfig.Status.WorkloadIdentityPoolData.ProjectId,
Jwks: wifConfig.Status.WorkloadIdentityPoolData.Jwks,
IssuerUrl: wifConfig.Status.WorkloadIdentityPoolData.IssuerUrl,
PoolIdentityProviderId: wifConfig.Status.WorkloadIdentityPoolData.IdentityProviderId,
PoolName: wifConfig.Gcp().WorkloadIdentityPool().PoolId(),
ProjectId: wifConfig.Gcp().ProjectId(),
Jwks: wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().Jwks(),
IssuerUrl: wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IssuerUrl(),
PoolIdentityProviderId: wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IdentityProviderId(),
}

if CreateWifConfigOpts.DryRun {
log.Printf("Writing script files to %s", CreateWifConfigOpts.TargetDir)

err := createScript(CreateWifConfigOpts.TargetDir, wifConfig)
projectNum, err := gcpClient.ProjectNumberFromId(wifConfig.Gcp().ProjectId())
if err != nil {
log.Fatalf("failed to get project number from id: %v", err)
}
err = createScript(CreateWifConfigOpts.TargetDir, wifConfig, projectNum)
if err != nil {
log.Fatalf("Failed to create script files: %s", err)
}
Expand All @@ -104,17 +99,17 @@ func createWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) {

if err = createWorkloadIdentityPool(ctx, gcpClient, poolSpec); err != nil {
log.Printf("Failed to create workload identity pool: %s", err)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.Metadata.Id)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.ID())
}

if err = createWorkloadIdentityProvider(ctx, gcpClient, poolSpec); err != nil {
log.Printf("Failed to create workload identity provider: %s", err)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.Metadata.Id)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.ID())
}

if err = createServiceAccounts(ctx, gcpClient, wifConfig); err != nil {
log.Printf("Failed to create IAM service accounts: %s", err)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.Metadata.Id)
log.Fatalf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.ID())
}

}
Expand Down Expand Up @@ -151,16 +146,34 @@ func validationForCreateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, arg

}

func createWorkloadIdentityConfiguration(input models.WifConfigInput) (*models.WifConfigOutput, error) {
ocmClient, err := alphaocm.NewOcmClient()
func createWorkloadIdentityConfiguration(displayName, projectId string) (*cmv1.WifConfig, error) {
connection, err := ocm.NewConnection().Build()
if err != nil {
log.Fatal(err)
}
defer connection.Close()

wifBuilder := cmv1.NewWifConfig()
gcpBuilder := cmv1.NewWifGcp().ProjectId(projectId)

wifBuilder.DisplayName(displayName)
wifBuilder.Gcp(gcpBuilder)

wifConfigInput, err := wifBuilder.Build()
if err != nil {
return nil, errors.Wrap(err, "failed to create backend client")
return nil, errors.Wrap(err, "failed to build WIF config")
}
output, err := ocmClient.CreateWifConfig(input)

response, err := connection.ClustersMgmt().V1().
WifConfigs().
Add().
Body(wifConfigInput).
Send()
if err != nil {
return nil, errors.Wrap(err, "failed to create wif config")
return nil, errors.Wrap(err, "failed to create WIF config")
}
return &output, nil

return response.Body(), nil
}

func createWorkloadIdentityPool(ctx context.Context, client gcp.GcpClient,
Expand Down Expand Up @@ -218,7 +231,7 @@ func createWorkloadIdentityProvider(ctx context.Context, client gcp.GcpClient,
State: "ACTIVE",
Disabled: false,
Oidc: &iamv1.Oidc{
AllowedAudiences: []string{openShiftAudience},
AllowedAudiences: spec.Audience,
IssuerUri: spec.IssuerUrl,
JwksJson: spec.Jwks,
},
Expand All @@ -245,17 +258,17 @@ func createWorkloadIdentityProvider(ctx context.Context, client gcp.GcpClient,
return nil
}

func createServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient, wifOutput *models.WifConfigOutput) error {
projectId := wifOutput.Spec.ProjectId
fmtRoleResourceId := func(role models.Role) string {
return fmt.Sprintf("roles/%s", role.Id)
func createServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient, wifConfig *cmv1.WifConfig) error {
projectId := wifConfig.Gcp().ProjectId()
fmtRoleResourceId := func(role *cmv1.WifRole) string {
return fmt.Sprintf("roles/%s", role.RoleId())
}

// Create service accounts
for _, serviceAccount := range wifOutput.Status.ServiceAccounts {
serviceAccountID := serviceAccount.Id
serviceAccountName := wifOutput.Spec.DisplayName + "-" + serviceAccountID
serviceAccountDesc := poolDescription + " for WIF config " + wifOutput.Spec.DisplayName
for _, serviceAccount := range wifConfig.Gcp().ServiceAccounts() {
serviceAccountID := serviceAccount.ServiceAccountId()
serviceAccountName := wifConfig.DisplayName() + "-" + serviceAccountID
serviceAccountDesc := poolDescription + " for WIF config " + wifConfig.DisplayName()

_, err := createServiceAccount(gcpClient, serviceAccountID, serviceAccountName, serviceAccountDesc, projectId, true)
if err != nil {
Expand All @@ -265,14 +278,14 @@ func createServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient, wifOutp
}

// Create roles that aren't predefined
for _, serviceAccount := range wifOutput.Status.ServiceAccounts {
for _, role := range serviceAccount.Roles {
if role.Predefined {
for _, serviceAccount := range wifConfig.Gcp().ServiceAccounts() {
for _, role := range serviceAccount.Roles() {
if role.Predefined() {
continue
}
roleID := role.Id
roleName := role.Id
permissions := role.Permissions
roleID := role.RoleId()
roleName := role.RoleId()
permissions := role.Permissions()
existingRole, err := GetRole(gcpClient, roleID, projectId)
if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 &&
Expand Down Expand Up @@ -300,11 +313,11 @@ func createServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient, wifOutp
}

// Bind roles and grant access
for _, serviceAccount := range wifOutput.Status.ServiceAccounts {
serviceAccountID := serviceAccount.Id
for _, serviceAccount := range wifConfig.Gcp().ServiceAccounts() {
serviceAccountID := serviceAccount.ServiceAccountId()

roles := make([]string, 0, len(serviceAccount.Roles))
for _, role := range serviceAccount.Roles {
roles := make([]string, 0, len(serviceAccount.Roles()))
for _, role := range serviceAccount.Roles() {
roles = append(roles, fmtRoleResourceId(role))
}
member := fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", serviceAccountID, projectId)
Expand All @@ -313,19 +326,21 @@ func createServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient, wifOutp
return errors.Errorf("Failed to bind roles to service account %s: %s", serviceAccountID, err)
}

switch serviceAccount.AccessMethod {
case "impersonate":
if err := gcpClient.AttachImpersonator(serviceAccount.Id, projectId,
impersonatorServiceAccount); err != nil {
return errors.Wrapf(err, "Failed to attach impersonator to service account %s", serviceAccount.Id)
switch serviceAccount.AccessMethod() {
case cmv1.WifAccessMethodImpersonate:
if err := gcpClient.AttachImpersonator(serviceAccount.ServiceAccountId(), projectId,
wifConfig.Gcp().ImpersonatorEmail()); err != nil {
return errors.Wrapf(err, "Failed to attach impersonator to service account %s",
serviceAccount.ServiceAccountId())
}
case "wif":
case cmv1.WifAccessMethodWif:
if err := gcpClient.AttachWorkloadIdentityPool(serviceAccount,
wifOutput.Status.WorkloadIdentityPoolData.PoolId, projectId); err != nil {
return errors.Wrapf(err, "Failed to attach workload identity pool to service account %s", serviceAccount.Id)
wifConfig.Gcp().WorkloadIdentityPool().PoolId(), projectId); err != nil {
return errors.Wrapf(err, "Failed to attach workload identity pool to service account %s",
serviceAccount.ServiceAccountId())
}
default:
log.Printf("Warning: %s is not a supported access type\n", serviceAccount.AccessMethod)
log.Printf("Warning: %s is not a supported access type\n", serviceAccount.AccessMethod())
}
}

Expand Down
43 changes: 24 additions & 19 deletions cmd/ocm/gcp/delete-wif-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"github.com/googleapis/gax-go/v2/apierror"
"google.golang.org/grpc/codes"

alphaocm "github.com/openshift-online/ocm-cli/pkg/alpha_ocm"
"github.com/openshift-online/ocm-cli/pkg/gcp"
"github.com/openshift-online/ocm-cli/pkg/models"
"github.com/openshift-online/ocm-cli/pkg/ocm"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
"github.com/pkg/errors"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -59,21 +59,23 @@ func deleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) {
log.Fatal("WIF config ID is required")
}

// Create clients
ocmClient, err := alphaocm.NewOcmClient()
// Create the client for the OCM API:
connection, err := ocm.NewConnection().Build()
if err != nil {
log.Fatalf("failed to create backend client: %v", err)
log.Fatal(err)
Copy link
Collaborator

@ckandag ckandag Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does the end user see when this happens ? error stack ?

Copy link
Collaborator

@ckandag ckandag Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we previously discussed bubbling up the errors to the caller and allow the top level "Run" function decide how to handle/display the error.

I dont see these kind of Fatal log msgs anywhere in the else in the ocm or rosa cli code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example error:

➜  go run ./cmd/ocm gcp delete wif-config 2crdacmjbo3jmdgfn4dq791a7nig04qg
2024/07/30 14:25:07 Not logged in, credentials aren't set, run the 'login' command
exit status 1

This is the top level Run function.

}
defer connection.Close()

wifConfig, err := ocmClient.GetWifConfig(wifConfigId)
response, err := connection.ClustersMgmt().V1().WifConfigs().WifConfig(wifConfigId).Get().Send()
if err != nil {
log.Fatal(err)
log.Fatalf("failed to get wif-config: %v", err)
}
wifConfig := response.Body()

if DeleteWifConfigOpts.DryRun {
log.Printf("Writing script files to %s", DeleteWifConfigOpts.TargetDir)

err := createDeleteScript(DeleteWifConfigOpts.TargetDir, &wifConfig)
err := createDeleteScript(DeleteWifConfigOpts.TargetDir, wifConfig)
if err != nil {
log.Fatalf("Failed to create script files: %s", err)
}
Expand All @@ -85,27 +87,30 @@ func deleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) {
log.Fatal(err)
}

if err := deleteServiceAccounts(ctx, gcpClient, &wifConfig, true); err != nil {
if err := deleteServiceAccounts(ctx, gcpClient, wifConfig, true); err != nil {
log.Fatal(err)
}

if err := deleteWorkloadIdentityPool(ctx, gcpClient, &wifConfig, true); err != nil {
if err := deleteWorkloadIdentityPool(ctx, gcpClient, wifConfig, true); err != nil {
log.Fatal(err)
}

err = ocmClient.DeleteWifConfig(wifConfigId)
_, err = connection.ClustersMgmt().V1().WifConfigs().
WifConfig(wifConfigId).
Delete().
Send()
if err != nil {
log.Fatal(err)
log.Fatalf("failed to delete wif config %q: %v", wifConfigId, err)
}
}

func deleteServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient,
wifConfig *models.WifConfigOutput, allowMissing bool) error {
wifConfig *cmv1.WifConfig, allowMissing bool) error {
log.Println("Deleting service accounts...")
projectId := wifConfig.Spec.ProjectId
projectId := wifConfig.Gcp().ProjectId()

for _, serviceAccount := range wifConfig.Status.ServiceAccounts {
serviceAccountID := serviceAccount.Id
for _, serviceAccount := range wifConfig.Gcp().ServiceAccounts() {
serviceAccountID := serviceAccount.ServiceAccountId()
log.Println("Deleting service account", serviceAccountID)
err := gcpClient.DeleteServiceAccount(serviceAccountID, projectId, allowMissing)
if err != nil {
Expand All @@ -117,10 +122,10 @@ func deleteServiceAccounts(ctx context.Context, gcpClient gcp.GcpClient,
}

func deleteWorkloadIdentityPool(ctx context.Context, gcpClient gcp.GcpClient,
wifConfig *models.WifConfigOutput, allowMissing bool) error {
wifConfig *cmv1.WifConfig, allowMissing bool) error {
log.Println("Deleting workload identity pool...")
projectId := wifConfig.Spec.ProjectId
poolName := wifConfig.Status.WorkloadIdentityPoolData.PoolId
projectId := wifConfig.Gcp().ProjectId()
poolName := wifConfig.Gcp().WorkloadIdentityPool().PoolId()
poolResource := fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", projectId, poolName)

_, err := gcpClient.DeleteWorkloadIdentityPool(ctx, poolResource)
Expand Down
20 changes: 10 additions & 10 deletions cmd/ocm/gcp/describe-wif-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"os"
"text/tabwriter"

alphaocm "github.com/openshift-online/ocm-cli/pkg/alpha_ocm"
"github.com/openshift-online/ocm-cli/pkg/ocm"
"github.com/openshift-online/ocm-cli/pkg/urls"
"github.com/spf13/cobra"
)
Expand All @@ -30,25 +30,25 @@ func describeWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string)
}

// Create the client for the OCM API:
ocmClient, err := alphaocm.NewOcmClient()
connection, err := ocm.NewConnection().Build()
if err != nil {
log.Fatalf("failed to create backend client: %v", err)
log.Fatal(err)
}
defer connection.Close()

wifconfig, err := ocmClient.GetWifConfig(id)
response, err := connection.ClustersMgmt().V1().WifConfigs().WifConfig(id).Get().Send()
if err != nil {
log.Fatalf("failed to get wif-config: %v", err)
}
wifConfig := response.Body()

// Print output
w := tabwriter.NewWriter(os.Stdout, 8, 0, 2, ' ', 0)

fmt.Fprintf(w, "ID:\t%s\n", wifconfig.Metadata.Id)
fmt.Fprintf(w, "Display Name:\t%s\n", wifconfig.Metadata.DisplayName)
fmt.Fprintf(w, "Project:\t%s\n", wifconfig.Spec.ProjectId)
fmt.Fprintf(w, "State:\t%s\n", wifconfig.Status.State)
fmt.Fprintf(w, "Summary:\t%s\n", wifconfig.Status.Summary)
fmt.Fprintf(w, "Issuer URL:\t%s\n", wifconfig.Status.WorkloadIdentityPoolData.IssuerUrl)
fmt.Fprintf(w, "ID:\t%s\n", wifConfig.ID())
fmt.Fprintf(w, "Display Name:\t%s\n", wifConfig.DisplayName())
fmt.Fprintf(w, "Project:\t%s\n", wifConfig.Gcp().ProjectId())
fmt.Fprintf(w, "Issuer URL:\t%s\n", wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IssuerUrl())

w.Flush()
}
Expand Down
Loading
Loading