...

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

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

     1  package services
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"strings"
     7  	"time"
     8  
     9  	secretmanagerpb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
    10  	_ "github.com/doug-martin/goqu/v9/dialect/mysql" //needed for generating the correctly formatted sql statement
    11  
    12  	gcperror "edge-infra.dev/pkg/edge/api/apierror/gcp"
    13  	"edge-infra.dev/pkg/edge/api/clients"
    14  	"edge-infra.dev/pkg/edge/api/graph/mapper"
    15  	"edge-infra.dev/pkg/edge/api/graph/model"
    16  	"edge-infra.dev/pkg/edge/api/types"
    17  	"edge-infra.dev/pkg/edge/api/utils"
    18  	workloadApi "edge-infra.dev/pkg/edge/constants/api/workload"
    19  	secretMgrApi "edge-infra.dev/pkg/lib/gcp/secretmanager"
    20  	gcputils "edge-infra.dev/pkg/lib/gcp/utils"
    21  )
    22  
    23  const PlatformSecret = "platform"
    24  const EdgeOwner = "edge"
    25  
    26  //go:generate mockgen -destination=../mocks/mock_gcp_service.go -package=mocks edge-infra.dev/pkg/edge/api/services GCPService
    27  type GCPService interface {
    28  	GetZones(ctx context.Context) ([]*string, error)
    29  	GetGKEVersions(ctx context.Context, zone string) ([]*string, error)
    30  	GetMachineTypes(ctx context.Context, zone string) ([]*model.MachineTypeInfo, error)
    31  	AddSecret(ctx context.Context, name, owner, t string, secrets []*model.KeyValues, projectID string, workload *string, expireAt *time.Time) error
    32  	GetMachineType(ctx context.Context, zone string, machineType string) (*model.MachineTypeInfo, error)
    33  	GetSecrets(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error)
    34  	DeleteSecret(ctx context.Context, name string, projectID string) (bool, error)
    35  }
    36  
    37  type gcpService struct {
    38  	GcpClientService  GcpClientService
    39  	TopLevelProjectID string
    40  	BigQueryClient    clients.BQClient
    41  }
    42  
    43  func (s *gcpService) GetZones(ctx context.Context) ([]*string, error) {
    44  	computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
    45  	if err != nil {
    46  		return nil, gcperror.Wrap(err)
    47  	}
    48  	zoneList, err := computeClient.GetZones(ctx)
    49  	if err != nil {
    50  		return nil, gcperror.Wrap(err)
    51  	}
    52  	return mapper.ToZones(zoneList), nil
    53  }
    54  
    55  func (s *gcpService) GetGKEVersions(ctx context.Context, zone string) ([]*string, error) {
    56  	containerClient, err := s.GcpClientService.GetContainerClient(ctx, s.TopLevelProjectID)
    57  	if err != nil {
    58  		return nil, gcperror.Wrap(err)
    59  	}
    60  	serverConfig, err := containerClient.GetServerConfig(ctx, zone)
    61  	if err != nil {
    62  		return nil, gcperror.Wrap(err)
    63  	}
    64  	return mapper.ToGkeVersions(serverConfig.ValidMasterVersions), nil
    65  }
    66  
    67  func (s *gcpService) GetMachineTypes(ctx context.Context, zone string) ([]*model.MachineTypeInfo, error) {
    68  	computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
    69  	if err != nil {
    70  		return nil, gcperror.Wrap(err)
    71  	}
    72  	machineList, err := computeClient.GetMachineTypes(ctx, zone)
    73  	if err != nil {
    74  		return nil, gcperror.Wrap(err)
    75  	}
    76  	return mapper.ToMachineTypes(machineList), nil
    77  }
    78  
    79  func (s *gcpService) GetMachineType(ctx context.Context, zone string, machineType string) (*model.MachineTypeInfo, error) {
    80  	computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
    81  	if err != nil {
    82  		return nil, gcperror.Wrap(err)
    83  	}
    84  	machineTypeInfo, err := computeClient.GetMachineType(ctx, zone, machineType)
    85  	if err != nil {
    86  		return nil, gcperror.Wrap(err)
    87  	}
    88  	return mapper.ToMachineType(machineTypeInfo), nil
    89  }
    90  
    91  func (s *gcpService) AddSecret(ctx context.Context, name, owner, t string, secrets []*model.KeyValues, projectID string, workload *string, expireAt *time.Time) error {
    92  	secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
    93  	if err != nil {
    94  		return gcperror.Wrap(err)
    95  	}
    96  	defer gcputils.CloseConnection(ctx, secretService)
    97  	m := make(map[string]string)
    98  	for _, s := range secrets {
    99  		m[s.Key] = s.Value
   100  	}
   101  	strSecret, err := json.Marshal(m)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	labels := map[string]string{
   106  		secretMgrApi.SecretLabel:      string(workloadApi.Tenant),
   107  		secretMgrApi.SecretTypeLabel:  t,
   108  		secretMgrApi.SecretOwnerLabel: owner,
   109  	}
   110  	if !utils.IsNullOrEmpty(workload) {
   111  		// we need to save this to be able to compare labels
   112  		labels[secretMgrApi.SecretNamespaceSelectorLabel] = *workload
   113  	}
   114  	err = secretService.AddSecret(ctx, name, strSecret, labels, false, expireAt, "")
   115  	if err != nil {
   116  		return gcperror.Wrap(err)
   117  	}
   118  	return nil
   119  }
   120  
   121  func (s *gcpService) GetSecrets(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error) {
   122  	secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
   123  	if err != nil {
   124  		return nil, gcperror.Wrap(err)
   125  	}
   126  	defer gcputils.CloseConnection(ctx, secretService)
   127  	secretsMap, err := getSecrets(ctx, name, owner, t, secretService)
   128  	if err != nil {
   129  		return nil, gcperror.Wrap(err)
   130  	}
   131  	res, err := mapSecretManagerToModel(ctx, secretsMap, getValues, secretService)
   132  	if err != nil {
   133  		return nil, gcperror.Wrap(err)
   134  	}
   135  	return res, nil
   136  }
   137  
   138  func getSecrets(ctx context.Context, name, owner, t *string, secretService types.SecretManagerService) ([]*secretmanagerpb.Secret, error) {
   139  	var secrets []*secretmanagerpb.Secret
   140  	var err error
   141  	if name != nil {
   142  		secret, err := secretService.GetSecret(ctx, *name)
   143  		if err != nil {
   144  			return nil, err
   145  		}
   146  		secrets = []*secretmanagerpb.Secret{secret}
   147  	} else {
   148  		secrets, err = secretService.ListSecrets(ctx, "")
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  	}
   153  	return secretManagerSecretsFiltered(secrets, t, owner), nil
   154  }
   155  
   156  func (s *gcpService) DeleteSecret(ctx context.Context, name string, projectID string) (bool, error) {
   157  	secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
   158  	if err != nil {
   159  		return false, gcperror.Wrap(err)
   160  	}
   161  	defer gcputils.CloseConnection(ctx, secretService)
   162  	err = secretService.DeleteSecret(ctx, name)
   163  	if err != nil {
   164  		return false, gcperror.Wrap(err)
   165  	}
   166  	return true, nil
   167  }
   168  
   169  func mapSecretManagerToModel(ctx context.Context, secrets []*secretmanagerpb.Secret, getValues bool, secretService types.SecretManagerService) ([]*model.SecretManagerResponse, error) {
   170  	result := []*model.SecretManagerResponse{}
   171  	for _, secret := range secrets {
   172  		var updated *string
   173  		var kv []*model.KeyValuesOutput
   174  		name := getSecretName(secret.Name)
   175  		if getValues {
   176  			secretValue, err := secretService.GetLatestSecretValue(ctx, name)
   177  			if err != nil {
   178  				return nil, err
   179  			}
   180  			secretInfo, err := secretService.GetLatestSecretValueInfo(ctx, name)
   181  			if err != nil {
   182  				return nil, err
   183  			}
   184  			var keyMap map[string]string
   185  			err = json.Unmarshal(secretValue, &keyMap)
   186  			if err != nil {
   187  				kv = []*model.KeyValuesOutput{{Key: name, Value: string(secretValue)}}
   188  			} else {
   189  				for k, v := range keyMap {
   190  					kv = append(kv, &model.KeyValuesOutput{Key: k, Value: v})
   191  				}
   192  			}
   193  			u := secretInfo.CreateTime.AsTime().Format(mapper.TimeFormat)
   194  			updated = &u
   195  		}
   196  		result = append(result, secretManagerToModel(name, secretService.GetProjectID(), secret, updated, kv))
   197  	}
   198  	return result, nil
   199  }
   200  
   201  func getSecretName(val string) string {
   202  	return val[strings.LastIndex(val, "/")+1:]
   203  }
   204  
   205  func secretManagerSecretsFiltered(secrets []*secretmanagerpb.Secret, filterType, owner *string) []*secretmanagerpb.Secret {
   206  	var filteredSecrets []*secretmanagerpb.Secret
   207  	for _, s := range secrets {
   208  		if filterType != nil {
   209  			if t, ok := s.Labels[secretMgrApi.SecretTypeLabel]; ok {
   210  				if *filterType != t {
   211  					continue
   212  				}
   213  			} else {
   214  				continue
   215  			}
   216  		}
   217  		if owner != nil {
   218  			if o, ok := s.Labels[secretMgrApi.SecretOwnerLabel]; ok {
   219  				if *owner != o {
   220  					continue
   221  				}
   222  			} else {
   223  				continue
   224  			}
   225  		}
   226  
   227  		filteredSecrets = append(filteredSecrets, s)
   228  	}
   229  	return filteredSecrets
   230  }
   231  
   232  func secretManagerToModel(name string, organization string, secret *secretmanagerpb.Secret, updated *string, kv []*model.KeyValuesOutput) *model.SecretManagerResponse {
   233  	var typ *string
   234  	w := PlatformSecret
   235  	o := EdgeOwner
   236  	workload := &w
   237  	owner := &o
   238  	if t, ok := secret.Labels[secretMgrApi.SecretTypeLabel]; ok {
   239  		typ = &t
   240  	}
   241  	if w, ok := secret.Labels[secretMgrApi.SecretLabel]; ok {
   242  		workload = &w
   243  	}
   244  	if o, ok := secret.Labels[secretMgrApi.SecretOwnerLabel]; ok {
   245  		owner = &o
   246  	}
   247  
   248  	created := secret.CreateTime.AsTime().Format(mapper.TimeFormat)
   249  	return &model.SecretManagerResponse{
   250  		Name:     name,
   251  		Project:  organization,
   252  		Created:  &created,
   253  		Updated:  updated,
   254  		Values:   kv,
   255  		Type:     typ,
   256  		Workload: workload,
   257  		Owner:    owner,
   258  	}
   259  }
   260  
   261  func NewGcpService(gcpClientService GcpClientService, topLevelProjectId string, bqClient clients.BQClient) *gcpService { //nolint stupid
   262  	return &gcpService{
   263  		GcpClientService:  gcpClientService,
   264  		TopLevelProjectID: topLevelProjectId,
   265  		BigQueryClient:    bqClient,
   266  	}
   267  }
   268  

View as plain text