...

Source file src/edge-infra.dev/pkg/edge/api/services/organization_service.go

Documentation: edge-infra.dev/pkg/edge/api/services

     1  package services
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/lib/pq"
    13  	"github.com/rs/zerolog/log"
    14  	"k8s.io/utils/ptr"
    15  
    16  	"edge-infra.dev/pkg/edge/api/apierror"
    17  	sqlerr "edge-infra.dev/pkg/edge/api/apierror/sql"
    18  	"edge-infra.dev/pkg/edge/api/bsl/types"
    19  	"edge-infra.dev/pkg/edge/api/graph/mapper"
    20  	"edge-infra.dev/pkg/edge/api/graph/model"
    21  	"edge-infra.dev/pkg/edge/api/middleware"
    22  	sqlquery "edge-infra.dev/pkg/edge/api/sql"
    23  	apiTypes "edge-infra.dev/pkg/edge/api/types"
    24  	"edge-infra.dev/pkg/edge/api/utils"
    25  	bannerv1alpha1 "edge-infra.dev/pkg/edge/apis/banner/v1alpha1"
    26  	"edge-infra.dev/pkg/edge/bsl"
    27  	chariotClientApi "edge-infra.dev/pkg/edge/chariot/client"
    28  	"edge-infra.dev/pkg/edge/constants/api/banner"
    29  	"edge-infra.dev/pkg/edge/controllers/util/edgedb"
    30  	"edge-infra.dev/pkg/sds/clustersecrets/audit"
    31  )
    32  
    33  const (
    34  	BspEnterpriseUnitPath              = "/provisioning/enterprise-units"
    35  	getEnterpriseUnit                  = "/provisioning/enterprise-units/%s"
    36  	updateOrganization                 = "/provisioning/organizations/%s"
    37  	bspOrgPath                         = "/provisioning/organizations"
    38  	bspExternalUserPath                = "/provisioning/users/external"
    39  	bspEnterpriseUnitOrganizationsPath = BspEnterpriseUnitPath + "?typeNamePattern=organization"
    40  	bspDeleteOrgPath                   = "/provisioning/organizations/%s/purge"
    41  	bspSubOrganizationsPath            = "/provisioning/organizations/find-by-parent?parentOrganizationName=%s" + bspPaging
    42  	bspUserAssignedSubOrgsPath         = "/provisioning/users/external/%s/accounts?pageNumber=%d&pageSize=%d"
    43  	bspPaging                          = "&pageNumber=%d&pageSize=%d"
    44  	bspEnterpriseUnitGrantBasePath     = "/provisioning/enterprise-unit-grants/unit-grants/%s/%s"
    45  	bspGetAllAssignedOrgURL            = "/provisioning/enterprise-unit-grants/unit-grants?username=%s"
    46  	bspGetOrgUsersListPath             = "/provisioning/enterprise-unit-grants/unit-grants?enterpriseUnitId=%s&pageNumber=%d&pageSize=%d"
    47  	bspUserDetailsPath                 = "/provisioning/users/user-details"
    48  	pageSize                           = 200
    49  	commerceOrg                        = "commerce"
    50  	ProvisionedStatus                  = "PROVISIONED"
    51  	ProvisioningStatusMessage          = "Edge Provisioning"
    52  )
    53  
    54  //go:generate mockgen -destination=../mocks/mock_organization_service.go -package=mocks edge-infra.dev/pkg/edge/api/services BannerService
    55  type BannerService interface {
    56  	GetBannerTenantInfo(ctx context.Context, orgName string) (*model.Tenant, error)
    57  	GetBanners(ctx context.Context) ([]*model.Banner, error)
    58  	GetBannerCRByID(ctx context.Context, id string) (*bannerv1alpha1.Banner, error)
    59  	GetBanner(ctx context.Context, bannerEdgeID string) (*model.Banner, error)
    60  	CheckBannerInBSL(ctx context.Context, bannerModel *model.Banner) (*model.Banner, error)
    61  	CreateEUBanner(ctx context.Context, name string, description *string) (*model.Banner, error)
    62  	CreateOrganizationBanner(ctx context.Context, name string, description *string) (*model.Banner, error)
    63  	UndoCreateBanner(ctx context.Context, name, id, uuid, bannerObject string, isOrgBanner *bool, bucketPath string) error
    64  	DeleteEUBanner(ctx context.Context, name, id string) (bool, error)
    65  	DeleteOrgBanner(ctx context.Context, id string) (bool, error)
    66  	AssignUserToEUBanners(ctx context.Context, username string, banners []string) error
    67  	AssignUserToOrgBanners(ctx context.Context, username string, banners []*model.Banner) error
    68  	GetUsersForEuBanner(ctx context.Context, organizationID string) ([]*model.User, error)
    69  	GetBSLOrganization(ctx context.Context, organization string) (*bsl.BSLOrganization, error)
    70  	GetUserAssignedBanners(ctx context.Context, username string) ([]*model.BannerInfo, error)
    71  	CreateBannerCr(ctx context.Context, uuid, projectID, name, enterpriseUnitID string, enablements []string) (string, error)
    72  	DeleteBannerSQLEntry(ctx context.Context, bannerUUID string) error
    73  	CreateBannerSQLEntry(ctx context.Context, projectID, bannerName, bannerType, enterpriseUnitID, bannerUUID, description string) error
    74  	GetBannerProjectID(ctx context.Context, bannerEdgeID string) (string, error)
    75  	GetBannerTypeFromID(ctx context.Context, id string) (banner.Type, error)
    76  	GetBannerTypeFromUUID(ctx context.Context, uuid string) (banner.Type, error)
    77  	GetBannerByEdgeID(ctx context.Context, bannerUUID string) (*model.Banner, error)
    78  	GetBannerByBSLID(ctx context.Context, bannerBSLID string) (*model.Banner, error)
    79  	GetEdgeBannerInfo(ctx context.Context, banners []*model.Banner) []*model.Banner
    80  	GetClusterInfraInfo(ctx context.Context, bannerEdgeID string) (*model.Cluster, error)
    81  	GetBannerByNameAndTenant(ctx context.Context, name, orgName string) (*model.Banner, error)
    82  	DeleteClusterSQLEntry(ctx context.Context, clusterEdgeID string) error
    83  	GetBannerInfraInfo(ctx context.Context) (*model.Cluster, error)
    84  	GetBannerInfraBucketPath(ctx context.Context) (string, error)
    85  	UpdateBannerSQL(ctx context.Context, update *model.Banner) error
    86  	UpdateEUBanner(ctx context.Context, update *model.Banner) error
    87  	UpdateOrgBanner(ctx context.Context, update *model.Banner) error
    88  	GetBSLEU(ctx context.Context, eu string) (*types.EnterpriseUnitData, error)
    89  	UpdateBannerRemoteAccessIP(ctx context.Context, remoteAccessIP string, bannerEdgeID string) error
    90  	GetBannerRemoteAccessIP(ctx context.Context, bannerEdgeID string) (string, error)
    91  	GetBannerInfraStatus(ctx context.Context, bannerEdgeID string) (*model.BannerStatus, error)
    92  	UpdateBannerEdgeSecurityCompliance(ctx context.Context, optInEdgeSecurityCompliance model.EdgeSecurityComplianceOptions, bannerEdgeID string) error
    93  }
    94  
    95  type bannerService struct {
    96  	GkeService        GkeClient
    97  	ChariotService    ChariotService
    98  	BSLClient         *bsl.Client
    99  	TopLevelProjectID string
   100  	SQLDB             *sql.DB
   101  	config            *apiTypes.Config
   102  }
   103  
   104  func (o *bannerService) UpdateBannerSQL(ctx context.Context, update *model.Banner) error {
   105  	_, err := o.SQLDB.ExecContext(ctx, sqlquery.UpdateBanner, update.Name, update.Description, update.BannerEdgeID)
   106  	if err != nil {
   107  		return sqlerr.Wrap(err)
   108  	}
   109  	return nil
   110  }
   111  
   112  func (o *bannerService) UpdateEUBanner(ctx context.Context, update *model.Banner) error {
   113  	desc := ""
   114  	if update.Description != nil {
   115  		desc = *update.Description
   116  	}
   117  	payload := mapper.ToEnterpriseUnitData(update.BannerBSLId, update.Name, desc, types.IsOrganization, true)
   118  	err := o.BSLClient.WithUserTokenCredentials(ctx).SetPayload(payload).Put(BspEnterpriseUnitPath)
   119  	if err != nil {
   120  		log.Err(err).Msg("error from bsp while updating an eu")
   121  	}
   122  	return err
   123  }
   124  
   125  func (o *bannerService) UpdateOrgBanner(ctx context.Context, update *model.Banner) error {
   126  	desc := ""
   127  	if update.Description != nil {
   128  		desc = *update.Description
   129  	}
   130  	orgData := &types.UpdateOrganizationData{
   131  		Description: desc,
   132  		DisplayName: update.Name,
   133  	}
   134  	err := o.BSLClient.WithUserTokenCredentials(ctx).SetPayload(orgData).Put(fmt.Sprintf(updateOrganization, update.BannerBSLId))
   135  	if err != nil {
   136  		log.Err(err).Msg("error from bsp while updating an org")
   137  	}
   138  	return err
   139  }
   140  
   141  func (o *bannerService) GetBanner(ctx context.Context, bannerEdgeID string) (*model.Banner, error) {
   142  	var (
   143  		optedInEdgeSecurityCompliance *bool
   144  	)
   145  
   146  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByBannerID, bannerEdgeID)
   147  	bannerModel := &model.Banner{}
   148  	bannerModel.BslEntityTypes = []string{}
   149  	err := row.Scan(&bannerModel.BannerEdgeID, &bannerModel.BannerBSLId, &bannerModel.Name, &bannerModel.BannerType, &bannerModel.Description, &bannerModel.ProjectID, &bannerModel.TenantEdgeID, &bannerModel.BslDataSynced, pq.Array(&bannerModel.BslEntityTypes), &optedInEdgeSecurityCompliance)
   150  	if err != nil {
   151  		return bannerModel, sqlerr.Wrap(err)
   152  	}
   153  
   154  	bannerModel.OptInEdgeSecurityCompliance = o.config.EdgeOptInSecurityCompliance
   155  	if optedInEdgeSecurityCompliance != nil {
   156  		bannerModel.OptInEdgeSecurityCompliance = *optedInEdgeSecurityCompliance
   157  	}
   158  	return bannerModel, nil
   159  }
   160  
   161  func (o *bannerService) GetBannerInfraStatus(ctx context.Context, bannerEdgeID string) (*model.BannerStatus, error) {
   162  	status := &model.BannerStatus{}
   163  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerInfraStatusByBannerEdgeID, bannerEdgeID)
   164  	if err := row.Scan(&status.Reason, &status.Message, &status.LastUpdatedAt); err != nil {
   165  		return nil, sqlerr.Wrap(err)
   166  	}
   167  	switch status.Reason {
   168  	case string(edgedb.InfraStatusReady):
   169  		status.Reason = ProvisionedStatus
   170  		status.Ready = true
   171  	default:
   172  		status.Reason = string(edgedb.InfraStatusProvisioning)
   173  
   174  		// Check if the banner's status message and lastUpdatedAt timestamp are empty
   175  		// since they may not be available yet (e.g., it has not been reconciled,
   176  		// there're issues writing to the db, etc.). If empty, defaults are used.
   177  		if status.Message == "" {
   178  			status.Message = ProvisioningStatusMessage
   179  		}
   180  		if status.LastUpdatedAt == "" {
   181  			status.LastUpdatedAt = time.Now().Format(time.RFC3339)
   182  		}
   183  	}
   184  	return status, nil
   185  }
   186  
   187  func (o *bannerService) CheckBannerInBSL(ctx context.Context, bannerModel *model.Banner) (*model.Banner, error) {
   188  	matchErr := apierror.New(apierror.BannerCheckMessage)
   189  	var bslBanner *model.Banner
   190  	if banner.Type(bannerModel.BannerType) == banner.Org {
   191  		org, err := o.GetBSLOrganization(ctx, bannerModel.BannerBSLId)
   192  		if err != nil {
   193  			return bannerModel, matchErr.AddGenericErrorExtension(apierror.BannerCheckKey, []string{fmt.Sprintf("banner %s not found in bsl: %s", bannerModel.Name, err.Error())})
   194  		}
   195  		bslBanner = mapper.BSLOrgToBanner(org)
   196  	} else {
   197  		eu, err := o.GetBSLEU(ctx, bannerModel.BannerBSLId)
   198  		if err != nil {
   199  			return bannerModel, matchErr.AddGenericErrorExtension(apierror.BannerCheckKey, []string{fmt.Sprintf("banner %s not found in bsl: %s", bannerModel.Name, err.Error())})
   200  		}
   201  		bslBanner = mapper.EnterpriseUnitToBanner(eu)
   202  	}
   203  	bannerModel, matchErr = bannerCheck(bslBanner, bannerModel, matchErr)
   204  	if len(matchErr.Ext[apierror.BannerCheckKey].([]string)) == 0 {
   205  		return bannerModel, nil
   206  	}
   207  	return bannerModel, matchErr
   208  }
   209  
   210  func (o *bannerService) GetBannerByNameAndTenant(ctx context.Context, name, orgName string) (*model.Banner, error) {
   211  	var (
   212  		optedInEdgeSecurityCompliance *bool
   213  	)
   214  
   215  	var tenant model.Tenant
   216  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.TenantGetByName, orgName)
   217  	if err := row.Scan(&tenant.TenantEdgeID, &tenant.TenantBSLId, &tenant.OrgName); err != nil {
   218  		return nil, sqlerr.Wrap(err)
   219  	}
   220  	row = o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByBannerByNameAndTenant, name, tenant.TenantEdgeID)
   221  	bannerModel := model.Banner{}
   222  	err := row.Scan(&bannerModel.BannerEdgeID, &bannerModel.BannerBSLId, &bannerModel.Name, &bannerModel.BannerType, &bannerModel.Description, &bannerModel.ProjectID, &bannerModel.TenantEdgeID, &optedInEdgeSecurityCompliance)
   223  	if err != nil {
   224  		return nil, sqlerr.Wrap(err)
   225  	}
   226  	bannerModel.OptInEdgeSecurityCompliance = o.config.EdgeOptInSecurityCompliance
   227  	if optedInEdgeSecurityCompliance != nil {
   228  		bannerModel.OptInEdgeSecurityCompliance = *optedInEdgeSecurityCompliance
   229  	}
   230  	return &bannerModel, nil
   231  }
   232  
   233  func (o *bannerService) GetBannerTenantInfo(ctx context.Context, orgName string) (*model.Tenant, error) {
   234  	var orgUUID, id, name string
   235  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerTenantByOrgName, orgName)
   236  	err := row.Scan(&orgUUID, &id, &name)
   237  	tenant := &model.Tenant{
   238  		TenantEdgeID: orgUUID,
   239  		TenantBSLId:  id,
   240  		OrgName:      name,
   241  	}
   242  	if err != nil {
   243  		return tenant, sqlerr.Wrap(err)
   244  	}
   245  	return tenant, nil
   246  }
   247  
   248  func (o *bannerService) GetBannerProjectID(ctx context.Context, bannerEdgeID string) (string, error) {
   249  	var projectID string
   250  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetProjectIDByBanner, bannerEdgeID)
   251  	err := row.Scan(&projectID)
   252  	if err != nil {
   253  		return projectID, sqlerr.Wrap(err)
   254  	}
   255  	return projectID, nil
   256  }
   257  
   258  // GetBanners gets all the enterprise unit and sub orgs from BSL, maps them to a Banner and returns the banner.
   259  func (o *bannerService) GetBanners(ctx context.Context) ([]*model.Banner, error) {
   260  	user := middleware.ForContext(ctx)
   261  	var (
   262  		banners []*model.Banner
   263  		eus     []*types.EnterpriseUnitData
   264  		orgs    []*types.OrganizationViewData
   265  		err     error
   266  	)
   267  	if utils.Contains(user.Roles, string(model.RoleEdgeOrgAdmin)) {
   268  		eus, err = getAllEUs(o.BSLClient.WithUserTokenCredentials(ctx))
   269  		if err != nil {
   270  			return nil, err
   271  		}
   272  		banners = append(banners, mapper.EnterpriseUnitsToBanners(eus)...)
   273  		orgName := bsl.GetOrgShortName(user.Organization)
   274  		orgs, err = getAllSubOrgs(o.BSLClient.WithUserTokenCredentials(ctx), orgName)
   275  		if err != nil {
   276  			return nil, err
   277  		}
   278  		banners = append(banners, mapper.SubOrgsToBanners(orgs)...)
   279  	} else {
   280  		banners, err = o.getUserAssignedBanners(ctx, bsl.CreateFullAccountName(user))
   281  		if err != nil {
   282  			return nil, err
   283  		}
   284  	}
   285  	if len(banners) == 0 {
   286  		return banners, nil
   287  	}
   288  	return o.GetEdgeBannerInfo(ctx, banners), nil
   289  }
   290  
   291  func (o *bannerService) GetEdgeBannerInfo(ctx context.Context, banners []*model.Banner) []*model.Banner {
   292  	edgeBanners := []*model.Banner{}
   293  	for _, banner := range banners {
   294  		matchErr := apierror.New(apierror.BannerCheckMessage)
   295  		row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByBSLID, banner.BannerBSLId)
   296  		sqlInfo := &model.Banner{}
   297  		sqlInfo.BslEntityTypes = []string{}
   298  		var optedInEdgeSecurityCompliance *bool
   299  		err := row.Scan(&sqlInfo.BannerEdgeID, &sqlInfo.BannerBSLId, &sqlInfo.Name, &sqlInfo.BannerType, &sqlInfo.ProjectID, &sqlInfo.TenantEdgeID, &sqlInfo.Description, &sqlInfo.BslDataSynced, pq.Array(&sqlInfo.BslEntityTypes), &optedInEdgeSecurityCompliance)
   300  		if err != nil {
   301  			_, matchErr = bannerCheck(banner, nil, matchErr)
   302  			if len(matchErr.Ext[apierror.BannerCheckKey].([]string)) > 0 {
   303  				banner.MismatchInfo = matchErr.Ext[apierror.BannerCheckKey].([]string)
   304  			}
   305  		} else {
   306  			banner, matchErr = bannerCheck(banner, sqlInfo, matchErr)
   307  			if len(matchErr.Ext[apierror.BannerCheckKey].([]string)) > 0 {
   308  				banner.MismatchInfo = matchErr.Ext[apierror.BannerCheckKey].([]string)
   309  			}
   310  			banner.OptInEdgeSecurityCompliance = o.config.EdgeOptInSecurityCompliance
   311  			if optedInEdgeSecurityCompliance != nil {
   312  				banner.OptInEdgeSecurityCompliance = *optedInEdgeSecurityCompliance
   313  			}
   314  			edgeBanners = append(edgeBanners, banner)
   315  		}
   316  	}
   317  	return edgeBanners
   318  }
   319  
   320  func (o *bannerService) UpdateBannerRemoteAccessIP(ctx context.Context, remoteAccessIP string, bannerEdgeID string) error {
   321  	if _, err := o.SQLDB.ExecContext(ctx, sqlquery.UpdateBannerRemoteAccessIP, remoteAccessIP, bannerEdgeID); err != nil {
   322  		return sqlerr.Wrap(err)
   323  	}
   324  	return nil
   325  }
   326  
   327  func (o *bannerService) UpdateBannerEdgeSecurityCompliance(ctx context.Context, optInEdgeSecurityCompliance model.EdgeSecurityComplianceOptions, bannerEdgeID string) error {
   328  	user := middleware.ForContext(ctx)
   329  	auditLog := audit.New("api")
   330  	var optInSetting *bool
   331  	switch optInEdgeSecurityCompliance {
   332  	case model.EdgeSecurityComplianceOptionsOptOut:
   333  		optInSetting = ptr.To(false)
   334  	case model.EdgeSecurityComplianceOptionsOptIn:
   335  		optInSetting = ptr.To(true)
   336  	case model.EdgeSecurityComplianceOptionsDefault:
   337  		optInSetting = nil
   338  	}
   339  	if _, err := o.SQLDB.ExecContext(ctx, sqlquery.UpdateBannerEdgeSecurityCompliance, optInSetting, bannerEdgeID); err != nil {
   340  		return sqlerr.Wrap(err)
   341  	}
   342  	var complianceType string
   343  	if optInSetting == nil {
   344  		complianceType = audit.ComplianceDefault
   345  	} else if *optInSetting {
   346  		complianceType = audit.ComplianceOptIn
   347  	} else if !*optInSetting {
   348  		complianceType = audit.ComplianceOptOut
   349  	}
   350  	auditLog.LogComplianceChange(complianceType, "action_by", user.Username, "bannerEdgeID", bannerEdgeID)
   351  	return nil
   352  }
   353  
   354  func bannerCheck(bslBanner, sqlBanner *model.Banner, matchErr *apierror.Error) (*model.Banner, *apierror.Error) {
   355  	message := []string{}
   356  	if val, ok := matchErr.Ext[apierror.BannerCheckKey]; ok {
   357  		message = val.([]string)
   358  	}
   359  	if sqlBanner == nil {
   360  		message = append(message, fmt.Sprintf("matching row not found for bsl banner: %s", bslBanner.Name))
   361  		return bslBanner, matchErr.AddGenericErrorExtension(apierror.BannerCheckKey, message)
   362  	}
   363  
   364  	// check banner name
   365  	if bslBanner.Name != sqlBanner.Name {
   366  		message = append(message, fmt.Sprintf("name not match for bsl banner %s (bsl name: %s, sql name: %s)", bslBanner.Name, bslBanner.Name, sqlBanner.Name))
   367  		sqlBanner.Name = bslBanner.Name
   368  	}
   369  	//check banner description
   370  	bslDescription := ""
   371  	sqlDescription := ""
   372  	if bslBanner.Description != nil {
   373  		bslDescription = *bslBanner.Description
   374  	}
   375  	if sqlBanner.Description != nil {
   376  		sqlDescription = *sqlBanner.Description
   377  	}
   378  	if bslDescription != sqlDescription {
   379  		message = append(message, fmt.Sprintf("description not match for bsl banner %s (bsl description: %s, sql description: %s)", bslBanner.Name, bslDescription, sqlDescription))
   380  		sqlBanner.Description = bslBanner.Description
   381  	}
   382  	return sqlBanner, matchErr.AddGenericErrorExtension(apierror.BannerCheckKey, message)
   383  }
   384  
   385  // GetBannerNameByBannerID get the banner name by the eu/Org id
   386  func (o *bannerService) GetBannerNameByBannerID(ctx context.Context, id string) (string, error) {
   387  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerNameByBannerID, id)
   388  	var name string
   389  	if err := row.Scan(&name); err != nil {
   390  		return "", sqlerr.Wrap(err)
   391  	}
   392  	return name, nil
   393  }
   394  
   395  // GetBannerEdgeIDByBannerID get the banner edge id by the eu/Org id
   396  // Deadcode
   397  func (o *bannerService) GetBannerEdgeIDByBannerID(ctx context.Context, id string) (string, error) {
   398  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerEdgeIDByBannerID, id)
   399  	var name string
   400  	if err := row.Scan(&name); err != nil {
   401  		return "", sqlerr.Wrap(err)
   402  	}
   403  	return name, nil
   404  }
   405  
   406  // GetClusterInfraInfo get the active status of the banner by banner edge id and 'cluster-infra' label
   407  func (o *bannerService) GetClusterInfraInfo(ctx context.Context, bannerEdgeID string) (*model.Cluster, error) {
   408  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetClusterInfraInfo, bannerEdgeID)
   409  	var clusterEdgeID, clusterName, projectID string
   410  	var active bool
   411  	if err := row.Scan(&clusterEdgeID, &clusterName, &projectID, &active); err != nil {
   412  		return nil, sqlerr.Wrap(err)
   413  	}
   414  	cluster := &model.Cluster{
   415  		ClusterEdgeID: clusterEdgeID,
   416  		Name:          clusterName,
   417  		ProjectID:     projectID,
   418  		Active:        &active,
   419  		BannerEdgeID:  bannerEdgeID,
   420  	}
   421  	return cluster, nil
   422  }
   423  
   424  func (o *bannerService) GetBannerInfraInfo(ctx context.Context) (*model.Cluster, error) {
   425  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerInfraInfo)
   426  	var clusterEdgeID, clusterName, projectID string
   427  	var active bool
   428  	if err := row.Scan(&clusterEdgeID, &clusterName, &projectID, &active); err != nil {
   429  		return nil, sqlerr.Wrap(err)
   430  	}
   431  	cluster := &model.Cluster{
   432  		ClusterEdgeID: clusterEdgeID,
   433  		Name:          clusterName,
   434  		ProjectID:     projectID,
   435  		Active:        &active,
   436  		BannerEdgeID:  "",
   437  	}
   438  	return cluster, nil
   439  }
   440  
   441  func (o *bannerService) GetBannerInfraBucketPath(ctx context.Context) (string, error) {
   442  	bi, err := o.GetBannerInfraInfo(ctx)
   443  	if err != nil {
   444  		return "", err
   445  	}
   446  	return bi.ClusterEdgeID, nil
   447  }
   448  
   449  func (o *bannerService) GetBannerByEdgeID(ctx context.Context, bannerUUID string) (*model.Banner, error) {
   450  	var (
   451  		optedInEdgeSecurityCompliance *bool
   452  	)
   453  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByID, bannerUUID)
   454  	var uuid, bannerID, bannerName, bannerType, projectID, tenant, description string
   455  	if err := row.Scan(&uuid, &bannerID, &bannerName, &bannerType, &projectID, &tenant, &description, &optedInEdgeSecurityCompliance); err != nil {
   456  		return nil, sqlerr.Wrap(err)
   457  	}
   458  	bannerModel := &model.Banner{
   459  		BannerBSLId:  bannerID,
   460  		Name:         bannerName,
   461  		Description:  &description,
   462  		BannerType:   bannerType,
   463  		TenantEdgeID: tenant,
   464  		ProjectID:    projectID,
   465  		BannerEdgeID: bannerUUID,
   466  	}
   467  
   468  	bannerModel.OptInEdgeSecurityCompliance = o.config.EdgeOptInSecurityCompliance
   469  	if optedInEdgeSecurityCompliance != nil {
   470  		bannerModel.OptInEdgeSecurityCompliance = *optedInEdgeSecurityCompliance
   471  	}
   472  	return bannerModel, nil
   473  }
   474  
   475  func (o *bannerService) GetBannerByBSLID(ctx context.Context, bannerBSLID string) (*model.Banner, error) {
   476  	banner := &model.Banner{}
   477  	banner.BslEntityTypes = []string{}
   478  	var optedInEdgeSecurityCompliance *bool
   479  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByBSLID, bannerBSLID)
   480  	err := row.Scan(&banner.BannerEdgeID, &banner.BannerBSLId, &banner.Name, &banner.BannerType, &banner.ProjectID, &banner.TenantEdgeID, &banner.Description, &banner.BslDataSynced, pq.Array(&banner.BslEntityTypes), &optedInEdgeSecurityCompliance)
   481  	if err != nil {
   482  		log.Ctx(ctx).Err(err).Msg("matching row not found for bsl banner: " + bannerBSLID)
   483  		return nil, sqlerr.Wrap(err)
   484  	}
   485  	banner.OptInEdgeSecurityCompliance = o.config.EdgeOptInSecurityCompliance
   486  	if optedInEdgeSecurityCompliance != nil {
   487  		banner.OptInEdgeSecurityCompliance = *optedInEdgeSecurityCompliance
   488  	}
   489  	return banner, nil
   490  }
   491  
   492  // probably need to better differentiate when to return api model vs cr
   493  func (o *bannerService) GetBannerCRByID(ctx context.Context, bannerUUID string) (*bannerv1alpha1.Banner, error) {
   494  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerByID, bannerUUID)
   495  
   496  	var uuid, bannerID, bannerName, bannerType, projectID, tenant, description string
   497  	var edgeOptInSecurityCompliance *bool
   498  	if err := row.Scan(&uuid, &bannerID, &bannerName, &bannerType, &projectID, &tenant, &description, &edgeOptInSecurityCompliance); err != nil {
   499  		return nil, sqlerr.Wrap(err)
   500  	}
   501  
   502  	// todo - mostly copy paste from capability service, need to refactor sql calls to prevent cross service dependencies
   503  	rows, err := o.SQLDB.QueryContext(ctx, sqlquery.ListCapabilitiesByBannerQuery, bannerUUID)
   504  	if err != nil {
   505  		return nil, sqlerr.Wrap(err)
   506  	}
   507  	var capabilities []string
   508  	defer rows.Close()
   509  	for rows.Next() {
   510  		var capability model.Capability
   511  		if err = rows.Scan(&capability.UUID, &capability.Name, &capability.Description); err != nil {
   512  			return nil, sqlerr.Wrap(err)
   513  		}
   514  		capabilities = append(capabilities, capability.Name)
   515  	}
   516  	if err := rows.Err(); err != nil {
   517  		return nil, sqlerr.Wrap(err)
   518  	}
   519  
   520  	user := middleware.ForContext(ctx)
   521  	bslName := bsl.GetOrgShortName(user.Organization)
   522  
   523  	return utils.NewBanner(uuid, bannerName, bslName, bannerID, projectID, capabilities), nil
   524  }
   525  
   526  // GetBSLOrganization gets the bsl organization with the provided reference.
   527  func (o *bannerService) GetBSLOrganization(ctx context.Context, organization string) (*bsl.BSLOrganization, error) {
   528  	data := &bsl.BSLOrganization{}
   529  	err := o.BSLClient.WithUserTokenCredentials(ctx).JSON(http.MethodGet, fmt.Sprintf("%s/%s", BslOrgPath, organization), data)
   530  	if err != nil {
   531  		return nil, err
   532  	}
   533  	return data, nil
   534  }
   535  
   536  func (o *bannerService) GetBSLEU(ctx context.Context, eu string) (*types.EnterpriseUnitData, error) {
   537  	data := &types.EnterpriseUnitData{}
   538  	err := o.BSLClient.WithUserTokenCredentials(ctx).JSON(http.MethodGet, fmt.Sprintf(getEnterpriseUnit, eu), data)
   539  	if err != nil {
   540  		return nil, err
   541  	}
   542  	return data, nil
   543  }
   544  
   545  func (o *bannerService) GetBannerTypeFromID(ctx context.Context, id string) (banner.Type, error) {
   546  	var bannerType string
   547  	err := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerTypeFromIDQuery, id).Scan(&bannerType)
   548  	if err != nil {
   549  		return "", sqlerr.Wrap(err)
   550  	}
   551  	return banner.Type(bannerType), nil
   552  }
   553  
   554  func (o *bannerService) GetBannerTypeFromUUID(ctx context.Context, uuid string) (banner.Type, error) {
   555  	var bannerType string
   556  	err := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerTypeFromUUIDQuery, uuid).Scan(&bannerType)
   557  	if err != nil {
   558  		return "", sqlerr.Wrap(err)
   559  	}
   560  	return banner.Type(bannerType), nil
   561  }
   562  
   563  func (o *bannerService) GetBannerTypeFromNameAndTenant(ctx context.Context, name, tenant string) (banner.Type, error) {
   564  	var bannerType string
   565  	err := o.SQLDB.QueryRowContext(ctx, sqlquery.GetBannerTypeFromNameAndTenantQuery, name, tenant).Scan(&bannerType)
   566  	if err != nil {
   567  		return "", sqlerr.Wrap(err)
   568  	}
   569  	return banner.Type(bannerType), nil
   570  }
   571  
   572  func (o *bannerService) GetUserAssignedBanners(ctx context.Context, username string) ([]*model.BannerInfo, error) {
   573  	banners, err := o.getUserAssignedBanners(ctx, username)
   574  	if err != nil {
   575  		return make([]*model.BannerInfo, 0), err
   576  	}
   577  	for _, banner := range banners {
   578  		sqlBanner, err := o.GetBannerByBSLID(ctx, banner.BannerBSLId)
   579  		if err != nil {
   580  			return nil, err
   581  		}
   582  		banner.BannerEdgeID = sqlBanner.BannerEdgeID
   583  		banner.BannerType = sqlBanner.BannerType
   584  	}
   585  	return toBannersList(banners), nil
   586  }
   587  
   588  func (o *bannerService) GetBannerRemoteAccessIP(ctx context.Context, bannerEdgeID string) (string, error) {
   589  	var remoteAccessIP string
   590  	if err := o.SQLDB.QueryRowContext(ctx, sqlquery.GetRemoteAccessIPByBannerEdgeID, bannerEdgeID).Scan(&remoteAccessIP); err != nil {
   591  		return "", sqlerr.Wrap(err)
   592  	}
   593  	return remoteAccessIP, nil
   594  }
   595  
   596  func toBannersList(data []*model.Banner) []*model.BannerInfo {
   597  	banners := make([]*model.BannerInfo, 0)
   598  	for _, banner := range data {
   599  		banners = append(banners, &model.BannerInfo{BannerBSLId: banner.BannerBSLId, Name: banner.Name, BannerType: banner.BannerType, BannerEdgeID: banner.BannerEdgeID})
   600  	}
   601  	return banners
   602  }
   603  
   604  func (o *bannerService) getUserAssignedBanners(ctx context.Context, username string) ([]*model.Banner, error) {
   605  	banners := make([]*model.Banner, 0)
   606  	lowercaseUsername := strings.ToLower(username)
   607  	orgs, err := o.getUserAssignedOrgs(ctx, lowercaseUsername)
   608  	if err != nil {
   609  		return nil, err
   610  	}
   611  	banners = append(banners, mapper.SubExternalUsersToBanners(orgs)...)
   612  	eus, err := o.getUserAssignedEUs(ctx, lowercaseUsername)
   613  	if err != nil {
   614  		return nil, err
   615  	}
   616  	banners = append(banners, mapper.EnterpriseUnitsToBanners(eus)...)
   617  	return banners, nil
   618  }
   619  
   620  func (o *bannerService) getUserAssignedOrgs(ctx context.Context, username string) ([]*types.ExternalUserData, error) {
   621  	orgs := []*types.ExternalUserData{}
   622  	data := &types.GetExternalUserResponse{}
   623  	user := middleware.ForContext(ctx)
   624  	pageNumber := 0
   625  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   626  	for !data.LastPage {
   627  		err := client.JSON(http.MethodGet, fmt.Sprintf(bspUserAssignedSubOrgsPath, username, pageNumber, pageSize), data)
   628  		if err != nil {
   629  			if apierror.IsNotFoundError(err) { //fix this for Error
   630  				return []*types.ExternalUserData{}, nil
   631  			}
   632  			return nil, err
   633  		}
   634  		//remove tenant and commerce orgs, remove orgs that are not a child of the tenant org
   635  		for _, org := range data.PageContent {
   636  			if org.OrganizationName == user.Organization && strings.Contains(username, commerceOrg) {
   637  				continue
   638  			}
   639  			if strings.Contains(org.OrganizationName, commerceOrg) {
   640  				continue
   641  			}
   642  			if !strings.Contains(org.OrganizationName, user.Organization) {
   643  				continue
   644  			}
   645  			orgs = append(orgs, org)
   646  		}
   647  		pageNumber++
   648  	}
   649  	return orgs, nil
   650  }
   651  
   652  func (o *bannerService) getUserAssignedEUs(ctx context.Context, username string) ([]*types.EnterpriseUnitData, error) {
   653  	var orgs []*types.EnterpriseUnitData
   654  	data := &types.FindEnterpriseUnitsResponse{}
   655  
   656  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   657  
   658  	pageNumber := 0
   659  	for !data.LastPage {
   660  		err := client.JSON(http.MethodGet, fmt.Sprintf(bspGetAllAssignedOrgURL+bspPaging, username, pageNumber, pageSize), data)
   661  		if err != nil {
   662  			return nil, err
   663  		}
   664  		for _, eu := range data.PageContent {
   665  			if eu.EnterpriseUnitID == "" {
   666  				continue
   667  			}
   668  			userOrganization, err := getEnterpriseUnitData(client, eu.EnterpriseUnitID)
   669  			if err != nil {
   670  				return nil, err
   671  			}
   672  
   673  			if userOrganization.Active {
   674  				orgs = append(orgs, &types.EnterpriseUnitData{
   675  					Name:             userOrganization.Name,
   676  					Description:      userOrganization.Description,
   677  					EnterpriseUnitID: userOrganization.EnterpriseUnitID,
   678  				})
   679  			}
   680  		}
   681  		pageNumber++
   682  	}
   683  	return orgs, nil
   684  }
   685  
   686  func getEnterpriseUnitData(client *bsl.Request, enterpriseUnitID string) (*types.EnterpriseUnitData, error) {
   687  	data := &types.EnterpriseUnitData{}
   688  	return data, client.JSON(http.MethodGet, BspEnterpriseUnitPath+"/"+enterpriseUnitID, data)
   689  }
   690  
   691  // getAllEUs gets all the enterprise units from BSL.
   692  func getAllEUs(client *bsl.Request) ([]*types.EnterpriseUnitData, error) {
   693  	var orgs []*types.EnterpriseUnitData
   694  	data := &types.FindEnterpriseUnitsResponse{}
   695  
   696  	pageNumber := 0
   697  	for pageNumber <= data.TotalPages {
   698  		err := client.
   699  			JSON(http.MethodGet, fmt.Sprintf(bspEnterpriseUnitOrganizationsPath+bspPaging, pageNumber, pageSize), data)
   700  		if err != nil {
   701  			return nil, err
   702  		}
   703  		orgs = append(orgs, data.PageContent...)
   704  		pageNumber++
   705  	}
   706  	return orgs, nil
   707  }
   708  
   709  // getAllSubOrgs gets all the sub orgs for a parent organization in BSL.
   710  func getAllSubOrgs(client *bsl.Request, parentOrg string) ([]*types.OrganizationViewData, error) {
   711  	var orgs []*types.OrganizationViewData
   712  	data := &types.GetOrganizationSubOrgsResponse{}
   713  
   714  	pageNumber := 0
   715  	for pageNumber <= data.TotalPages {
   716  		if data.LastPage {
   717  			break
   718  		}
   719  		err := client.JSON(http.MethodGet, fmt.Sprintf(bspSubOrganizationsPath, parentOrg, pageNumber, pageSize), data)
   720  		if err != nil {
   721  			return nil, err
   722  		}
   723  		orgs = append(orgs, data.PageContent...)
   724  		pageNumber++
   725  	}
   726  	return orgs, nil
   727  }
   728  
   729  func (o *bannerService) CreateBannerCr(ctx context.Context, uuid, projectID, name, enterpriseUnitID string, enablements []string) (string, error) {
   730  	user := middleware.ForContext(ctx)
   731  	bannerRequest := utils.NewBanner(uuid, name, bsl.GetOrgShortName(user.Organization), enterpriseUnitID, projectID, enablements)
   732  	if err := bannerRequest.IsValid(); err != nil {
   733  		return "", err
   734  	}
   735  	bannerRequestByte, err := json.Marshal(bannerRequest)
   736  	if err != nil {
   737  		return "", err
   738  	}
   739  	bannerRequestBase64 := utils.ToBase64(bannerRequestByte)
   740  	return bannerRequestBase64, nil
   741  }
   742  
   743  func (o *bannerService) CreateBannerSQLEntry(ctx context.Context, projectID, bannerName, bannerType, enterpriseUnitID, bannerUUID, description string) error {
   744  	var tenantID string
   745  	user := middleware.ForContext(ctx)
   746  	row := o.SQLDB.QueryRowContext(ctx, sqlquery.GetTenantByOrgNameQuery, bsl.GetOrgShortName(user.Organization))
   747  	if err := row.Scan(&tenantID); err != nil {
   748  		return sqlerr.Wrap(err)
   749  	}
   750  	_, err := o.SQLDB.ExecContext(ctx, sqlquery.BannerInsertQuery, enterpriseUnitID, bannerName, bannerType, projectID, tenantID, bannerUUID, description)
   751  	if err != nil {
   752  		return sqlerr.Wrap(err)
   753  	}
   754  	return nil
   755  }
   756  
   757  func (o *bannerService) DeleteBannerSQLEntry(ctx context.Context, bannerUUID string) error {
   758  	_, err := o.SQLDB.ExecContext(ctx, sqlquery.DeleteBannerQuery, bannerUUID)
   759  	if err != nil {
   760  		return sqlerr.Wrap(err)
   761  	}
   762  	return nil
   763  }
   764  
   765  func (o *bannerService) CreateEUBanner(ctx context.Context, name string, description *string) (*model.Banner, error) {
   766  	desc := ""
   767  	if !utils.IsNullOrEmpty(description) {
   768  		desc = *description
   769  	}
   770  
   771  	eud := &types.EnterpriseUnitData{}
   772  	err := o.BSLClient.WithUserTokenCredentials(ctx).
   773  		SetPayload(mapper.ToEnterpriseUnitData("", name, desc, types.IsOrganization, true)).
   774  		JSON(http.MethodPost, BspEnterpriseUnitPath, eud)
   775  	if err != nil {
   776  		log.Err(err).Msg("error from bsp while creating an org")
   777  		return nil, err
   778  	}
   779  
   780  	return mapper.EnterpriseUnitToBanner(eud), nil
   781  }
   782  
   783  func (o *bannerService) CreateOrganizationBanner(ctx context.Context, name string, description *string) (*model.Banner, error) {
   784  	user := middleware.ForContext(ctx)
   785  
   786  	desc := ""
   787  	if !utils.IsNullOrEmpty(description) {
   788  		desc = *description
   789  	}
   790  
   791  	createOrg := &types.CreateOrganizationRequest{
   792  		Name:                   name,
   793  		Description:            desc,
   794  		DisplayName:            name + " Banner",
   795  		ParentOrganizationName: user.Organization,
   796  	}
   797  	orgResponse := &types.CreateOrganizationResponse{}
   798  	err := o.BSLClient.WithUserTokenCredentials(ctx).SetPayload(createOrg).JSON(http.MethodPost, bspOrgPath, orgResponse)
   799  	if err != nil {
   800  		log.Err(err).Msg("error from bsp while creating an org")
   801  		return nil, err
   802  	}
   803  
   804  	return mapper.ToOrgBanner(orgResponse), nil
   805  }
   806  
   807  func (o *bannerService) UndoCreateBanner(ctx context.Context, name, id, uuid, bannerObject string, isOrgBanner *bool, bucketPath string) error {
   808  	var err error
   809  	if isOrgBanner != nil && *isOrgBanner {
   810  		_, err = o.DeleteOrgBanner(ctx, id)
   811  	} else {
   812  		_, err = o.DeleteEUBanner(ctx, name, id)
   813  	}
   814  
   815  	deleteErr := o.DeleteBannerSQLEntry(ctx, uuid)
   816  	if deleteErr != nil {
   817  		if err != nil {
   818  			err = fmt.Errorf("%w, error deleting banner sql entry: %s", err, deleteErr)
   819  		} else {
   820  			err = fmt.Errorf("error deleting banner sql entry: %w", deleteErr)
   821  		}
   822  	}
   823  
   824  	deleteStoreClusterMessage := chariotClientApi.
   825  		NewChariotMessage().
   826  		SetOperation(chariotClientApi.Delete).
   827  		SetOwner(ComponentOwner).
   828  		SetBanner(o.TopLevelProjectID).
   829  		SetCluster(bucketPath).
   830  		AddObject(bannerObject)
   831  
   832  	if deleteChariotMsgErr := o.ChariotService.InvokeChariotPubsub(ctx, deleteStoreClusterMessage, nil); deleteChariotMsgErr != nil {
   833  		err = fmt.Errorf("%w, error calling chariot v2 and deleting a banner cr: %s", err, deleteChariotMsgErr)
   834  	} else {
   835  		err = fmt.Errorf("error calling chariot v2 and deleting a banner cr: %w", deleteChariotMsgErr)
   836  	}
   837  	return err
   838  }
   839  
   840  func (o *bannerService) DeleteEUBanner(ctx context.Context, name, id string) (bool, error) {
   841  	dname := name + "-deleted-" + time.Now().UTC().String()
   842  	payload := mapper.ToEnterpriseUnitData(id, dname, "organization deleted", "", false)
   843  	err := o.BSLClient.WithUserTokenCredentials(ctx).SetPayload(payload).Put(BspEnterpriseUnitPath)
   844  	if err != nil {
   845  		log.Err(err).Msg("error from bsp while deleting an org")
   846  		return false, err
   847  	}
   848  	return true, nil
   849  }
   850  
   851  func (o *bannerService) DeleteOrgBanner(ctx context.Context, id string) (bool, error) {
   852  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   853  	err := client.Delete(fmt.Sprintf(bspDeleteOrgPath, id))
   854  	if err != nil {
   855  		log.Err(err).Msg("error from bsp while deleting an org")
   856  		return false, err
   857  	}
   858  	return true, nil
   859  }
   860  
   861  func (o *bannerService) AssignUserToEUBanners(ctx context.Context, username string, banners []string) error {
   862  	if err := o.clearAssignedEUBanners(ctx, username); err != nil {
   863  		return err
   864  	}
   865  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   866  	for _, banner := range banners {
   867  		err := client.Put(fmt.Sprintf(bspEnterpriseUnitGrantBasePath, username, banner))
   868  		if err != nil {
   869  			return err
   870  		}
   871  	}
   872  
   873  	return nil
   874  }
   875  
   876  // AssignUserToOrgBanners creates external user
   877  func (o *bannerService) AssignUserToOrgBanners(ctx context.Context, username string, banners []*model.Banner) error {
   878  	if err := o.clearAssignOrgBanners(ctx, username); err != nil {
   879  		return err
   880  	}
   881  
   882  	externalUser := &types.CreateExternalUserRequest{
   883  		Status:   ActiveStatus,
   884  		Username: username,
   885  	}
   886  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   887  	for _, banner := range banners {
   888  		err := client.SetOrgID(banner.BannerBSLId).SetPayload(externalUser).Post(bspExternalUserPath)
   889  		if err != nil {
   890  			return err
   891  		}
   892  	}
   893  	return nil
   894  }
   895  
   896  func (o *bannerService) GetUsersForEuBanner(ctx context.Context, bannerBSLID string) ([]*model.User, error) {
   897  	data := &types.FindUnitGrantsResponse{}
   898  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   899  	var userNames []types.UserName
   900  	pageNumber := 0
   901  	for !data.LastPage {
   902  		err := client.JSON(http.MethodGet, fmt.Sprintf(bspGetOrgUsersListPath, bannerBSLID, pageNumber, pageSize), data)
   903  		if err != nil {
   904  			return nil, err
   905  		}
   906  		if data.TotalPages == 0 { // weird bsl bug where LastPage is false and TotalPages is zero
   907  			break
   908  		}
   909  		for _, grantViewData := range data.PageContent {
   910  			userNames = append(userNames, types.UserName{Username: grantViewData.Username})
   911  		}
   912  		pageNumber++
   913  	}
   914  
   915  	if len(userNames) == 0 {
   916  		return make([]*model.User, 0), nil
   917  	}
   918  
   919  	payload := types.GetUserDetailsRequest{UserIDs: userNames}
   920  	res := &types.GetUserDetailsResponse{}
   921  	err := client.SetPayload(payload).JSON(http.MethodPost, bspUserDetailsPath, res)
   922  
   923  	if err != nil {
   924  		return nil, err
   925  	}
   926  	return res.Users, nil
   927  }
   928  
   929  func (o *bannerService) clearAssignedEUBanners(ctx context.Context, username string) error {
   930  	data, err := o.getUserAssignedEUs(ctx, username)
   931  	if err != nil {
   932  		return err
   933  	}
   934  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   935  	for _, eud := range data {
   936  		if eud.EnterpriseUnitID == "" {
   937  			continue
   938  		}
   939  		if err := revokeUser(client, username, eud.EnterpriseUnitID); err != nil {
   940  			return err
   941  		}
   942  	}
   943  	return nil
   944  }
   945  
   946  func revokeUser(client *bsl.Request, user string, organizationID string) error {
   947  	return client.Delete(fmt.Sprintf(bspEnterpriseUnitGrantBasePath, user, organizationID))
   948  }
   949  
   950  func (o *bannerService) clearAssignOrgBanners(ctx context.Context, username string) error {
   951  	orgs, err := o.getUserAssignedOrgs(ctx, username)
   952  	if err != nil {
   953  		return err
   954  	}
   955  	client := o.BSLClient.WithUserTokenCredentials(ctx)
   956  	for _, org := range orgs {
   957  		if org.Primary {
   958  			continue
   959  		}
   960  		if err := o.deleteExternalUser(client, username, org.OrganizationName); err != nil {
   961  			return err
   962  		}
   963  	}
   964  	return nil
   965  }
   966  
   967  func (o *bannerService) deleteExternalUser(client *bsl.Request, username, org string) error {
   968  	return client.SetOrg(org).Delete(fmt.Sprintf("%s/%s", bspUsersPath, username))
   969  }
   970  
   971  func (o *bannerService) DeleteClusterSQLEntry(ctx context.Context, clusterEdgeID string) error {
   972  	_, err := o.SQLDB.ExecContext(ctx, sqlquery.DeleteClusterQuery, clusterEdgeID)
   973  	if err != nil {
   974  		return sqlerr.Wrap(err)
   975  	}
   976  	return nil
   977  }
   978  
   979  func NewBannerService(gkeService GkeClient, chariotService ChariotService, bslClient *bsl.Client, project string, sqlDB *sql.DB, config *apiTypes.Config) BannerService {
   980  	return &bannerService{
   981  		GkeService:        gkeService,
   982  		ChariotService:    chariotService,
   983  		BSLClient:         bslClient,
   984  		SQLDB:             sqlDB,
   985  		TopLevelProjectID: project,
   986  		config:            config,
   987  	}
   988  }
   989  

View as plain text