...

Source file src/edge-infra.dev/pkg/edge/api/graph/resolver/helm_schema_queries.resolvers.go

Documentation: edge-infra.dev/pkg/edge/api/graph/resolver

     1  package resolver
     2  
     3  // This file will be automatically regenerated based on the schema, any resolver implementations
     4  // will be copied through when generating and any unknown code will be moved to the end.
     5  // Code generated by github.com/99designs/gqlgen version v0.17.45
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  
    12  	"edge-infra.dev/pkg/edge/api/apierror"
    13  	"edge-infra.dev/pkg/edge/api/graph/mapper"
    14  	"edge-infra.dev/pkg/edge/api/graph/model"
    15  	"edge-infra.dev/pkg/edge/api/utils"
    16  	"edge-infra.dev/pkg/edge/constants"
    17  	"k8s.io/apimachinery/pkg/util/validation"
    18  )
    19  
    20  // CreateHelmRelease is the resolver for the createHelmRelease field.
    21  func (r *mutationResolver) CreateHelmRelease(ctx context.Context, payload model.HelmReleasePayload) (bool, error) {
    22  	errors := validation.IsDNS1123Label(payload.Name)
    23  	if len(errors) > 0 {
    24  		return false, fmt.Errorf("invalid name for helm resource: %s, errors: %v", payload.Name, errors)
    25  	}
    26  	errors = validation.IsDNS1123Label(payload.Namespace)
    27  	if len(errors) > 0 {
    28  		return false, fmt.Errorf("invalid namespace for helm resource: %s, errors: %v", payload.Namespace, errors)
    29  	}
    30  
    31  	var (
    32  		cluster   *model.Cluster
    33  		projectID string
    34  		err       error
    35  	)
    36  	switch {
    37  	case !utils.IsNullOrEmpty(payload.ClusterEdgeID):
    38  		cluster, err = r.StoreClusterService.GetCluster(ctx, *payload.ClusterEdgeID)
    39  		if err != nil {
    40  			return false, err
    41  		}
    42  		projectID = cluster.ProjectID
    43  	case !utils.IsNullOrEmpty(payload.BannerEdgeID):
    44  		projectID, err = r.BannerService.GetBannerProjectID(ctx, *payload.BannerEdgeID)
    45  		if err != nil {
    46  			return false, fmt.Errorf("failed to get banner for workload: %w", err)
    47  		}
    48  	default:
    49  		return false, apierror.New("please provide bannerEdgeId or clusterEdgeId")
    50  	}
    51  
    52  	valid, err := r.HelmService.ValidateHelmConfigAgainstSchema(ctx, payload.ConfigValues, projectID, payload.HelmChart, payload.Version, payload.Secret)
    53  	if !valid {
    54  		return false, fmt.Errorf("error validating config value against schema: %s", err)
    55  	}
    56  
    57  	err = r.HelmService.CreateHelmReleaseSQL(ctx, payload, cluster)
    58  	if err != nil {
    59  		return false, err
    60  	}
    61  
    62  	return true, err
    63  }
    64  
    65  // DeleteHelmRelease is the resolver for the deleteHelmRelease field.
    66  func (r *mutationResolver) DeleteHelmRelease(ctx context.Context, helmEdgeID *string, name *string, clusterEdgeID *string) (bool, error) {
    67  	if !utils.IsNullOrEmpty(helmEdgeID) {
    68  		err := r.HelmService.SoftDeleteHelmReleaseSQL(ctx, helmEdgeID, name, clusterEdgeID)
    69  		if err != nil {
    70  			return false, err
    71  		}
    72  	} else {
    73  		hasClusterInfo := !utils.IsNullOrEmpty(name) && !utils.IsNullOrEmpty(clusterEdgeID)
    74  
    75  		if hasClusterInfo {
    76  			matchedWorkloads, err := r.HelmService.GetHelmWorkloadsByName(ctx, *clusterEdgeID, *name)
    77  
    78  			if err != nil || len(matchedWorkloads) == 0 {
    79  				return false, fmt.Errorf("there was an issue finding workload for deletion")
    80  			}
    81  
    82  			if len(matchedWorkloads) == 1 {
    83  				err := r.HelmService.SoftDeleteHelmReleaseSQL(ctx, &matchedWorkloads[0].HelmEdgeID, &matchedWorkloads[0].Name, &matchedWorkloads[0].ClusterEdgeID)
    84  				if err != nil {
    85  					return false, err
    86  				}
    87  			} else {
    88  				return false, fmt.Errorf("multiple matching workload(s) found, please use helmEdgeId instead")
    89  			}
    90  		} else {
    91  			return false, fmt.Errorf("please provide a helmEdgeId or clusterEdgeId and workload name")
    92  		}
    93  	}
    94  
    95  	return true, nil
    96  }
    97  
    98  // CreateOrUpdateBannerHelmRepository is the resolver for the createOrUpdateBannerHelmRepository field.
    99  func (r *mutationResolver) CreateOrUpdateBannerHelmRepository(ctx context.Context, name string, bannerEdgeID string, url string, secret *string) (bool, error) {
   100  	errors := validation.IsDNS1123Label(name)
   101  	if len(errors) > 0 {
   102  		return false, fmt.Errorf("invalid name for helm repository: %s, errors: %v", name, errors)
   103  	}
   104  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   105  	if err != nil {
   106  		return false, err
   107  	}
   108  	err = r.HelmService.CreateBannerHelmRepository(ctx, name, url, secret, projectID)
   109  	if err != nil {
   110  		return false, err
   111  	}
   112  	return true, nil
   113  }
   114  
   115  // CreateHelmRepository is the resolver for the createHelmRepository field.
   116  func (r *mutationResolver) CreateHelmRepository(ctx context.Context, name string, bannerEdgeID string, url string, username *string, password *string) (bool, error) {
   117  	if _, reserved := constants.PlatformHelmRepositories[name]; reserved {
   118  		return false, fmt.Errorf("the name %s is an edge reserved name. please use another", name)
   119  	}
   120  	errors := validation.IsDNS1123Label(name)
   121  	if len(errors) > 0 {
   122  		return false, fmt.Errorf("invalid name for helm repository: %s, errors: %v", name, errors)
   123  	}
   124  	if username != nil && password == nil {
   125  		return false, fmt.Errorf("password cannot be empty when username is provided")
   126  	}
   127  	if password != nil && username == nil {
   128  		return false, fmt.Errorf("username cannot be empty when password is provided")
   129  	}
   130  	if username == nil && password == nil {
   131  		username = new(string)
   132  		password = new(string)
   133  	}
   134  	index, err := r.HelmService.GetHelmRepositoryIndex(url, *username, *password)
   135  	if index == nil {
   136  		return false, fmt.Errorf("invalid helm repository, missing index.yaml")
   137  	}
   138  	if err != nil {
   139  		return false, fmt.Errorf("invalid helm repository, invalid index.yaml file")
   140  	}
   141  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   142  	if err != nil {
   143  		return false, err
   144  	}
   145  	defaultWorkload := string(constants.TenantNamespaceSelector)
   146  	_, err = r.CreateOrUpdateSecretManagerSecret(ctx, name, bannerEdgeID, constants.DefaultOwnerFilter, mapper.ToHelmRepositoryKeyValues(name, url, username, password), &defaultWorkload, constants.HelmRepositorySecretType)
   147  	if err != nil {
   148  		return false, err
   149  	}
   150  	externalSecrets, err := r.HelmService.GenerateHelmReleaseExternalSecrets(ctx, projectID, mapper.HelmReleaseNamespace, []string{name})
   151  	if err != nil {
   152  		return false, err
   153  	}
   154  	if err = r.HelmService.SendExternalSecretToChariot(ctx, projectID, "", externalSecrets); err != nil {
   155  		return false, err
   156  	}
   157  	err = r.HelmService.CreateBannerHelmRepository(ctx, name, url, &name, projectID)
   158  	if err != nil {
   159  		return false, err
   160  	}
   161  	return true, nil
   162  }
   163  
   164  // DeleteHelmRepository is the resolver for the deleteHelmRepository field.
   165  func (r *mutationResolver) DeleteHelmRepository(ctx context.Context, name string, bannerEdgeID string) (bool, error) {
   166  	if _, reserved := constants.PlatformHelmRepositories[name]; reserved {
   167  		return false, fmt.Errorf("the name %s is an edge reserved name. please use another", name)
   168  	}
   169  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   170  	if err != nil {
   171  		return false, err
   172  	}
   173  	err = r.HelmService.DeleteHelmRepo(ctx, name, projectID, bannerEdgeID)
   174  	if err != nil {
   175  		return false, err
   176  	}
   177  	return r.GCPService.DeleteSecret(ctx, name, projectID)
   178  }
   179  
   180  // DeleteBannerHelmRepository is the resolver for the deleteBannerHelmRepository field.
   181  func (r *mutationResolver) DeleteBannerHelmRepository(ctx context.Context, name string, bannerEdgeID string) (bool, error) {
   182  	return r.DeleteHelmRepository(ctx, name, bannerEdgeID)
   183  }
   184  
   185  // UpdateHelmRelease is the resolver for the updateHelmRelease field.
   186  func (r *mutationResolver) UpdateHelmRelease(ctx context.Context, helmEdgeID *string, helmReleaseName *string, clusterEdgeID *string, version *string, configValues *string, injectConfigmaps []model.InjectableConfigmaps, secrets []string, labelEdgeIds []string) (bool, error) {
   187  	var helmEdgeIDToUpdate string
   188  
   189  	switch {
   190  	case !utils.IsNullOrEmpty(helmEdgeID):
   191  		helmEdgeIDToUpdate = utils.CheckString(helmEdgeID)
   192  	case !utils.IsNullOrEmpty(helmReleaseName) && !utils.IsNullOrEmpty(clusterEdgeID):
   193  		matchedWorkloads, err := r.HelmService.GetHelmWorkloadsByName(ctx, *clusterEdgeID, *helmReleaseName)
   194  		if err != nil || len(matchedWorkloads) == 0 {
   195  			return false, fmt.Errorf("there was an issue finding workload for update")
   196  		}
   197  		if len(matchedWorkloads) == 1 {
   198  			helmEdgeIDToUpdate = utils.CheckString(&matchedWorkloads[0].HelmEdgeID)
   199  		} else {
   200  			return false, fmt.Errorf("multiple matching workload(s) found, please use helmEdgeId instead")
   201  		}
   202  	default:
   203  		return false, fmt.Errorf("please provide a helmEdgeId or helmReleaseName and clusterEdgeId")
   204  	}
   205  
   206  	helmWorkload, err := r.HelmService.GetHelmWorkloadSQL(ctx, helmEdgeIDToUpdate)
   207  	if err != nil {
   208  		return false, fmt.Errorf("failed to get helm workload: %s", err)
   209  	}
   210  	projectID, err := r.BannerService.GetBannerProjectID(ctx, helmWorkload.BannerEdgeID)
   211  	if err != nil {
   212  		return false, fmt.Errorf("failed to get banner project ID: %s", err)
   213  	}
   214  
   215  	// validate config value against repo validation schema for ncr-charts
   216  	newVersion := helmWorkload.HelmChartVersion
   217  	if version != nil {
   218  		newVersion = *version
   219  	}
   220  	newConfigValues := helmWorkload.ConfigValues
   221  	if configValues != nil {
   222  		newConfigValues = configValues
   223  	}
   224  	valid, err := r.HelmService.ValidateHelmConfigAgainstSchema(ctx, newConfigValues, projectID, helmWorkload.HelmChart, newVersion, helmWorkload.HelmRepoSecret)
   225  	if !valid {
   226  		return false, fmt.Errorf("error validating config value against schema: %s", err)
   227  	}
   228  
   229  	if secrets != nil {
   230  		// Validating array of secret names user input
   231  		for i := range secrets {
   232  			if secrets[i] == "" {
   233  				// If user passes in an empty list
   234  				// Cleanse all secrets currently existed
   235  				currentSecretsToDelete, err := r.HelmService.GetSecretsByHelmEdgeID(ctx, helmEdgeIDToUpdate)
   236  				if err != nil {
   237  					return false, err
   238  				}
   239  				if currentSecretsToDelete != nil {
   240  					_, errDeleteSecrets := r.HelmService.DeleteHelmSecrets(ctx, helmEdgeIDToUpdate, currentSecretsToDelete)
   241  					if errDeleteSecrets != nil {
   242  						return false, fmt.Errorf("failed to delete helm secrets")
   243  					}
   244  				}
   245  				err = r.HelmService.UpdateHelmReleaseSQL(ctx, helmEdgeIDToUpdate, newVersion, newConfigValues, injectConfigmaps)
   246  				if err != nil {
   247  					return false, err
   248  				}
   249  				return true, err
   250  			}
   251  			// If not empty, validate if secret exist on GCP
   252  			_, errSecrets := r.GCPService.GetSecrets(ctx, &secrets[i], nil, nil, false, projectID)
   253  			if errSecrets != nil {
   254  				return false, fmt.Errorf("invalid secrets")
   255  			}
   256  		}
   257  		// Get list of current secret
   258  		currentSecretsToDelete, err := r.HelmService.GetSecretsByHelmEdgeID(ctx, helmEdgeIDToUpdate)
   259  		if err != nil {
   260  			return false, err
   261  		}
   262  
   263  		// Delete list of current secret
   264  		if currentSecretsToDelete != nil {
   265  			_, errDeleteSecrets := r.HelmService.DeleteHelmSecrets(ctx, helmEdgeIDToUpdate, currentSecretsToDelete)
   266  			if errDeleteSecrets != nil {
   267  				return false, fmt.Errorf("Failed to delete helm secrets")
   268  			}
   269  			// Add list of new secret
   270  			_, errAddSecrets := r.HelmService.AddHelmSecrets(ctx, helmEdgeIDToUpdate, secrets)
   271  			if errAddSecrets != nil {
   272  				return false, fmt.Errorf("failed to add helm secrets")
   273  			}
   274  		}
   275  	}
   276  
   277  	// Update labels
   278  	if labelEdgeIds != nil {
   279  		_, errDelete := r.HelmService.DeleteWorkloadLabels(ctx, helmEdgeIDToUpdate)
   280  		if errDelete != nil {
   281  			return false, fmt.Errorf("failed to delete labels from workload")
   282  		}
   283  		if len(labelEdgeIds) > 0 {
   284  			_, errAdd := r.HelmService.AddWorkloadLabels(ctx, helmEdgeIDToUpdate, labelEdgeIds)
   285  			if errAdd != nil {
   286  				return false, fmt.Errorf("failed to add labels from workload: err: %w", errAdd)
   287  			}
   288  		}
   289  	}
   290  
   291  	// Update Helm Release on DB
   292  	err = r.HelmService.UpdateHelmReleaseSQL(ctx, helmEdgeIDToUpdate, newVersion, newConfigValues, injectConfigmaps)
   293  	if err != nil {
   294  		return false, err
   295  	}
   296  	return true, nil
   297  }
   298  
   299  // ValidateHelmConfig is the resolver for the validateHelmConfig field.
   300  func (r *mutationResolver) ValidateHelmConfig(ctx context.Context, payload model.ValidateHelmConfigParams) (bool, error) {
   301  	projectID, err := r.BannerService.GetBannerProjectID(ctx, payload.BannerEdgeID)
   302  	if err != nil {
   303  		return false, err
   304  	}
   305  	config, err := r.HelmService.GetDefaultConfigSchema(ctx, payload.ChartName, payload.SecretName, payload.ChartVersion, projectID)
   306  	if err != nil {
   307  		return false, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   308  	}
   309  	if config == nil {
   310  		return false, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   311  	}
   312  	if config.ConfigSchema == nil {
   313  		return false, apierror.New("No schema available for chart").AddGenericErrorExtension(apierror.DetailedHelmError, err)
   314  	}
   315  
   316  	return r.HelmService.ValidateHelmConfig(payload.HelmConfig, *config.ConfigSchema)
   317  }
   318  
   319  // AddWorkloadLabel is the resolver for the addWorkloadLabel field.
   320  func (r *mutationResolver) AddWorkloadLabel(ctx context.Context, workloadLabelParameters model.WorkloadLabelInput) (bool, error) {
   321  	return r.HelmService.AddWorkloadLabel(ctx, workloadLabelParameters.HelmEdgeID, workloadLabelParameters.LabelEdgeID)
   322  }
   323  
   324  // AddWorkloadLabels is the resolver for the addWorkloadLabels field.
   325  func (r *mutationResolver) AddWorkloadLabels(ctx context.Context, helmEdgeID string, labelEdgeIds []string) (bool, error) {
   326  	return r.HelmService.AddWorkloadLabels(ctx, helmEdgeID, labelEdgeIds)
   327  }
   328  
   329  // DeleteWorkloadLabel is the resolver for the deleteWorkloadLabel field.
   330  func (r *mutationResolver) DeleteWorkloadLabel(ctx context.Context, workloadLabelParameters model.WorkloadLabelInput) (bool, error) {
   331  	// Case 1: Delete this label from any workload currently using it if only labelID provided
   332  	if workloadLabelParameters.HelmEdgeID == "" && workloadLabelParameters.LabelEdgeID != "" {
   333  		_, errDeleteWithLabel := r.HelmService.DeleteWorkloadLabelByLabelEdgeID(ctx, workloadLabelParameters.LabelEdgeID)
   334  		if errDeleteWithLabel != nil {
   335  			return false, fmt.Errorf("failed to delete labels from workload with label id")
   336  		}
   337  		return true, nil
   338  	}
   339  
   340  	// Case 2: Delete all labels from this workload if only helm edge id provided
   341  	if workloadLabelParameters.HelmEdgeID != "" && workloadLabelParameters.LabelEdgeID == "" {
   342  		// Delete labels
   343  		_, errDeleteWithHelmID := r.HelmService.DeleteWorkloadLabels(ctx, workloadLabelParameters.HelmEdgeID)
   344  		if errDeleteWithHelmID != nil {
   345  			return false, fmt.Errorf("failed to delete labels from workload with helm id")
   346  		}
   347  
   348  		// Case 3: Delete label
   349  	} else {
   350  		_, errDelete := r.HelmService.DeleteWorkloadLabel(ctx, workloadLabelParameters.HelmEdgeID, workloadLabelParameters.LabelEdgeID)
   351  		if errDelete != nil {
   352  			return false, fmt.Errorf("failed to delete labels from workload")
   353  		}
   354  	}
   355  	return true, nil
   356  }
   357  
   358  // HelmChartVersion is the resolver for the helmChartVersion field.
   359  func (r *queryResolver) HelmChartVersion(ctx context.Context, name string, secretName string, bannerEdgeID string) (*model.HelmChartResponse, error) {
   360  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	chartVersion, err := r.HelmService.GetHelmChartVersion(ctx, name, secretName, projectID)
   365  	if err != nil {
   366  		return nil, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   367  	}
   368  	return chartVersion, nil
   369  }
   370  
   371  // DefaultSchemaConfig is the resolver for the defaultSchemaConfig field.
   372  func (r *queryResolver) DefaultSchemaConfig(ctx context.Context, params model.HelmConfigSchemaParams) (*model.HelmConfig, error) {
   373  	projectID, err := r.BannerService.GetBannerProjectID(ctx, params.BannerEdgeID)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  	config, err := r.HelmService.GetDefaultConfigSchema(ctx, params.ChartName, params.SecretName, params.ChartVersion, projectID)
   378  	if err != nil {
   379  		return nil, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   380  	}
   381  	return config, nil
   382  }
   383  
   384  // HelmReleases is the resolver for the helmReleases field.
   385  func (r *queryResolver) HelmReleases(ctx context.Context, clusterEdgeID string) ([]*model.HelmRelease, error) {
   386  	return nil, errors.New("helmReleases query is deprecated. use helmWorkloads instead")
   387  }
   388  
   389  // HelmReleasesStatus is the resolver for the helmReleasesStatus field.
   390  func (r *queryResolver) HelmReleasesStatus(ctx context.Context, clusterEdgeID string) ([]*model.HelmReleaseStatus, error) {
   391  	cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	return r.HelmService.GetHelmReleasesStatus(ctx, cluster)
   396  }
   397  
   398  // HelmWorkloads is the resolver for the helmWorkloads field.
   399  func (r *queryResolver) HelmWorkloads(ctx context.Context, clusterEdgeID *string, bannerEdgeID *string) ([]*model.HelmWorkload, error) {
   400  	return r.HelmService.GetHelmWorkloads(ctx, clusterEdgeID, bannerEdgeID, true)
   401  }
   402  
   403  // HelmWorkload is the resolver for the helmWorkload field.
   404  func (r *queryResolver) HelmWorkload(ctx context.Context, helmEdgeID string, clusterEdgeID string) (*model.HelmWorkload, error) {
   405  	return r.HelmService.GetHelmWorkload(ctx, helmEdgeID, clusterEdgeID)
   406  }
   407  
   408  // HelmCharts is the resolver for the helmCharts field.
   409  func (r *queryResolver) HelmCharts(ctx context.Context, secretName string, bannerEdgeID string) ([]*model.HelmChart, error) {
   410  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   411  	if err != nil {
   412  		return nil, err
   413  	}
   414  	charts, err := r.HelmService.GetHelmCharts(ctx, secretName, projectID)
   415  	if err != nil {
   416  		return nil, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   417  	}
   418  	return charts, err
   419  }
   420  
   421  // HelmRepositories is the resolver for the helmRepositories field.
   422  func (r *queryResolver) HelmRepositories(ctx context.Context, bannerEdgeID string) ([]*model.HelmRepository, error) {
   423  	defaultOwnerFilter := constants.DefaultOwnerFilter
   424  	helmRepoType := constants.HelmRepositorySecretType
   425  	projectID, err := r.BannerService.GetBannerProjectID(ctx, bannerEdgeID)
   426  	if err != nil {
   427  		return nil, err
   428  	}
   429  	helmRepoSecrets, err := r.GCPService.GetSecrets(ctx, nil, &defaultOwnerFilter, &helmRepoType, true, projectID)
   430  	if err != nil {
   431  		return nil, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   432  	}
   433  	return mapper.ToHelmRepositoriesModels(helmRepoSecrets), nil
   434  }
   435  
   436  // HelmRepositoryInfo is the resolver for the helmRepositoryInfo field.
   437  func (r *queryResolver) HelmRepositoryInfo(ctx context.Context, params model.HelmConfigSchemaParams) (*model.HelmRepositoryInfo, error) {
   438  	projectID, err := r.BannerService.GetBannerProjectID(ctx, params.BannerEdgeID)
   439  	if err != nil {
   440  		return nil, err
   441  	}
   442  	repoInfo, err := r.HelmService.GetHelmRepositoryInfo(ctx, params, projectID)
   443  	if err != nil {
   444  		return nil, apierror.New(apierror.HelmChartError).AddGenericErrorExtension(apierror.DetailedHelmError, err)
   445  	}
   446  	return repoInfo, nil
   447  }
   448  

View as plain text