From 21ff6b865404c52aaee7bfd30a261eb02fab9dff Mon Sep 17 00:00:00 2001 From: Jakob Gray <20209054+JakobGray@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:36:36 -0400 Subject: [PATCH] Replace wif models and client with sdk (#643) --- cmd/ocm/gcp/create-wif-config.go | 256 ++++++++++-------- cmd/ocm/gcp/delete-wif-config.go | 96 +++---- cmd/ocm/gcp/describe-wif-config.go | 43 +-- cmd/ocm/gcp/generate-wif-script.go | 57 ++-- cmd/ocm/gcp/get-wif-config.go | 49 ++-- cmd/ocm/gcp/iam.go | 26 +- cmd/ocm/gcp/list-wif-config.go | 72 +++-- cmd/ocm/gcp/scripting.go | 132 ++++----- cmd/ocm/gcp/update-wif-config.go | 14 +- go.mod | 2 +- go.sum | 4 +- pkg/alpha_ocm/client.go | 125 --------- pkg/gcp/client.go | 22 +- pkg/gcp/helpers.go | 9 - pkg/models/role.go | 8 - pkg/models/service_account.go | 36 --- pkg/models/wif_config_input.go | 6 - pkg/models/wif_config_list.go | 7 - pkg/models/wif_config_metadata.go | 7 - .../wif_config_metadata_organization.go | 6 - pkg/models/wif_config_output.go | 32 --- pkg/models/wif_config_status.go | 23 -- pkg/models/wif_template.go | 7 - pkg/output/tables/wifconfigs.yaml | 6 +- 24 files changed, 416 insertions(+), 629 deletions(-) delete mode 100644 pkg/alpha_ocm/client.go delete mode 100644 pkg/models/role.go delete mode 100644 pkg/models/service_account.go delete mode 100644 pkg/models/wif_config_input.go delete mode 100644 pkg/models/wif_config_list.go delete mode 100644 pkg/models/wif_config_metadata.go delete mode 100644 pkg/models/wif_config_metadata_organization.go delete mode 100644 pkg/models/wif_config_output.go delete mode 100644 pkg/models/wif_config_status.go delete mode 100644 pkg/models/wif_template.go diff --git a/cmd/ocm/gcp/create-wif-config.go b/cmd/ocm/gcp/create-wif-config.go index 3e6a8300..b97a8dc0 100644 --- a/cmd/ocm/gcp/create-wif-config.go +++ b/cmd/ocm/gcp/create-wif-config.go @@ -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" @@ -31,26 +31,20 @@ var ( Project: "", TargetDir: "", } - - //nolint:lll - impersonatorServiceAccount = "projects/sda-ccs-3/serviceAccounts/osd-impersonator@sda-ccs-3.iam.gserviceaccount.com" - impersonatorEmail = "osd-impersonator@sda-ccs-3.iam.gserviceaccount.com" ) const ( poolDescription = "Created by the OLM CLI" roleDescription = "Created by the OLM CLI" - - openShiftAudience = "openshift" ) // NewCreateWorkloadIdentityConfiguration provides the "gcp create wif-config" subcommand func NewCreateWorkloadIdentityConfiguration() *cobra.Command { createWifConfigCmd := &cobra.Command{ - Use: "wif-config", - Short: "Create workload identity configuration", - Run: createWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForCreateWorkloadIdentityConfigurationCmd, + Use: "wif-config", + Short: "Create workload identity configuration", + RunE: createWorkloadIdentityConfigurationCmd, + PreRunE: validationForCreateWorkloadIdentityConfigurationCmd, } createWifConfigCmd.PersistentFlags().StringVar(&CreateWifConfigOpts.Name, "name", "", @@ -67,70 +61,63 @@ func NewCreateWorkloadIdentityConfiguration() *cobra.Command { return createWifConfigCmd } -func createWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func createWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { ctx := context.Background() gcpClient, err := gcp.NewGcpClient(ctx) if err != nil { - log.Fatalf("failed to initiate GCP client: %v", err) + return errors.Wrapf(err, "failed to initiate GCP client") } 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, + return errors.Wrapf(err, "failed to create WIF config") } 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 create script files: %s", err) + return errors.Wrapf(err, "failed to get project number from id") } - return + err = createScript(CreateWifConfigOpts.TargetDir, wifConfig, projectNum) + if err != nil { + return errors.Wrapf(err, "Failed to create script files") + } + return nil } - if err = createWorkloadIdentityPool(ctx, gcpClient, poolSpec); err != nil { + if err = createWorkloadIdentityPool(ctx, gcpClient, wifConfig); 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) + return fmt.Errorf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.ID()) } - if err = createWorkloadIdentityProvider(ctx, gcpClient, poolSpec); err != nil { + if err = createWorkloadIdentityProvider(ctx, gcpClient, wifConfig); 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) + return fmt.Errorf("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) + return fmt.Errorf("To clean up, run the following command: ocm gcp delete wif-config %s", wifConfig.ID()) } - + return nil } -func validationForCreateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForCreateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { if CreateWifConfigOpts.Name == "" { - log.Fatal("Name is required") + return fmt.Errorf("Name is required") } if CreateWifConfigOpts.Project == "" { - log.Fatal("Project is required") + return fmt.Errorf("Project is required") } if CreateWifConfigOpts.TargetDir == "" { pwd, err := os.Getwd() if err != nil { - log.Fatalf("Failed to get current directory: %s", err) + return errors.Wrapf(err, "failed to get current directory") } CreateWifConfigOpts.TargetDir = pwd @@ -138,124 +125,152 @@ func validationForCreateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, arg fPath, err := filepath.Abs(CreateWifConfigOpts.TargetDir) if err != nil { - log.Fatalf("Failed to resolve full path: %s", err) + return errors.Wrapf(err, "failed to resolve full path") } sResult, err := os.Stat(fPath) if os.IsNotExist(err) { - log.Fatalf("Directory %s does not exist", fPath) + return fmt.Errorf("directory %s does not exist", fPath) } if !sResult.IsDir() { - log.Fatalf("file %s exists and is not a directory", fPath) + return fmt.Errorf("file %s exists and is not a directory", fPath) } - + return nil } -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 { + return nil, errors.Wrapf(err, "Failed to create OCM connection") + } + 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().GCP(). + 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, - spec gcp.WorkloadIdentityPoolSpec) error { - name := spec.PoolName - project := spec.ProjectId + wifConfig *cmv1.WifConfig) error { + poolId := wifConfig.Gcp().WorkloadIdentityPool().PoolId() + project := wifConfig.Gcp().ProjectId() parentResourceForPool := fmt.Sprintf("projects/%s/locations/global", project) - poolResource := fmt.Sprintf("%s/workloadIdentityPools/%s", parentResourceForPool, name) + poolResource := fmt.Sprintf("%s/workloadIdentityPools/%s", parentResourceForPool, poolId) resp, err := client.GetWorkloadIdentityPool(ctx, poolResource) if resp != nil && resp.State == "DELETED" { - log.Printf("Workload identity pool %s was deleted", name) + log.Printf("Workload identity pool %s was deleted", poolId) _, err := client.UndeleteWorkloadIdentityPool(ctx, poolResource, &iamv1.UndeleteWorkloadIdentityPoolRequest{}) if err != nil { - return errors.Wrapf(err, "failed to undelete workload identity pool %s", name) + return errors.Wrapf(err, "failed to undelete workload identity pool %s", poolId) } } else if err != nil { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 && strings.Contains(gerr.Message, "Requested entity was not found") { pool := &iamv1.WorkloadIdentityPool{ - Name: name, - DisplayName: name, + Name: poolId, + DisplayName: poolId, Description: poolDescription, State: "ACTIVE", Disabled: false, } - _, err := client.CreateWorkloadIdentityPool(ctx, parentResourceForPool, name, pool) + _, err := client.CreateWorkloadIdentityPool(ctx, parentResourceForPool, poolId, pool) if err != nil { - return errors.Wrapf(err, "failed to create workload identity pool %s", name) + return errors.Wrapf(err, "failed to create workload identity pool %s", poolId) } - log.Printf("Workload identity pool created with name %s", name) + log.Printf("Workload identity pool created with name %s", poolId) } else { - return errors.Wrapf(err, "failed to check if there is existing workload identity pool %s", name) + return errors.Wrapf(err, "failed to check if there is existing workload identity pool %s", poolId) } } else { - log.Printf("Workload identity pool %s already exists", name) + log.Printf("Workload identity pool %s already exists", poolId) } return nil } func createWorkloadIdentityProvider(ctx context.Context, client gcp.GcpClient, - spec gcp.WorkloadIdentityPoolSpec) error { - //nolint:lll - providerResource := fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s/providers/%s", spec.ProjectId, spec.PoolName, spec.PoolName) + wifConfig *cmv1.WifConfig) error { + projectId := wifConfig.Gcp().ProjectId() + poolId := wifConfig.Gcp().WorkloadIdentityPool().PoolId() + jwks := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().Jwks() + audiences := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().AllowedAudiences() + issuerUrl := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IssuerUrl() + providerId := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IdentityProviderId() + + parent := fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", projectId, poolId) + providerResource := fmt.Sprintf("%s/providers/%s", parent, providerId) + _, err := client.GetWorkloadIdentityProvider(ctx, providerResource) if err != nil { if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 && strings.Contains(gerr.Message, "Requested entity was not found") { provider := &iamv1.WorkloadIdentityPoolProvider{ - Name: spec.PoolName, - DisplayName: spec.PoolName, + Name: providerId, + DisplayName: providerId, Description: poolDescription, State: "ACTIVE", Disabled: false, Oidc: &iamv1.Oidc{ - AllowedAudiences: []string{openShiftAudience}, - IssuerUri: spec.IssuerUrl, - JwksJson: spec.Jwks, + AllowedAudiences: audiences, + IssuerUri: issuerUrl, + JwksJson: jwks, }, AttributeMapping: map[string]string{ "google.subject": "assertion.sub", }, } - parent := fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", - spec.ProjectId, spec.PoolName) - _, err := client.CreateWorkloadIdentityProvider(ctx, parent, spec.PoolName, provider) + _, err := client.CreateWorkloadIdentityProvider(ctx, parent, providerId, provider) if err != nil { - return errors.Wrapf(err, "failed to create workload identity provider %s", spec.PoolName) + return errors.Wrapf(err, "failed to create workload identity provider %s", providerId) } - log.Printf("workload identity provider created with name %s", spec.PoolName) + log.Printf("workload identity provider created with name %s", providerId) } else { return errors.Wrapf(err, "failed to check if there is existing workload identity provider %s in pool %s", - spec.PoolName, spec.PoolName) + providerId, poolId) } } else { - return errors.Errorf("workload identity provider %s already exists in pool %s", spec.PoolName, spec.PoolName) + return errors.Errorf("workload identity provider %s already exists in pool %s", providerId, poolId) } 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 { + if role.Predefined() { + return fmt.Sprintf("roles/%s", role.RoleId()) + } else { + return fmt.Sprintf("projects/%s/roles/%s", projectId, 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 { @@ -265,46 +280,57 @@ 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 - existingRole, err := GetRole(gcpClient, roleID, projectId) + roleID := role.RoleId() + roleTitle := role.RoleId() + permissions := role.Permissions() + existingRole, err := GetRole(gcpClient, fmtRoleResourceId(role)) if err != nil { - if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 && - strings.Contains(gerr.Message, "Requested entity was not found") { - existingRole, err = CreateRole(gcpClient, permissions, roleName, + if gerr, ok := err.(*apierror.APIError); ok && gerr.GRPCStatus().Code() == codes.NotFound { + _, err = CreateRole(gcpClient, permissions, roleTitle, roleID, roleDescription, projectId) if err != nil { - return errors.Wrap(err, fmt.Sprintf("Failed to create %s", roleName)) + return errors.Wrap(err, fmt.Sprintf("Failed to create %s", roleID)) } - log.Printf("Role %s created", roleID) + log.Printf("Role %q created", roleID) + continue } else { return errors.Wrap(err, "Failed to check if role exists") } } + + // Undelete role if it was deleted + if existingRole.Deleted { + _, err = UndeleteRole(gcpClient, fmtRoleResourceId(role)) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("Failed to undelete custom role %q", roleID)) + } + existingRole.Deleted = false + log.Printf("Role %q undeleted", roleID) + } + // Update role if permissions have changed if !reflect.DeepEqual(existingRole.IncludedPermissions, permissions) { existingRole.IncludedPermissions = permissions - _, err := UpdateRole(gcpClient, existingRole, roleName) + _, err := UpdateRole(gcpClient, existingRole, fmtRoleResourceId(role)) if err != nil { - return errors.Wrap(err, fmt.Sprintf("Failed to update %s", roleName)) + return errors.Wrap(err, fmt.Sprintf("Failed to update %s", roleID)) } - log.Printf("Role %s updated", roleID) + log.Printf("Role %q updated", roleID) } } } // 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) @@ -313,19 +339,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()) } } diff --git a/cmd/ocm/gcp/delete-wif-config.go b/cmd/ocm/gcp/delete-wif-config.go index 86cae760..6dd6b020 100644 --- a/cmd/ocm/gcp/delete-wif-config.go +++ b/cmd/ocm/gcp/delete-wif-config.go @@ -3,16 +3,15 @@ package gcp import ( "context" "fmt" + "strings" "log" - "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" + "google.golang.org/api/googleapi" "github.com/spf13/cobra" ) @@ -28,10 +27,10 @@ var ( // NewDeleteWorkloadIdentityConfiguration provides the "gcp delete wif-config" subcommand func NewDeleteWorkloadIdentityConfiguration() *cobra.Command { deleteWifConfigCmd := &cobra.Command{ - Use: "wif-config [ID]", - Short: "Delete workload identity configuration", - Run: deleteWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForDeleteWorkloadIdentityConfigurationCmd, + Use: "wif-config [ID]", + Short: "Delete workload identity configuration", + RunE: deleteWorkloadIdentityConfigurationCmd, + PreRunE: validationForDeleteWorkloadIdentityConfigurationCmd, } deleteWifConfigCmd.PersistentFlags().BoolVar(&DeleteWifConfigOpts.DryRun, "dry-run", false, @@ -42,74 +41,81 @@ func NewDeleteWorkloadIdentityConfiguration() *cobra.Command { return deleteWifConfigCmd } -func validationForDeleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForDeleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { if len(argv) != 1 { - log.Fatal( - "Expected exactly one command line parameters containing the id " + - "of the WIF config.", + return fmt.Errorf( + "expected exactly one command line parameters containing the id " + + "of the WIF config", ) } + return nil } -func deleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func deleteWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { ctx := context.Background() wifConfigId := argv[0] if wifConfigId == "" { - log.Fatal("WIF config ID is required") + return fmt.Errorf("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) + return errors.Wrapf(err, "Failed to create OCM connection") } + defer connection.Close() - wifConfig, err := ocmClient.GetWifConfig(wifConfigId) + response, err := connection.ClustersMgmt().V1().GCP().WifConfigs().WifConfig(wifConfigId).Get().Send() if err != nil { - log.Fatal(err) + return errors.Wrapf(err, "failed to get wif-config") } + 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) + return errors.Wrapf(err, "failed to create script files") } - return + return nil } gcpClient, err := gcp.NewGcpClient(context.Background()) if err != nil { - log.Fatal(err) + return err } - if err := deleteServiceAccounts(ctx, gcpClient, &wifConfig, true); err != nil { - log.Fatal(err) + if err := deleteServiceAccounts(ctx, gcpClient, wifConfig, true); err != nil { + return err } - if err := deleteWorkloadIdentityPool(ctx, gcpClient, &wifConfig, true); err != nil { - log.Fatal(err) + if err := deleteWorkloadIdentityPool(ctx, gcpClient, wifConfig, true); err != nil { + return err } - err = ocmClient.DeleteWifConfig(wifConfigId) + _, err = connection.ClustersMgmt().V1().GCP().WifConfigs(). + WifConfig(wifConfigId). + Delete(). + Send() if err != nil { - log.Fatal(err) + return errors.Wrapf(err, "failed to delete wif config %q", wifConfigId) } + return nil } 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 { - return errors.Wrapf(err, "Failed to delete service account %s", serviceAccountID) + return errors.Wrapf(err, "Failed to delete service account %q", serviceAccountID) } } @@ -117,24 +123,22 @@ 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) if err != nil { - pApiError, ok := err.(*apierror.APIError) - if ok { - if pApiError.GRPCStatus().Code() == codes.NotFound && allowMissing { - log.Printf("Workload identity pool %s not found", poolName) - return nil - } + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 && + strings.Contains(gerr.Message, "Requested entity was not found") && allowMissing { + log.Printf("Workload identity pool %q not found", poolName) + return nil } - return errors.Wrapf(err, "Failed to delete workload identity pool %s", poolName) + return errors.Wrapf(err, "Failed to delete workload identity pool %q", poolName) } - log.Printf("Workload identity pool %s deleted", poolName) + log.Printf("Workload identity pool %q deleted", poolName) return nil } diff --git a/cmd/ocm/gcp/describe-wif-config.go b/cmd/ocm/gcp/describe-wif-config.go index 687b1720..bb5cd326 100644 --- a/cmd/ocm/gcp/describe-wif-config.go +++ b/cmd/ocm/gcp/describe-wif-config.go @@ -2,59 +2,60 @@ package gcp import ( "fmt" - "log" "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/pkg/errors" "github.com/spf13/cobra" ) // NewDescribeWorkloadIdentityConfiguration provides the "gcp describe wif-config" subcommand func NewDescribeWorkloadIdentityConfiguration() *cobra.Command { describeWorkloadIdentityPoolCmd := &cobra.Command{ - Use: "wif-config [ID]", - Short: "Show details of a wif-config.", - Run: describeWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForDescribeWorkloadIdentityConfigurationCmd, + Use: "wif-config [ID]", + Short: "Show details of a wif-config.", + RunE: describeWorkloadIdentityConfigurationCmd, + PreRunE: validationForDescribeWorkloadIdentityConfigurationCmd, } return describeWorkloadIdentityPoolCmd } -func describeWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func describeWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { id, err := urls.Expand(argv) if err != nil { - log.Fatalf("could not create URI: %v", err) + return errors.Wrapf(err, "could not create URI") } // 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) + return errors.Wrapf(err, "Failed to create OCM connection") } + defer connection.Close() - wifconfig, err := ocmClient.GetWifConfig(id) + response, err := connection.ClustersMgmt().V1().GCP().WifConfigs().WifConfig(id).Get().Send() if err != nil { - log.Fatalf("failed to get wif-config: %v", err) + return errors.Wrapf(err, "failed to get wif-config") } + 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() + return w.Flush() } -func validationForDescribeWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForDescribeWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { if len(argv) != 1 { - log.Fatalf("Expected exactly one command line parameters containing the id of the WIF config.") + return fmt.Errorf("Expected exactly one command line parameters containing the id of the WIF config") } + return nil } diff --git a/cmd/ocm/gcp/generate-wif-script.go b/cmd/ocm/gcp/generate-wif-script.go index 13e1b981..1b4bf166 100644 --- a/cmd/ocm/gcp/generate-wif-script.go +++ b/cmd/ocm/gcp/generate-wif-script.go @@ -1,9 +1,13 @@ package gcp import ( + "context" + "fmt" "log" - 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/ocm" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -16,11 +20,11 @@ var ( func NewGenerateCommand() *cobra.Command { generateScriptCmd := &cobra.Command{ - Use: "generate [wif-config ID]", - Short: "Generate script based on a wif-config", - Args: cobra.ExactArgs(1), - Run: generateCreateScriptCmd, - PersistentPreRun: validationForGenerateCreateScriptCmd, + Use: "generate [wif-config ID]", + Short: "Generate script based on a wif-config", + Args: cobra.ExactArgs(1), + RunE: generateCreateScriptCmd, + PreRunE: validationForGenerateCreateScriptCmd, } generateScriptCmd.PersistentFlags().StringVar(&GenerateScriptOpts.TargetDir, "output-dir", "", @@ -29,37 +33,52 @@ func NewGenerateCommand() *cobra.Command { return generateScriptCmd } -func validationForGenerateCreateScriptCmd(cmd *cobra.Command, argv []string) { +func validationForGenerateCreateScriptCmd(cmd *cobra.Command, argv []string) error { if len(argv) != 1 { - log.Fatal( + return fmt.Errorf( "Expected exactly one command line parameters containing the id " + "of the WIF config.", ) } + return nil } -func generateCreateScriptCmd(cmd *cobra.Command, argv []string) { - // Create the client for the OCM API: - ocmClient, err := alphaocm.NewOcmClient() +func generateCreateScriptCmd(cmd *cobra.Command, argv []string) error { + ctx := context.Background() + + gcpClient, err := gcp.NewGcpClient(ctx) + if err != nil { + errors.Wrapf(err, "failed to initiate GCP client") + } + + connection, err := ocm.NewConnection().Build() if err != nil { - log.Fatalf("failed to create backend client: %v", err) + return errors.Wrapf(err, "Failed to create OCM connection") } + defer connection.Close() wifConfigId := argv[0] if wifConfigId == "" { - log.Fatal("WIF config ID is required") + return fmt.Errorf("WIF config ID is required") + } + + response, err := connection.ClustersMgmt().V1().GCP().WifConfigs().WifConfig(wifConfigId).Get().Send() + if err != nil { + return errors.Wrapf(err, "failed to get wif-config") } + wifConfig := response.Body() - wifConfig, err := ocmClient.GetWifConfig(wifConfigId) + projectNum, err := gcpClient.ProjectNumberFromId(wifConfig.Gcp().ProjectId()) if err != nil { - log.Fatalf("failed to get wif-config: %v", err) + return errors.Wrapf(err, "failed to get project number from id") } log.Printf("Writing script files to %s", GenerateScriptOpts.TargetDir) - if err := createScript(GenerateScriptOpts.TargetDir, &wifConfig); err != nil { - log.Fatalf("failed to generate create script: %v", err) + if err := createScript(GenerateScriptOpts.TargetDir, wifConfig, projectNum); err != nil { + return errors.Wrapf(err, "failed to generate create script") } - if err := createDeleteScript(GenerateScriptOpts.TargetDir, &wifConfig); err != nil { - log.Fatalf("failed to generate delete script: %v", err) + if err := createDeleteScript(GenerateScriptOpts.TargetDir, wifConfig); err != nil { + return errors.Wrapf(err, "failed to generate delete script") } + return nil } diff --git a/cmd/ocm/gcp/get-wif-config.go b/cmd/ocm/gcp/get-wif-config.go index c56cc387..67cbae29 100644 --- a/cmd/ocm/gcp/get-wif-config.go +++ b/cmd/ocm/gcp/get-wif-config.go @@ -2,12 +2,12 @@ package gcp import ( "fmt" - "log" "os" - "github.com/openshift-online/ocm-cli/pkg/config" "github.com/openshift-online/ocm-cli/pkg/dump" + "github.com/openshift-online/ocm-cli/pkg/ocm" "github.com/openshift-online/ocm-cli/pkg/urls" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -18,10 +18,10 @@ var GetWorkloadIdentityConfigurationOpts struct { // NewCreateWorkloadIdentityConfiguration provides the "create-wif-config" subcommand func NewGetWorkloadIdentityConfiguration() *cobra.Command { getWorkloadIdentityPoolCmd := &cobra.Command{ - Use: "wif-config [ID]", - Short: "Send a GET request for wif-config.", - Run: getWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForGetWorkloadIdentityConfigurationCmd, + Use: "wif-config [ID]", + Short: "Send a GET request for wif-config.", + RunE: getWorkloadIdentityConfigurationCmd, + PreRunE: validationForGetWorkloadIdentityConfigurationCmd, } fs := getWorkloadIdentityPoolCmd.Flags() @@ -35,40 +35,21 @@ func NewGetWorkloadIdentityConfiguration() *cobra.Command { return getWorkloadIdentityPoolCmd } -func getWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func getWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { id, err := urls.Expand(argv) if err != nil { - log.Fatalf("could not create URI: %v", err) + return errors.Wrapf(err, "could not create URI") } - // Load the configuration file: - cfg, err := config.Load() + connection, err := ocm.NewConnection().Build() if err != nil { - log.Fatalf("Can't load config file: %v", err) - } - if cfg == nil { - log.Fatalf("Not logged in, run the 'login' command") - } - - // Check that the configuration has credentials or tokens that don't have expired: - armed, reason, err := cfg.Armed() - if err != nil { - log.Fatalf(err.Error()) - } - if !armed { - log.Fatalf("Not logged in, %s, run the 'login' command", reason) - } - - // Create the connection: - connection, err := cfg.Connection() - if err != nil { - log.Fatalf("Can't create connection: %v", err) + return errors.Wrapf(err, "Failed to create OCM connection") } defer connection.Close() resp, err := connection.Get().Path(fmt.Sprintf("/api/clusters_mgmt/v1/gcp/wif_configs/%s", id)).Send() if err != nil { - log.Fatalf("can't send request: %v", err) + return errors.Wrapf(err, "can't send request") } status := resp.Status() body := resp.Bytes() @@ -86,12 +67,14 @@ func getWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { } } if err != nil { - log.Fatalf("Can't print body: %v", err) + return errors.Wrapf(err, "can't print body") } + return nil } -func validationForGetWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForGetWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { if len(argv) != 1 { - log.Fatalf("Expected exactly one command line parameter containing the id of the WIF config.") + return fmt.Errorf("Expected exactly one command line parameter containing the id of the WIF config.") } + return nil } diff --git a/cmd/ocm/gcp/iam.go b/cmd/ocm/gcp/iam.go index 53c4b7fa..d308a71b 100644 --- a/cmd/ocm/gcp/iam.go +++ b/cmd/ocm/gcp/iam.go @@ -3,7 +3,6 @@ package gcp import ( "context" "fmt" - "log" "cloud.google.com/go/iam/admin/apiv1/adminpb" "github.com/openshift-online/ocm-cli/pkg/gcp" @@ -11,7 +10,9 @@ import ( cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1" ) -// EnsurePolicyBindingsForProject ensures that given roles and member, appropriate binding is added to project +// EnsurePolicyBindingsForProject ensures that given roles and member, appropriate binding is added to project. +// Roles should be in the format projects/{project}/roles/{role_id} for custom roles and roles/{role_id} +// for predefined roles. func EnsurePolicyBindingsForProject(gcpClient gcp.GcpClient, roles []string, member string, projectName string) error { needPolicyUpdate := false @@ -88,27 +89,27 @@ func setProjectIamPolicy(gcpClient gcp.GcpClient, policy *cloudresourcemanager.P /* Custom Role Creation */ -// GetRole fetches the role created to satisfy a credentials request -func GetRole(gcpClient gcp.GcpClient, roleID, projectName string) (*adminpb.Role, error) { - log.Printf("role id %v", roleID) +// GetRole fetches the role created to satisfy a credentials request. +// Custom roles should follow the format projects/{project}/roles/{role_id}. +func GetRole(gcpClient gcp.GcpClient, roleName string) (*adminpb.Role, error) { role, err := gcpClient.GetRole(context.TODO(), &adminpb.GetRoleRequest{ - Name: fmt.Sprintf("projects/%s/roles/%s", projectName, roleID), + Name: roleName, }) return role, err } // CreateRole creates a new role given permissions -func CreateRole(gcpClient gcp.GcpClient, permissions []string, roleName, roleID, roleDescription, +func CreateRole(gcpClient gcp.GcpClient, permissions []string, roleTitle, roleId, roleDescription, projectName string) (*adminpb.Role, error) { role, err := gcpClient.CreateRole(context.TODO(), &adminpb.CreateRoleRequest{ Role: &adminpb.Role{ - Title: roleName, + Title: roleTitle, Description: roleDescription, IncludedPermissions: permissions, Stage: adminpb.Role_GA, }, Parent: fmt.Sprintf("projects/%s", projectName), - RoleId: roleID, + RoleId: roleId, }) if err != nil { return nil, err @@ -116,16 +117,17 @@ func CreateRole(gcpClient gcp.GcpClient, permissions []string, roleName, roleID, return role, nil } -// UpdateRole updates an existing role given permissions +// UpdateRole updates an existing role given permissions. +// Custom roles should follow the format projects/{project}/roles/{role_id}. func UpdateRole(gcpClient gcp.GcpClient, role *adminpb.Role, roleName string) (*adminpb.Role, error) { - role, err := gcpClient.UpdateRole(context.TODO(), &adminpb.UpdateRoleRequest{ + updated, err := gcpClient.UpdateRole(context.TODO(), &adminpb.UpdateRoleRequest{ Name: roleName, Role: role, }) if err != nil { return nil, err } - return role, nil + return updated, nil } // DeleteRole deletes the role created to satisfy a credentials request diff --git a/cmd/ocm/gcp/list-wif-config.go b/cmd/ocm/gcp/list-wif-config.go index 7e1f8211..98f88363 100644 --- a/cmd/ocm/gcp/list-wif-config.go +++ b/cmd/ocm/gcp/list-wif-config.go @@ -2,12 +2,13 @@ package gcp import ( "context" - "log" "os" - alphaocm "github.com/openshift-online/ocm-cli/pkg/alpha_ocm" "github.com/openshift-online/ocm-cli/pkg/config" + "github.com/openshift-online/ocm-cli/pkg/ocm" "github.com/openshift-online/ocm-cli/pkg/output" + cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" + "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -19,18 +20,18 @@ var ListWorkloadIdentityConfigurationOpts struct { // NewListWorkloadIdentityConfiguration provides the "gcp list wif-config" subcommand func NewListWorkloadIdentityConfiguration() *cobra.Command { listWorkloadIdentityPoolCmd := &cobra.Command{ - Use: "wif-config", - Aliases: []string{"wif-configs"}, - Short: "List wif-configs.", - Run: listWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForListWorkloadIdentityConfigurationCmd, + Use: "wif-config", + Aliases: []string{"wif-configs"}, + Short: "List wif-configs.", + RunE: listWorkloadIdentityConfigurationCmd, + PreRunE: validationForListWorkloadIdentityConfigurationCmd, } fs := listWorkloadIdentityPoolCmd.Flags() fs.StringVar( &ListWorkloadIdentityConfigurationOpts.columns, "columns", - "metadata.id, metadata.displayName, status.state", + "id, display_name", "Specify which columns to display separated by commas, path is based on wif-config struct", ) fs.BoolVar( @@ -43,25 +44,27 @@ func NewListWorkloadIdentityConfiguration() *cobra.Command { return listWorkloadIdentityPoolCmd } -func validationForListWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForListWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { // No validation needed + return nil } -func listWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func listWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { // Create a context: ctx := context.Background() // Load the configuration: cfg, err := config.Load() if err != nil { - log.Fatal(err) + return err } // 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) + return errors.Wrapf(err, "Failed to create OCM connection") } + defer connection.Close() // Create the output printer: printer, err := output.NewPrinter(). @@ -69,23 +72,17 @@ func listWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { Pager(cfg.Pager). Build(ctx) if err != nil { - log.Fatal(err) + return err } defer printer.Close() - // Get the wif-configs: - wifconfigs, err := ocmClient.ListWifConfigs() - if err != nil { - log.Fatalf("failed to get wif-configs: %v", err) - } - // Create the output table: table, err := printer.NewTable(). Name("wifconfigs"). Columns(ListWorkloadIdentityConfigurationOpts.columns). Build(ctx) if err != nil { - log.Fatal(err) + return err } defer table.Close() @@ -94,14 +91,35 @@ func listWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { table.WriteHeaders() } - // Write the rows: - for _, wc := range wifconfigs { - err = table.WriteObject(wc) + // Create the request + request := connection.ClustersMgmt().V1().GCP().WifConfigs().List() + + size := 100 + index := 1 + for { + // Fetch the next page: + request.Size(size) + request.Page(index) + response, err := request.Send() if err != nil { + return errors.Wrapf(err, "can't retrieve wif configs") + } + + // Display the items of the fetched page: + response.Items().Each(func(wc *cmv1.WifConfig) bool { + err = table.WriteObject(wc) + return err == nil + }) + if err != nil { + return err + } + + // If the number of fetched items is less than requested, then this was the last + // page, otherwise process the next one: + if response.Size() < size { break } + index++ } - if err != nil { - log.Fatal(err) - } + return nil } diff --git a/cmd/ocm/gcp/scripting.go b/cmd/ocm/gcp/scripting.go index 893004a0..cf0f0ab4 100644 --- a/cmd/ocm/gcp/scripting.go +++ b/cmd/ocm/gcp/scripting.go @@ -6,27 +6,26 @@ import ( "path/filepath" "strings" - "github.com/openshift-online/ocm-cli/pkg/gcp" - "github.com/openshift-online/ocm-cli/pkg/models" + cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" ) -func createScript(targetDir string, wifConfig *models.WifConfigOutput) error { +func createScript(targetDir string, wifConfig *cmv1.WifConfig, projectNum int64) error { // Write the script content to the path - scriptContent := generateScriptContent(wifConfig) + scriptContent := generateScriptContent(wifConfig, projectNum) err := os.WriteFile(filepath.Join(targetDir, "script.sh"), []byte(scriptContent), 0600) if err != nil { return err } // Write jwk json file to the path jwkPath := filepath.Join(targetDir, "jwk.json") - err = os.WriteFile(jwkPath, []byte(wifConfig.Status.WorkloadIdentityPoolData.Jwks), 0600) + err = os.WriteFile(jwkPath, []byte(wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().Jwks()), 0600) if err != nil { return err } return nil } -func createDeleteScript(targetDir string, wifConfig *models.WifConfigOutput) error { +func createDeleteScript(targetDir string, wifConfig *cmv1.WifConfig) error { // Write the script content to the path scriptContent := generateDeleteScriptContent(wifConfig) err := os.WriteFile(filepath.Join(targetDir, "delete.sh"), []byte(scriptContent), 0600) @@ -36,7 +35,7 @@ func createDeleteScript(targetDir string, wifConfig *models.WifConfigOutput) err return nil } -func generateDeleteScriptContent(wifConfig *models.WifConfigOutput) string { +func generateDeleteScriptContent(wifConfig *cmv1.WifConfig) string { scriptContent := "#!/bin/bash\n" // Append the script to delete the service accounts @@ -47,53 +46,45 @@ func generateDeleteScriptContent(wifConfig *models.WifConfigOutput) string { return scriptContent } -func deleteServiceAccountScriptContent(wifConfig *models.WifConfigOutput) string { +func deleteServiceAccountScriptContent(wifConfig *cmv1.WifConfig) string { var sb strings.Builder sb.WriteString("\n# Delete service accounts:\n") - for _, sa := range wifConfig.Status.ServiceAccounts { - project := wifConfig.Spec.ProjectId - serviceAccountID := sa.Id + for _, sa := range wifConfig.Gcp().ServiceAccounts() { + project := wifConfig.Gcp().ProjectId() + serviceAccountEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", sa.ServiceAccountId(), project) sb.WriteString(fmt.Sprintf("gcloud iam service-accounts delete %s --project=%s\n", - serviceAccountID, project)) + serviceAccountEmail, project)) } return sb.String() } -func deleteIdentityPoolScriptContent(wifConfig *models.WifConfigOutput) string { - pool := wifConfig.Status.WorkloadIdentityPoolData +func deleteIdentityPoolScriptContent(wifConfig *cmv1.WifConfig) string { + pool := wifConfig.Gcp().WorkloadIdentityPool() // Delete the workload identity pool return fmt.Sprintf(` # Delete the workload identity pool gcloud iam workload-identity-pools delete %s --project=%s --location=global -`, pool.PoolId, pool.ProjectId) +`, pool.PoolId(), wifConfig.Gcp().ProjectId()) } -func generateScriptContent(wifConfig *models.WifConfigOutput) string { - 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, - } - +func generateScriptContent(wifConfig *cmv1.WifConfig, projectNum int64) string { scriptContent := "#!/bin/bash\n" // Create a script to create the workload identity pool - scriptContent += createIdentityPoolScriptContent(poolSpec) + scriptContent += createIdentityPoolScriptContent(wifConfig) // Append the script to create the identity provider - scriptContent += createIdentityProviderScriptContent(poolSpec) + scriptContent += createIdentityProviderScriptContent(wifConfig) // Append the script to create the service accounts - scriptContent += createServiceAccountScriptContent(wifConfig) + scriptContent += createServiceAccountScriptContent(wifConfig, projectNum) return scriptContent } -func createIdentityPoolScriptContent(spec gcp.WorkloadIdentityPoolSpec) string { - name := spec.PoolName - project := spec.ProjectId +func createIdentityPoolScriptContent(wifConfig *cmv1.WifConfig) string { + name := wifConfig.Gcp().WorkloadIdentityPool().PoolId() + project := wifConfig.Gcp().ProjectId() return fmt.Sprintf(` # Create a workload identity pool @@ -105,7 +96,12 @@ gcloud iam workload-identity-pools create %s \ `, name, project, poolDescription, name) } -func createIdentityProviderScriptContent(spec gcp.WorkloadIdentityPoolSpec) string { +func createIdentityProviderScriptContent(wifConfig *cmv1.WifConfig) string { + poolId := wifConfig.Gcp().WorkloadIdentityPool().PoolId() + audiences := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().AllowedAudiences() + issuerUrl := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IssuerUrl() + providerId := wifConfig.Gcp().WorkloadIdentityPool().IdentityProvider().IdentityProviderId() + return fmt.Sprintf(` # Create a workload identity provider gcloud iam workload-identity-pools providers create-oidc %s \ @@ -117,34 +113,34 @@ gcloud iam workload-identity-pools providers create-oidc %s \ --allowed-audiences="%s" \ --attribute-mapping="google.subject=assertion.sub" \ --workload-identity-pool=%s -`, spec.PoolName, spec.PoolName, poolDescription, spec.IssuerUrl, openShiftAudience, spec.PoolName) +`, providerId, providerId, poolDescription, issuerUrl, strings.Join(audiences, ","), poolId) } // This returns the gcloud commands to create a service account, bind roles, and grant access // to the workload identity pool -func createServiceAccountScriptContent(wifConfig *models.WifConfigOutput) string { +func createServiceAccountScriptContent(wifConfig *cmv1.WifConfig, projectNum int64) string { // For each service account, create a service account and bind it to the workload identity pool var sb strings.Builder sb.WriteString("\n# Create service accounts:\n") - for _, sa := range wifConfig.Status.ServiceAccounts { - project := wifConfig.Spec.ProjectId - serviceAccountID := sa.Id - serviceAccountName := wifConfig.Spec.DisplayName + "-" + serviceAccountID - serviceAccountDesc := poolDescription + " for WIF config " + wifConfig.Spec.DisplayName + for _, sa := range wifConfig.Gcp().ServiceAccounts() { + project := wifConfig.Gcp().ProjectId() + serviceAccountID := sa.ServiceAccountId() + serviceAccountName := wifConfig.DisplayName() + "-" + serviceAccountID + serviceAccountDesc := poolDescription + " for WIF config " + wifConfig.DisplayName() //nolint:lll sb.WriteString(fmt.Sprintf("gcloud iam service-accounts create %s --display-name=%s --description=\"%s\" --project=%s\n", serviceAccountID, serviceAccountName, serviceAccountDesc, project)) } sb.WriteString("\n# Create roles:\n") - for _, sa := range wifConfig.Status.ServiceAccounts { - for _, role := range sa.Roles { - if !role.Predefined { - roleId := strings.ReplaceAll(role.Id, "-", "_") - project := wifConfig.Spec.ProjectId - permissions := strings.Join(role.Permissions, ",") + for _, sa := range wifConfig.Gcp().ServiceAccounts() { + for _, role := range sa.Roles() { + if !role.Predefined() { + roleId := strings.ReplaceAll(role.RoleId(), "-", "_") + project := wifConfig.Gcp().ProjectId() + permissions := strings.Join(role.Permissions(), ",") roleName := roleId - serviceAccountDesc := roleDescription + " for WIF config " + wifConfig.Spec.DisplayName + serviceAccountDesc := roleDescription + " for WIF config " + wifConfig.DisplayName() //nolint:lll sb.WriteString(fmt.Sprintf("gcloud iam roles create %s --project=%s --title=%s --description=\"%s\" --stage=GA --permissions=%s\n", roleId, project, roleName, serviceAccountDesc, permissions)) @@ -152,45 +148,51 @@ func createServiceAccountScriptContent(wifConfig *models.WifConfigOutput) string } } sb.WriteString("\n# Bind service account roles:\n") - for _, sa := range wifConfig.Status.ServiceAccounts { - for _, role := range sa.Roles { - project := wifConfig.Spec.ProjectId - member := fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", sa.Id, project) - sb.WriteString(fmt.Sprintf("gcloud projects add-iam-policy-binding %s --member=%s --role=roles/%s\n", - project, member, role.Id)) + for _, sa := range wifConfig.Gcp().ServiceAccounts() { + for _, role := range sa.Roles() { + project := wifConfig.Gcp().ProjectId() + member := fmt.Sprintf("serviceAccount:%s@%s.iam.gserviceaccount.com", sa.ServiceAccountId(), project) + var roleResource string + if role.Predefined() { + roleResource = fmt.Sprintf("roles/%s", role.RoleId()) + } else { + roleResource = fmt.Sprintf("projects/%s/roles/%s", project, role.RoleId()) + } + sb.WriteString(fmt.Sprintf("gcloud projects add-iam-policy-binding %s --member=%s --role=%s\n", + project, member, roleResource)) } } sb.WriteString("\n# Grant access:\n") - for _, sa := range wifConfig.Status.ServiceAccounts { - if sa.AccessMethod == "wif" { - project := wifConfig.Spec.ProjectId - serviceAccount := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", sa.Id, project) - members := fmtMembers(sa, wifConfig.Status.WorkloadIdentityPoolData.ProjectNumber, - wifConfig.Status.WorkloadIdentityPoolData.PoolId) + for _, sa := range wifConfig.Gcp().ServiceAccounts() { + if sa.AccessMethod() == "wif" { + project := wifConfig.Gcp().ProjectId() + serviceAccount := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", sa.ServiceAccountId(), project) + members := fmtMembers(sa, projectNum, + wifConfig.Gcp().WorkloadIdentityPool().PoolId()) for _, member := range members { //nolint:lll sb.WriteString(fmt.Sprintf("gcloud iam service-accounts add-iam-policy-binding %s --member=%s --role=roles/iam.workloadIdentityUser --project=%s\n", serviceAccount, member, project)) } - } else if sa.AccessMethod == "impersonate" { - project := wifConfig.Spec.ProjectId - serviceAccount := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", sa.Id, project) - impersonator := fmt.Sprintf("serviceAccount:%s", impersonatorEmail) + } else if sa.AccessMethod() == "impersonate" { + project := wifConfig.Gcp().ProjectId() + serviceAccount := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", sa.ServiceAccountId(), project) + impersonator := fmt.Sprintf("serviceAccount:%s", wifConfig.Gcp().ImpersonatorEmail()) //nolint:lll sb.WriteString(fmt.Sprintf("gcloud iam service-accounts add-iam-policy-binding %s --member=%s --role=roles/iam.serviceAccountTokenCreator --project=%s\n", - serviceAccount, impersonator, wifConfig.Spec.ProjectId)) + serviceAccount, impersonator, wifConfig.Gcp().ProjectId())) } } return sb.String() } -func fmtMembers(sa models.ServiceAccount, projectNum int64, poolId string) []string { +func fmtMembers(sa *cmv1.WifServiceAccount, projectNum int64, poolId string) []string { members := []string{} - for _, saName := range sa.GetServiceAccountNames() { + for _, saName := range sa.CredentialRequest().ServiceAccountNames() { //nolint:lll members = append(members, fmt.Sprintf( "principal://iam.googleapis.com/projects/%d/locations/global/workloadIdentityPools/%s/subject/system:serviceaccount:%s:%s", - projectNum, poolId, sa.GetSecretNamespace(), saName)) + projectNum, poolId, sa.CredentialRequest().SecretRef().Namespace(), saName)) } return members } diff --git a/cmd/ocm/gcp/update-wif-config.go b/cmd/ocm/gcp/update-wif-config.go index 8ee3061e..31273157 100644 --- a/cmd/ocm/gcp/update-wif-config.go +++ b/cmd/ocm/gcp/update-wif-config.go @@ -12,10 +12,10 @@ var UpdateWifConfigOpts struct { // NewUpdateWorkloadIdentityConfiguration provides the "gcp update wif-config" subcommand func NewUpdateWorkloadIdentityConfiguration() *cobra.Command { updateWifConfigCmd := &cobra.Command{ - Use: "wif-config", - Short: "Update wif-config.", - Run: updateWorkloadIdentityConfigurationCmd, - PersistentPreRun: validationForUpdateWorkloadIdentityConfigurationCmd, + Use: "wif-config", + Short: "Update wif-config.", + RunE: updateWorkloadIdentityConfigurationCmd, + PreRunE: validationForUpdateWorkloadIdentityConfigurationCmd, } updateWifConfigCmd.PersistentFlags().StringVar(&UpdateWifConfigOpts.wifId, "wif-id", "", @@ -28,10 +28,12 @@ func NewUpdateWorkloadIdentityConfiguration() *cobra.Command { return updateWifConfigCmd } -func validationForUpdateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func validationForUpdateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { // No validation needed + return nil } -func updateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) { +func updateWorkloadIdentityConfigurationCmd(cmd *cobra.Command, argv []string) error { // No implementation yet + return nil } diff --git a/go.mod b/go.mod index bb6772c8..500bedb7 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/nwidger/jsoncolor v0.3.2 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.8 - github.com/openshift-online/ocm-sdk-go v0.1.422 + github.com/openshift-online/ocm-sdk-go v0.1.433 github.com/openshift/rosa v1.2.24 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index f0ce8af2..4de12fa3 100644 --- a/go.sum +++ b/go.sum @@ -361,8 +361,8 @@ github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= -github.com/openshift-online/ocm-sdk-go v0.1.422 h1:NWXLNTg7sLgUJRM3tyuk/QuVbUCRuMH+aLlbCKNzXWc= -github.com/openshift-online/ocm-sdk-go v0.1.422/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= +github.com/openshift-online/ocm-sdk-go v0.1.433 h1:8i0Si9KrFkMprMBGR1a4ppmgVezMBjjXXkvhv28OVUk= +github.com/openshift-online/ocm-sdk-go v0.1.433/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y= github.com/openshift/rosa v1.2.24 h1:vv0yYnWHx6CCPEAau/0rS54P2ksaf+uWXb1TQPWxiYE= github.com/openshift/rosa v1.2.24/go.mod h1:MVXB27O3PF8WoOic23I03mmq6/9kVxpFx6FKyLMCyrQ= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= diff --git a/pkg/alpha_ocm/client.go b/pkg/alpha_ocm/client.go deleted file mode 100644 index b284c986..00000000 --- a/pkg/alpha_ocm/client.go +++ /dev/null @@ -1,125 +0,0 @@ -package alphaocm - -/* This package will be replaced with calls to the sdk once available */ - -import ( - "encoding/json" - "fmt" - "os" - - sdk "github.com/openshift-online/ocm-sdk-go" - - "github.com/openshift-online/ocm-cli/pkg/config" - "github.com/openshift-online/ocm-cli/pkg/dump" - "github.com/openshift-online/ocm-cli/pkg/models" -) - -type OcmClient interface { - CreateWifConfig(models.WifConfigInput) (models.WifConfigOutput, error) - GetWifConfig(string) (models.WifConfigOutput, error) - ListWifConfigs() ([]models.WifConfigOutput, error) - DeleteWifConfig(string) error -} - -type ocmClient struct { - connection *sdk.Connection -} - -func NewOcmClient() (OcmClient, error) { - // Load the configuration file: - cfg, err := config.Load() - if err != nil { - return nil, fmt.Errorf("can't load config file: %v", err) - } - if cfg == nil { - return nil, fmt.Errorf("not logged in, run the 'login' command") - } - - // Check that the configuration has credentials or tokens that don't have expired: - armed, reason, err := cfg.Armed() - if err != nil { - return nil, fmt.Errorf(err.Error()) - } - if !armed { - return nil, fmt.Errorf("not logged in, %s, run the 'login' command", reason) - } - - // Create the connection: - connection, err := cfg.Connection() - if err != nil { - return nil, fmt.Errorf("can't create connection: %v", err) - } - return &ocmClient{ - connection: connection, - }, nil -} - -func (c *ocmClient) CreateWifConfig(input models.WifConfigInput) (models.WifConfigOutput, error) { - var wifConfigOutput models.WifConfigOutput - - inputJson, err := json.Marshal(input) - if err != nil { - return wifConfigOutput, fmt.Errorf("failed to marshal wif input: %v", err) - } - - resp, err := c.connection.Post().Path("/api/clusters_mgmt/v1/gcp/wif_configs").Bytes(inputJson).Send() - if err != nil { - return wifConfigOutput, fmt.Errorf("can't send request: %v", err) - } - - status := resp.Status() - body := resp.Bytes() - - if status >= 400 { - dump.Pretty(os.Stderr, body) - return wifConfigOutput, fmt.Errorf("failed to create WIF config: %s", string(body)) - } - - wifConfigOutput, err = models.WifConfigOutputFromJson(body) - return wifConfigOutput, err -} - -func (c *ocmClient) GetWifConfig(id string) (models.WifConfigOutput, error) { - var wifConfigOutput models.WifConfigOutput - resp, err := c.connection.Get().Path(fmt.Sprintf("/api/clusters_mgmt/v1/gcp/wif_configs/%s", id)).Send() - if err != nil { - return wifConfigOutput, fmt.Errorf("can't send request: %v", err) - } - if resp.Status() >= 400 { - body := resp.Bytes() - dump.Pretty(os.Stderr, body) - return wifConfigOutput, fmt.Errorf("failed to list WIF configs: %s", string(body)) - } - - wifConfigOutput, err = models.WifConfigOutputFromJson(resp.Bytes()) - return wifConfigOutput, err -} - -func (c *ocmClient) ListWifConfigs() ([]models.WifConfigOutput, error) { - var wifConfigs []models.WifConfigOutput - resp, err := c.connection.Get().Path("/api/clusters_mgmt/v1/gcp/wif_configs").Send() - if err != nil { - return wifConfigs, fmt.Errorf("can't send request: %v", err) - } - if resp.Status() >= 400 { - body := resp.Bytes() - dump.Pretty(os.Stderr, body) - return wifConfigs, fmt.Errorf("failed to list WIF configs: %s", string(body)) - } - - wifConfigsList, err := models.WifConfigOutputListFromJson(resp.Bytes()) - return wifConfigsList.Items, err -} - -func (c *ocmClient) DeleteWifConfig(id string) error { - resp, err := c.connection.Delete().Path(fmt.Sprintf("/api/clusters_mgmt/v1/gcp/wif_configs/%s", id)).Send() - if err != nil { - return fmt.Errorf("can't send request: %v", err) - } - if resp.Status() >= 400 { - body := resp.Bytes() - dump.Pretty(os.Stderr, body) - return fmt.Errorf("failed to delete WIF config: %s", string(body)) - } - return nil -} diff --git a/pkg/gcp/client.go b/pkg/gcp/client.go index 77df428a..10876f8c 100644 --- a/pkg/gcp/client.go +++ b/pkg/gcp/client.go @@ -10,7 +10,9 @@ import ( "cloud.google.com/go/iam/admin/apiv1/adminpb" "cloud.google.com/go/iam/apiv1/iampb" "cloud.google.com/go/storage" + cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" cloudresourcemanager "google.golang.org/api/cloudresourcemanager/v1" + iamv1 "google.golang.org/api/iam/v1" "google.golang.org/api/iterator" secretmanager "google.golang.org/api/secretmanager/v1" @@ -35,7 +37,7 @@ type GcpClient interface { SetProjectIamPolicy(svcAcctResource string, request *cloudresourcemanager.SetIamPolicyRequest) (*cloudresourcemanager.Policy, error) //nolint:lll AttachImpersonator(saId, projectId, impersonatorResourceId string) error - AttachWorkloadIdentityPool(sa ServiceAccount, poolId, projectId string) error + AttachWorkloadIdentityPool(sa *cmv1.WifServiceAccount, poolId, projectId string) error SaveSecret(secretId, projectId string, secretData []byte) error RetreiveSecret(secretId string, projectId string) ([]byte, error) @@ -50,12 +52,6 @@ type GcpClient interface { ListRoles(context.Context, *adminpb.ListRolesRequest) (*adminpb.ListRolesResponse, error) } -type ServiceAccount interface { - GetId() string - GetSecretNamespace() string - GetServiceAccountNames() []string -} - type gcpClient struct { ctx context.Context iamClient *iamadmin.IamClient @@ -139,7 +135,7 @@ func (c *gcpClient) ListServiceAccounts(project string, filter func(string) bool return out, nil } -func (c *gcpClient) AttachImpersonator(saId, projectId string, impersonatorId string) error { +func (c *gcpClient) AttachImpersonator(saId, projectId string, impersonatorEmail string) error { saResourceId := fmt.Sprintf("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com", projectId, saId, projectId) policy, err := c.iamClient.GetIamPolicy(context.Background(), &iampb.GetIamPolicyRequest{ @@ -149,7 +145,7 @@ func (c *gcpClient) AttachImpersonator(saId, projectId string, impersonatorId st return c.handleAttachImpersonatorError(err) } policy.Add( - fmt.Sprintf("serviceAccount:%s", c.extractEmail(impersonatorId)), + fmt.Sprintf("serviceAccount:%s", impersonatorEmail), iam.RoleName("roles/iam.serviceAccountTokenCreator")) _, err = c.iamClient.SetIamPolicy(context.Background(), &iamadmin.SetIamPolicyRequest{ Resource: saResourceId, @@ -161,8 +157,8 @@ func (c *gcpClient) AttachImpersonator(saId, projectId string, impersonatorId st return nil } -func (c *gcpClient) AttachWorkloadIdentityPool(sa ServiceAccount, poolId, projectId string) error { - saResourceId := c.fmtSaResourceId(sa.GetId(), projectId) +func (c *gcpClient) AttachWorkloadIdentityPool(sa *cmv1.WifServiceAccount, poolId, projectId string) error { + saResourceId := c.fmtSaResourceId(sa.ServiceAccountId(), projectId) projectNum, err := c.ProjectNumberFromId(projectId) if err != nil { @@ -175,12 +171,12 @@ func (c *gcpClient) AttachWorkloadIdentityPool(sa ServiceAccount, poolId, projec if err != nil { return c.handleAttachWorkloadIdentityPoolError(err) } - for _, openshiftServiceAccount := range sa.GetServiceAccountNames() { + for _, openshiftServiceAccount := range sa.CredentialRequest().ServiceAccountNames() { policy.Add( //nolint:lll fmt.Sprintf( "principal://iam.googleapis.com/projects/%d/locations/global/workloadIdentityPools/%s/subject/system:serviceaccount:%s:%s", - projectNum, poolId, sa.GetSecretNamespace(), openshiftServiceAccount, + projectNum, poolId, sa.CredentialRequest().SecretRef().Namespace(), openshiftServiceAccount, ), iam.RoleName("roles/iam.workloadIdentityUser")) } diff --git a/pkg/gcp/helpers.go b/pkg/gcp/helpers.go index cfc9f406..d2d3d6b6 100644 --- a/pkg/gcp/helpers.go +++ b/pkg/gcp/helpers.go @@ -2,17 +2,8 @@ package gcp import ( "fmt" - "strings" ) -func (c *gcpClient) extractEmail(saResourceId string) string { - email := strings.SplitAfter(saResourceId, "/serviceAccounts/") - if len(email) != 2 { - return "" - } - return email[1] -} - func (c *gcpClient) fmtSaResourceId(accountId, projectId string) string { return fmt.Sprintf("projects/%s/serviceAccounts/%s@%s.iam.gserviceaccount.com", projectId, accountId, projectId) } diff --git a/pkg/models/role.go b/pkg/models/role.go deleted file mode 100644 index 654967c0..00000000 --- a/pkg/models/role.go +++ /dev/null @@ -1,8 +0,0 @@ -package models - -type Role struct { - Id string `json:"id,omitempty"` - Kind string `json:"kind,omitempty"` - Permissions []string `json:"permissions,omitempty"` - Predefined bool `json:"predefined,omitempty"` -} diff --git a/pkg/models/service_account.go b/pkg/models/service_account.go deleted file mode 100644 index 12d6adaa..00000000 --- a/pkg/models/service_account.go +++ /dev/null @@ -1,36 +0,0 @@ -package models - -type ServiceAccount struct { - AccessMethod string `json:"access_method,omitempty"` - CredentialRequest CredentialRequest `json:"credential_request,omitempty"` - Id string `json:"id,omitempty"` - Kind string `json:"kind,omitempty"` - OsdRole string `json:"osd_role,omitempty"` - Roles []Role `json:"roles,omitempty"` -} - -type CredentialRequest struct { - SecretRef SecretRef - ServiceAccountNames []string -} - -type SecretRef struct { - Name string - Namespace string -} - -func (s ServiceAccount) GetId() string { - return s.Id -} - -func (s ServiceAccount) GetSecretName() string { - return s.CredentialRequest.SecretRef.Name -} - -func (s ServiceAccount) GetSecretNamespace() string { - return s.CredentialRequest.SecretRef.Namespace -} - -func (s ServiceAccount) GetServiceAccountNames() []string { - return s.CredentialRequest.ServiceAccountNames -} diff --git a/pkg/models/wif_config_input.go b/pkg/models/wif_config_input.go deleted file mode 100644 index 00da13d9..00000000 --- a/pkg/models/wif_config_input.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -type WifConfigInput struct { - DisplayName string `json:"display_name"` - ProjectId string `json:"project_id"` -} diff --git a/pkg/models/wif_config_list.go b/pkg/models/wif_config_list.go deleted file mode 100644 index 28b6518d..00000000 --- a/pkg/models/wif_config_list.go +++ /dev/null @@ -1,7 +0,0 @@ -package models - -type WifConfigList struct { - Items []WifConfigOutput `json:"items,omitempty"` - Page int32 `json:"page,omitempty"` - Total int32 `json:"total,omitempty"` -} diff --git a/pkg/models/wif_config_metadata.go b/pkg/models/wif_config_metadata.go deleted file mode 100644 index a9321a3a..00000000 --- a/pkg/models/wif_config_metadata.go +++ /dev/null @@ -1,7 +0,0 @@ -package models - -type WifConfigMetadata struct { - DisplayName string `json:"display_name,omitempty"` - Id string `json:"id,omitempty"` - Organization *WifConfigMetadataOrganization `json:"organization,omitempty"` -} diff --git a/pkg/models/wif_config_metadata_organization.go b/pkg/models/wif_config_metadata_organization.go deleted file mode 100644 index b64deece..00000000 --- a/pkg/models/wif_config_metadata_organization.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -type WifConfigMetadataOrganization struct { - Href string `json:"href,omitempty"` - Kind string `json:"kind,omitempty"` -} diff --git a/pkg/models/wif_config_output.go b/pkg/models/wif_config_output.go deleted file mode 100644 index 820ac233..00000000 --- a/pkg/models/wif_config_output.go +++ /dev/null @@ -1,32 +0,0 @@ -package models - -import ( - "encoding/json" - "fmt" -) - -type WifConfigOutput struct { - Metadata *WifConfigMetadata `json:"metadata,omitempty"` - Spec *WifConfigInput `json:"spec,omitempty"` - Status *WifConfigStatus `json:"status,omitempty"` -} - -type WifConfigOutputList struct { - Items []WifConfigOutput `json:"items"` -} - -func WifConfigOutputFromJson(rawWifConfigOutput []byte) (WifConfigOutput, error) { - var output WifConfigOutput - err := json.Unmarshal(rawWifConfigOutput, &output) - return output, err -} - -func WifConfigOutputListFromJson(data []byte) (*WifConfigOutputList, error) { - var wifConfigListOutput WifConfigOutputList - err := json.Unmarshal(data, &wifConfigListOutput) - if err != nil { - return nil, fmt.Errorf("error unmarshalling data: %v", err) - } - return &wifConfigListOutput, nil - -} diff --git a/pkg/models/wif_config_status.go b/pkg/models/wif_config_status.go deleted file mode 100644 index 0e1c2ace..00000000 --- a/pkg/models/wif_config_status.go +++ /dev/null @@ -1,23 +0,0 @@ -package models - -type WifConfigStatus struct { - ServiceAccounts []ServiceAccount `json:"service_accounts,omitempty"` - State string `json:"state,omitempty"` - Summary string `json:"summary,omitempty"` - TimeData WifTimeData `json:"time_data,omitempty"` - WorkloadIdentityPoolData WifWorkloadIdentityPoolData `json:"workload_identity_pool,omitempty"` -} - -type WifWorkloadIdentityPoolData struct { - IdentityProviderId string `json:"identity_provider_id,omitempty"` - IssuerUrl string `json:"issuer_url,omitempty"` - Jwks string `json:"jwks,omitempty"` - PoolId string `json:"pool_id,omitempty"` - ProjectId string `json:"gcp_project_name,omitempty"` - ProjectNumber int64 `json:"gcp_project_num,omitempty"` -} - -type WifTimeData struct { - LastChecked string `json:"last_checked,omitempty"` - CreatedAt string `json:"created_at,omitempty"` -} diff --git a/pkg/models/wif_template.go b/pkg/models/wif_template.go deleted file mode 100644 index bb22986e..00000000 --- a/pkg/models/wif_template.go +++ /dev/null @@ -1,7 +0,0 @@ -package models - -type WifTemplate struct { - Id string `json:"id,omitempty"` - Kind string `json:"kind,omitempty"` - ServiceAccounts []ServiceAccount `json:"service_accounts,omitempty"` -} diff --git a/pkg/output/tables/wifconfigs.yaml b/pkg/output/tables/wifconfigs.yaml index eb10deff..330a22c1 100644 --- a/pkg/output/tables/wifconfigs.yaml +++ b/pkg/output/tables/wifconfigs.yaml @@ -1,7 +1,5 @@ columns: -- name: metadata.id +- name: id header: ID -- name: metadata.displayName +- name: displayName header: NAME -- name: status.state - header: STATE