1 package resolver
2
3
4
5
6
7 import (
8 "context"
9 "fmt"
10
11 "edge-infra.dev/pkg/edge/api/apierror"
12 "edge-infra.dev/pkg/edge/api/graph/mapper"
13 "edge-infra.dev/pkg/edge/api/graph/model"
14 "edge-infra.dev/pkg/edge/api/middleware"
15 "edge-infra.dev/pkg/edge/api/services"
16 "edge-infra.dev/pkg/edge/api/utils"
17 clusterApi "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1"
18 "edge-infra.dev/pkg/edge/bsl"
19 chariotClientApi "edge-infra.dev/pkg/edge/chariot/client"
20 "edge-infra.dev/pkg/edge/constants"
21 "edge-infra.dev/pkg/edge/constants/api/fleet"
22 "edge-infra.dev/pkg/edge/k8objectsutils"
23 "github.com/rs/zerolog/log"
24 corev1 "k8s.io/api/core/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 )
27
28
29 func (r *mutationResolver) DeleteCluster(ctx context.Context, clusterEdgeID string, deleteBSLSite *bool) (bool, error) {
30 errors := utils.NewErrorWrapper()
31 cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
32 if err != nil {
33 log.Ctx(ctx).Err(err).Msg("failed to get cluster")
34 return false, err
35 }
36 bannerToDelete, err := r.BannerService.GetBanner(ctx, cluster.BannerEdgeID)
37 if err != nil {
38 log.Ctx(ctx).Err(err).Msg("failed to get cluster")
39 return false, err
40 }
41
42
43
44 if err := r.UpdateClusterIENodesViaChariot(ctx, &cluster.ClusterEdgeID, chariotClientApi.Delete); err != nil {
45 errors.AddError(err, "error deleting terminal resources")
46 }
47
48
49 if err := r.DeleteClustersInfraAndGCPResources(ctx, cluster); err != nil {
50 log.Ctx(ctx).Err(err).Msg("error deleting cluster resources")
51 errors.AddError(err, "error deleting cluster resources")
52 }
53
54
55 storeNsBase64, err := utils.ConvertStructToBase64(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: clusterEdgeID}})
56 if err != nil {
57 return false, err
58 }
59 err = r.sendChariotMessage(ctx, r.Config.Bff.TopLevelProjectID, "foreman0", chariotClientApi.Delete, storeNsBase64)
60 if err != nil {
61 return false, err
62 }
63
64 err = r.StoreClusterService.SoftDeleteStoreEntry(ctx, clusterEdgeID)
65 if err != nil {
66 log.Ctx(ctx).Err(err).Msg("failed to soft delete store sql entry")
67 errors.AddError(err, "error soft deleting store sql entry")
68 }
69
70 clusterInfra, err := r.BannerService.GetClusterInfraInfo(ctx, cluster.BannerEdgeID)
71 if err != nil {
72 log.Ctx(ctx).Err(err).Msg("fail to get cluster infra info")
73 errors.AddError(err, "error getting cluster infra info")
74 } else {
75 banner := &model.Banner{}
76
77 clusterCR := clusterApi.NewCluster(cluster.Name, cluster.ProjectID, "", "", "", "", "", "", clusterEdgeID, 0, banner)
78 obj, err := k8objectsutils.ToBase64JSONString(clusterCR)
79 if err != nil {
80 log.Ctx(ctx).Err(err).Msg("fail to convert cluster object to base64 json string")
81 errors.AddError(err, "error converting cluster object to base64 json string")
82 } else {
83 chariotMessage := chariotClientApi.
84 NewChariotMessage().
85 SetOperation(chariotClientApi.Delete).
86 SetOwner(services.ComponentOwner).
87 SetBanner(clusterInfra.ProjectID).
88 SetCluster(clusterInfra.ClusterEdgeID).
89 AddObject(obj)
90 if err := r.ChariotService.InvokeChariotPubsub(ctx, chariotMessage, nil); err != nil {
91 log.Ctx(ctx).Err(err).Msg("chariot invocation failed")
92 errors.AddError(err, "error invoking chariot")
93 }
94 }
95 }
96
97 if deleteBSLSite != nil && *deleteBSLSite {
98 if cluster.BslSiteID != nil || *cluster.BslSiteID != "" {
99 inactiveStatus := services.InActiveStatus
100 _, errs := r.BSLSiteService.UpdateBSLSiteByID(ctx, bannerToDelete, *cluster.BslSiteID, model.Site{Status: &inactiveStatus})
101 if errs != nil {
102 log.Ctx(ctx).Err(errs).Msg("delete bsl site failed")
103 errors.AddError(errs, "error deleting site")
104 }
105 } else {
106 log.Ctx(ctx).Err(err).Msg("error deleting site, cluster has no associated bsl site")
107 errors.AddError(err, "error deleting site, cluster has no associated bsl site")
108 }
109 }
110
111 if errors.IsNotNil() {
112 return false, errors.GetErrors()
113 }
114 return true, nil
115 }
116
117
118 func (r *mutationResolver) UpdateSite(ctx context.Context, clusterEdgeID string, site model.Site) (*model.StoreSiteInfo, error) {
119 cluster, err := r.StoreClusterService.GetClusterByClusterEdgeID(ctx, clusterEdgeID)
120 if err != nil {
121 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("Error cluster by clusterEdgeID %s", clusterEdgeID))
122 return nil, err
123 }
124 bannerResponse, err := r.BannerService.GetBannerByEdgeID(ctx, cluster.BannerEdgeID)
125 if err != nil {
126 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("Error getting banner by bannerEdgeID %s", cluster.BannerEdgeID))
127 return nil, err
128 }
129 siteResponse, err := r.BSLSiteService.UpdateBSLSiteByID(ctx, bannerResponse, cluster.BSLSiteID, site)
130 if err != nil {
131 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("Error updating cluster bsl site by bsl_site_id %s", cluster.BSLSiteID))
132 return nil, err
133 }
134 return siteResponse, nil
135 }
136
137
138 func (r *mutationResolver) CreateClusterNetworkServices(ctx context.Context, clusterEdgeID string, networkServicesInfo []*model.CreateNetworkServiceInfo) ([]*model.ClusterNetworkServiceInfo, error) {
139 for _, service := range networkServicesInfo {
140 if _, ok := constants.ClusterNetworkServiceDefaults[service.ServiceType]; ok {
141 return nil, fmt.Errorf("cannot create %s already exists", service.ServiceType)
142 }
143 }
144
145 services, err := r.StoreClusterService.CreateClusterNetworkServices(ctx, clusterEdgeID, networkServicesInfo)
146 if err != nil {
147 return nil, err
148 }
149
150 if err := r.UpdateClusterIENodesViaChariot(ctx, &clusterEdgeID, chariotClientApi.Create); err != nil {
151 return services, err
152 }
153
154 return services, nil
155 }
156
157
158 func (r *mutationResolver) UpdateClusterNetworkServices(ctx context.Context, clusterEdgeID string, networkServicesInfo []*model.UpdateNetworkServiceInfo) ([]*model.ClusterNetworkServiceInfo, error) {
159 cluster, err := r.StoreClusterService.GetClusterByClusterEdgeID(ctx, clusterEdgeID)
160 if err != nil {
161 return nil, err
162 }
163 networkServices, err := r.StoreClusterService.GetClusterNetworkServices(ctx, clusterEdgeID)
164 if err != nil {
165 return nil, err
166 }
167 networkServiceByID := map[string]string{}
168 for _, service := range networkServices {
169 networkServiceByID[service.NetworkServiceID] = service.ServiceType
170 }
171
172 if err := utils.CheckNetworkServicesUpdatePermitted(cluster.Active, networkServicesInfo, networkServiceByID); err != nil {
173 return nil, err
174 }
175
176 services, err := r.StoreClusterService.UpdateClusterNetworkServices(ctx, clusterEdgeID, networkServicesInfo, networkServiceByID)
177 if err != nil {
178 return nil, err
179 }
180
181 if err := r.UpdateClusterIENodesViaChariot(ctx, &clusterEdgeID, chariotClientApi.Create); err != nil {
182 return services, err
183 }
184
185 return services, nil
186 }
187
188
189 func (r *mutationResolver) DeleteClusterNetworkService(ctx context.Context, clusterEdgeID string, networkServiceID string) (bool, error) {
190 deletedService, err := r.StoreClusterService.DeleteClusterNetworkService(ctx, clusterEdgeID, networkServiceID)
191 if err != nil {
192 return deletedService, err
193 }
194
195 if err := r.UpdateClusterIENodesViaChariot(ctx, &clusterEdgeID, chariotClientApi.Create); err != nil {
196 return deletedService, err
197 }
198
199 return deletedService, nil
200 }
201
202
203 func (r *mutationResolver) UpdateClusterName(ctx context.Context, clusterEdgeID string, name string) (*model.Cluster, error) {
204 err := r.StoreClusterService.UpdateStoreName(ctx, clusterEdgeID, name)
205 if err != nil {
206 return nil, err
207 }
208 cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
209 if err != nil {
210 return cluster, err
211 }
212
213 return cluster, nil
214 }
215
216
217 func (r *mutationResolver) CreateClusterConfig(ctx context.Context, clusterEdgeID string, createClusterConfig model.CreateClusterConfig) (*model.ClusterConfig, error) {
218 updateClusterCfg := model.UpdateClusterConfig(createClusterConfig)
219 return r.UpdateClusterConfig(ctx, clusterEdgeID, updateClusterCfg)
220 }
221
222
223 func (r *mutationResolver) UpdateClusterConfig(ctx context.Context, clusterEdgeID string, updateClusterConfig model.UpdateClusterConfig) (*model.ClusterConfig, error) {
224 clusterConfig, err := r.ClusterConfigService.UpdateClusterConfig(ctx, clusterEdgeID, &updateClusterConfig)
225 if err != nil {
226 return nil, err
227 }
228 clusterLabels, err := r.StoreClusterService.GetLabelsForCluster(ctx, clusterEdgeID)
229 if err != nil {
230 return nil, err
231 }
232 labelsMap := utils.ClusterLabelsTypeMap(clusterLabels)
233 _, gkeExists := labelsMap["gke"]
234 _, genericExists := labelsMap["generic"]
235
236 if !gkeExists && !genericExists {
237 if err := r.UpdateBootOptionsViaChariot(ctx, clusterEdgeID, clusterConfig, chariotClientApi.Create); err != nil {
238 return nil, err
239 }
240 if err := r.UpdateTopologyInfoCMViaChariot(ctx, clusterEdgeID, clusterConfig, chariotClientApi.Create); err != nil {
241 return nil, err
242 }
243 }
244 return clusterConfig, r.ActivationCodeService.SyncAllToStore(ctx, clusterEdgeID)
245 }
246
247
248 func (r *mutationResolver) DeleteClusters(ctx context.Context, clusterEdgeIds []string, deleteBSLSite *bool) (bool, error) {
249 deleteErr := apierror.New(apierror.DeleteClustersMessage)
250 for _, clusterEdgeID := range clusterEdgeIds {
251 message := []string{}
252 if val, ok := deleteErr.Ext[apierror.DeleteClustersKey]; ok {
253 message = val.([]string)
254 }
255 _, err := r.DeleteCluster(ctx, clusterEdgeID, deleteBSLSite)
256 if err != nil {
257 message = append(message, fmt.Sprintf("failed delete cluster, clusterEdgeId: %s, error: %s", clusterEdgeID, err.Error()))
258 }
259 deleteErr = deleteErr.AddGenericErrorExtension(apierror.DeleteClustersKey, message)
260 }
261 isDeleted := len(deleteErr.Ext[apierror.DeleteClustersKey].([]string)) == 0
262 if isDeleted {
263 return isDeleted, nil
264 }
265 return isDeleted, deleteErr
266 }
267
268
269 func (r *mutationResolver) AddSiteToStore(ctx context.Context, clusterEdgeID string, siteID *string) (*model.RegistrationResponse, error) {
270 var (
271 bslInfoForCluster = &bslHolder{siteInfo: &bsl.BSLInfo{}}
272 )
273
274 clusterInfo, bannerInfo, err := r.GetClusterAndBannerInfo(ctx, clusterEdgeID)
275 if err != nil {
276 return nil, err
277 }
278
279 createSite := utils.IsNullOrEmpty(siteID)
280 organization := bsl.GetOrgShortName(middleware.ForContext(ctx).Organization)
281 storeInfo := &model.StoreInfo{
282 SiteID: siteID,
283 CreateSite: &createSite,
284 BslOrganization: &organization,
285 }
286
287 bslInfoForCluster.siteInfo, _, err = r.BSLSiteService.GetOrCreateSite(ctx, storeInfo, bannerInfo, clusterInfo.ClusterName, clusterEdgeID)
288 if err != nil {
289 return nil, err
290 }
291
292
293 err = r.StoreClusterService.UpdateStoreSiteID(ctx, clusterEdgeID, bslInfoForCluster.siteInfo.ID)
294 if err != nil {
295 return nil, err
296 }
297
298 return &model.RegistrationResponse{
299 ClusterEdgeID: clusterEdgeID,
300 SiteID: &bslInfoForCluster.siteInfo.ID,
301 }, nil
302 }
303
304
305 func (r *mutationResolver) UpdateClusterFleetVersion(ctx context.Context, clusterEdgeID string, fleetVersion string) (*model.Cluster, error) {
306 var previousStoreVersion string
307 artifactVersions, err := r.ArtifactsService.GetClusterArtifactVersions(ctx, clusterEdgeID)
308 if err != nil {
309 return nil, err
310 }
311
312 for _, artifact := range artifactVersions {
313 if artifact.Name == fleet.Store {
314 previousStoreVersion = artifact.Version
315 }
316 }
317
318 if err := r.ArtifactsService.UpdateClusterFleetVersionAndArtifact(ctx, clusterEdgeID, fleetVersion); err != nil {
319 return nil, err
320 }
321
322 cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
323 if err != nil {
324 return nil, err
325 }
326
327 if err := r.UpdateClusterDefaultOptionalPallets(ctx, cluster, fleetVersion, previousStoreVersion); err != nil {
328 return nil, err
329 }
330
331 return cluster, nil
332 }
333
334
335 func (r *queryResolver) Clusters(ctx context.Context, bannerEdgeID string, labels []string) ([]*model.Cluster, error) {
336 return r.StoreClusterService.GetClusters(ctx, bannerEdgeID, labels)
337 }
338
339
340 func (r *queryResolver) Cluster(ctx context.Context, clusterEdgeID string) (*model.Cluster, error) {
341 return r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
342 }
343
344
345 func (r *queryResolver) StoreStatus(ctx context.Context, clusterEdgeID string) (*model.StoreStatusInfo, error) {
346 cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
347 if err != nil {
348 log.Ctx(ctx).Err(err).Msg("failed to get cluster")
349 return nil, err
350 }
351 response := mapper.ToStoreStatusModel(cluster.Name, cluster.BannerEdgeID, nil, nil)
352 active := cluster.Active != nil && *cluster.Active
353 if !active {
354 response.Status = &model.ClusterStatus{
355 Status: mapper.Provisioning,
356 Message: "status not found",
357 }
358 return response, nil
359 }
360
361 clusterStatus, err := r.StoreClusterService.GetClusterStatus(ctx, cluster)
362 if err != nil || clusterStatus == nil {
363 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("error in getting store status for cluster %s", cluster.Name))
364 response.Status = &model.ClusterStatus{
365 Status: mapper.Provisioning,
366 Message: "status not found",
367 }
368 return response, nil
369 }
370 response.Status = clusterStatus.Status
371 response.KubeVersion = clusterStatus.KubeVersion
372 response.BucketStatus = clusterStatus.BucketStatus
373 response.KustomizationStatus = clusterStatus.KustomizationStatus
374 return response, nil
375 }
376
377
378 func (r *queryResolver) Site(ctx context.Context, clusterEdgeID string) (*model.StoreSiteInfo, error) {
379 cluster, err := r.StoreClusterService.GetCluster(ctx, clusterEdgeID)
380 if err != nil {
381 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("Error cluster by clusterEdgeID %s", clusterEdgeID))
382 return nil, err
383 }
384
385
386 if utils.IsNullOrEmpty(cluster.BslSiteID) {
387 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("bsl_site_id data is missing in DB for clusterEdgeID %s", clusterEdgeID))
388 return nil, apierror.New("Site ID is missing and/or empty for this cluster")
389 }
390
391 bannerResponse, err := r.BannerService.GetBannerByEdgeID(ctx, cluster.BannerEdgeID)
392 if err != nil {
393 return nil, err
394 }
395
396 site, err := r.BSLSiteService.GetBSLSiteByID(ctx, *cluster.BslSiteID, bannerResponse)
397 if err != nil {
398 log.Ctx(ctx).Err(err).Msg(fmt.Sprintf("Error getting bsl site, id: %s", *cluster.BslSiteID))
399 return nil, err
400 }
401 return mapper.ToStoreSiteInfo(site), nil
402 }
403
404
405 func (r *queryResolver) ClusterConfig(ctx context.Context, clusterEdgeID string) (*model.ClusterConfig, error) {
406 clusterConfig, err := r.ClusterConfigService.GetClusterConfig(ctx, clusterEdgeID)
407 if err != nil {
408 return nil, err
409 }
410 return clusterConfig, nil
411 }
412
View as plain text