github.com/IBM-Cloud/bluemix-go@v0.0.0-20240314082800-4e02a69b84b2/api/container/containerv2/clusters.go (about) 1 package containerv2 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "net/url" 8 "os" 9 "path" 10 "path/filepath" 11 "strings" 12 13 "gopkg.in/yaml.v2" 14 15 "github.com/IBM-Cloud/bluemix-go/api/container/containerv1" 16 "github.com/IBM-Cloud/bluemix-go/client" 17 "github.com/IBM-Cloud/bluemix-go/helpers" 18 "github.com/IBM-Cloud/bluemix-go/trace" 19 ) 20 21 // ClusterCreateRequest ... 22 type ClusterCreateRequest struct { 23 DisablePublicServiceEndpoint bool `json:"disablePublicServiceEndpoint"` 24 KubeVersion string `json:"kubeVersion" description:"kubeversion of cluster"` 25 Billing string `json:"billing,omitempty"` 26 PodSubnet string `json:"podSubnet"` 27 Provider string `json:"provider"` 28 ServiceSubnet string `json:"serviceSubnet"` 29 Name string `json:"name" binding:"required" description:"The cluster's name"` 30 DefaultWorkerPoolEntitlement string `json:"defaultWorkerPoolEntitlement"` 31 CosInstanceCRN string `json:"cosInstanceCRN"` 32 WorkerPools WorkerPoolConfig `json:"workerPool"` 33 SecurityGroupIDs []string `json:"securityGroupIDs,omitempty"` 34 } 35 36 type WorkerPoolConfig struct { 37 HostPoolID string `json:"hostPoolID,omitempty"` 38 CommonWorkerPoolConfig 39 } 40 41 type WorkerVolumeEncryption struct { 42 KmsInstanceID string `json:"kmsInstanceID,omitempty"` 43 WorkerVolumeCRKID string `json:"workerVolumeCRKID,omitempty"` 44 KMSAccountID string `json:"kmsAccountID,omitempty"` 45 } 46 47 // type Label struct { 48 // AdditionalProp1 string `json:"additionalProp1,omitempty"` 49 // AdditionalProp2 string `json:"additionalProp2,omitempty"` 50 // AdditionalProp3 string `json:"additionalProp3,omitempty"` 51 // } 52 53 type Zone struct { 54 ID string `json:"id,omitempty" description:"The id"` 55 SubnetID string `json:"subnetID,omitempty"` 56 } 57 58 // ClusterInfo ... 59 type ClusterInfo struct { 60 CreatedDate string `json:"createdDate"` 61 DataCenter string `json:"dataCenter"` 62 ID string `json:"id"` 63 Location string `json:"location"` 64 Entitlement string `json:"entitlement"` 65 MasterKubeVersion string `json:"masterKubeVersion"` 66 Name string `json:"name"` 67 Region string `json:"region"` 68 ResourceGroupID string `json:"resourceGroup"` 69 State string `json:"state"` 70 IsPaid bool `json:"isPaid"` 71 Addons []Addon `json:"addons"` 72 OwnerEmail string `json:"ownerEmail"` 73 Type string `json:"type"` 74 TargetVersion string `json:"targetVersion"` 75 ServiceSubnet string `json:"serviceSubnet"` 76 ResourceGroupName string `json:"resourceGroupName"` 77 Provider string `json:"provider"` 78 PodSubnet string `json:"podSubnet"` 79 MultiAzCapable bool `json:"multiAzCapable"` 80 APIUser string `json:"apiUser"` 81 ServerURL string `json:"serverURL"` 82 MasterURL string `json:"masterURL"` 83 MasterStatus string `json:"masterStatus"` 84 DisableAutoUpdate bool `json:"disableAutoUpdate"` 85 WorkerZones []string `json:"workerZones"` 86 Vpcs []string `json:"vpcs"` 87 CRN string `json:"crn"` 88 VersionEOS string `json:"versionEOS"` 89 ServiceEndpoints Endpoints `json:"serviceEndpoints"` 90 PrivateServiceEndpointEnabled bool `json:"privateServiceEndpointEnabled"` 91 PrivateServiceEndpointURL string `json:"privateServiceEndpointURL"` 92 PublicServiceEndpointEnabled bool `json:"publicServiceEndpointEnabled"` 93 PublicServiceEndpointURL string `json:"publicServiceEndpointURL"` 94 Lifecycle LifeCycleInfo `json:"lifecycle"` 95 WorkerCount int `json:"workerCount"` 96 Ingress IngresInfo `json:"ingress"` 97 Features Feat `json:"features"` 98 ImageSecurityEnabled bool `json:"imageSecurityEnabled"` 99 VirtualPrivateEndpointURL string `json:"virtualPrivateEndpointURL"` 100 } 101 type Feat struct { 102 KeyProtectEnabled bool `json:"keyProtectEnabled"` 103 PullSecretApplied bool `json:"pullSecretApplied"` 104 } 105 type IngresInfo struct { 106 HostName string `json:"hostname"` 107 SecretName string `json:"secretName"` 108 } 109 type LifeCycleInfo struct { 110 ModifiedDate string `json:"modifiedDate"` 111 MasterStatus string `json:"masterStatus"` 112 MasterStatusModifiedDate string `json:"masterStatusModifiedDate"` 113 MasterHealth string `json:"masterHealth"` 114 MasterState string `json:"masterState"` 115 } 116 117 // ClusterTargetHeader ... 118 type ClusterTargetHeader struct { 119 AccountID string 120 ResourceGroup string 121 Provider string // supported providers e.g vpc-classic , vpc-gen2, satellite 122 } 123 type Endpoints struct { 124 PrivateServiceEndpointEnabled bool `json:"privateServiceEndpointEnabled"` 125 PrivateServiceEndpointURL string `json:"privateServiceEndpointURL"` 126 PublicServiceEndpointEnabled bool `json:"publicServiceEndpointEnabled"` 127 PublicServiceEndpointURL string `json:"publicServiceEndpointURL"` 128 } 129 130 type Addon struct { 131 Name string `json:"name"` 132 Version string `json:"version"` 133 } 134 135 // ClusterCreateResponse ... 136 type ClusterCreateResponse struct { 137 ID string `json:"clusterID"` 138 } 139 140 // Clusters interface 141 type Clusters interface { 142 Create(params ClusterCreateRequest, target ClusterTargetHeader) (ClusterCreateResponse, error) 143 List(target ClusterTargetHeader) ([]ClusterInfo, error) 144 Delete(name string, target ClusterTargetHeader, deleteDependencies ...bool) error 145 GetCluster(name string, target ClusterTargetHeader) (*ClusterInfo, error) 146 GetClusterConfigDetail(name, homeDir string, admin bool, target ClusterTargetHeader, endpointType string) (containerv1.ClusterKeyInfo, error) 147 StoreConfigDetail(name, baseDir string, admin bool, createCalicoConfig bool, target ClusterTargetHeader, endpointType string) (string, containerv1.ClusterKeyInfo, error) 148 EnableImageSecurityEnforcement(name string, target ClusterTargetHeader) error 149 DisableImageSecurityEnforcement(name string, target ClusterTargetHeader) error 150 //TODO Add other opertaions 151 } 152 type clusters struct { 153 client *client.Client 154 pathPrefix string 155 } 156 157 const ( 158 accountIDHeader = "X-Auth-Resource-Account" 159 resourceGroupHeader = "X-Auth-Resource-Group" 160 ) 161 162 // ToMap ... 163 func (c ClusterTargetHeader) ToMap() map[string]string { 164 m := make(map[string]string, 3) 165 m[accountIDHeader] = c.AccountID 166 m[resourceGroupHeader] = c.ResourceGroup 167 return m 168 } 169 170 func newClusterAPI(c *client.Client) Clusters { 171 return &clusters{ 172 client: c, 173 //pathPrefix: "/v2/vpc/", 174 } 175 } 176 177 // List ... 178 func (r *clusters) List(target ClusterTargetHeader) ([]ClusterInfo, error) { 179 clusters := []ClusterInfo{} 180 var err error 181 if target.Provider != "satellite" { 182 getClustersPath := "/v2/vpc/getClusters" 183 if len(target.Provider) > 0 { 184 getClustersPath = fmt.Sprintf(getClustersPath+"?provider=%s", url.QueryEscape(target.Provider)) 185 } 186 _, err := r.client.Get(getClustersPath, &clusters, target.ToMap()) 187 if err != nil { 188 return nil, err 189 } 190 } 191 if len(target.Provider) == 0 || target.Provider == "satellite" { 192 // get satellite clusters 193 satelliteClusters := []ClusterInfo{} 194 _, err = r.client.Get("/v2/satellite/getClusters", &satelliteClusters, target.ToMap()) 195 if err != nil && target.Provider == "satellite" { 196 // return error only when provider is satellite. Else ignore error and return VPC clusters 197 trace.Logger.Println("Unable to get the satellite clusters ", err) 198 return nil, err 199 } 200 clusters = append(clusters, satelliteClusters...) 201 } 202 return clusters, nil 203 } 204 205 // Create ... 206 func (r *clusters) Create(params ClusterCreateRequest, target ClusterTargetHeader) (ClusterCreateResponse, error) { 207 var cluster ClusterCreateResponse 208 _, err := r.client.Post("/v2/vpc/createCluster", params, &cluster, target.ToMap()) 209 return cluster, err 210 } 211 212 // Delete ... 213 func (r *clusters) Delete(name string, target ClusterTargetHeader, deleteDependencies ...bool) error { 214 var rawURL string 215 if len(deleteDependencies) != 0 { 216 rawURL = fmt.Sprintf("/v1/clusters/%s?deleteResources=%t", name, deleteDependencies[0]) 217 } else { 218 rawURL = fmt.Sprintf("/v1/clusters/%s", name) 219 } 220 _, err := r.client.Delete(rawURL, target.ToMap()) 221 return err 222 } 223 224 // GetClusterByIDorName 225 func (r *clusters) GetCluster(name string, target ClusterTargetHeader) (*ClusterInfo, error) { 226 ClusterInfo := &ClusterInfo{} 227 rawURL := fmt.Sprintf("/v2/getCluster?cluster=%s&v1-compatible", name) 228 _, err := r.client.Get(rawURL, &ClusterInfo, target.ToMap()) 229 if err != nil { 230 return nil, err 231 } 232 233 return ClusterInfo, err 234 } 235 func (r *ClusterInfo) IsStagingSatelliteCluster() bool { 236 return strings.Index(r.ServerURL, "stg") > 0 && r.Provider == "satellite" 237 } 238 239 // FindWithOutShowResourcesCompatible ... 240 func (r *clusters) FindWithOutShowResourcesCompatible(name string, target ClusterTargetHeader) (ClusterInfo, error) { 241 rawURL := fmt.Sprintf("/v2/getCluster?v1-compatible&cluster=%s", name) 242 cluster := ClusterInfo{} 243 _, err := r.client.Get(rawURL, &cluster, target.ToMap()) 244 if err != nil { 245 return cluster, err 246 } 247 // Handle VPC cluster. ServerURL is blank for v2/vpc clusters 248 if cluster.ServerURL == "" { 249 cluster.ServerURL = cluster.MasterURL 250 } 251 252 // Workaround for ServiceEndpoints: armada-api returns different structure for different providers (classic vs VPC) 253 if !cluster.ServiceEndpoints.PrivateServiceEndpointEnabled && cluster.PrivateServiceEndpointEnabled { 254 cluster.ServiceEndpoints.PrivateServiceEndpointEnabled = cluster.PrivateServiceEndpointEnabled 255 } 256 if cluster.ServiceEndpoints.PrivateServiceEndpointURL == "" && cluster.PrivateServiceEndpointURL != "" { 257 cluster.ServiceEndpoints.PrivateServiceEndpointURL = cluster.PrivateServiceEndpointURL 258 } 259 if !cluster.ServiceEndpoints.PublicServiceEndpointEnabled && cluster.PublicServiceEndpointEnabled { 260 cluster.ServiceEndpoints.PublicServiceEndpointEnabled = cluster.PublicServiceEndpointEnabled 261 } 262 if cluster.ServiceEndpoints.PublicServiceEndpointURL == "" && cluster.PublicServiceEndpointURL != "" { 263 cluster.ServiceEndpoints.PublicServiceEndpointURL = cluster.PublicServiceEndpointURL 264 } 265 266 return cluster, err 267 } 268 269 // GetClusterConfigDetail ... 270 func (r *clusters) GetClusterConfigDetail(name, dir string, admin bool, target ClusterTargetHeader, endpointType string) (containerv1.ClusterKeyInfo, error) { 271 clusterkey := containerv1.ClusterKeyInfo{} 272 // Block to add token for openshift clusters (This can be temporary until iks team handles openshift clusters) 273 clusterInfo, err := r.FindWithOutShowResourcesCompatible(name, target) 274 if err != nil { 275 // Assuming an error means that this is a vpc cluster, and we're returning existing kubeconfig 276 // When we add support for vpcs on openshift clusters, we may want revisit this 277 return clusterkey, err 278 } 279 280 if !helpers.FileExists(dir) { 281 return clusterkey, fmt.Errorf("Path: %q, to download the config doesn't exist", dir) 282 } 283 postBody := map[string]interface{}{ 284 "cluster": name, 285 "format": "zip", 286 } 287 rawURL := fmt.Sprintf("/v2/applyRBACAndGetKubeconfig") 288 if admin { 289 postBody["admin"] = true 290 } 291 if clusterInfo.Provider == "satellite" { 292 postBody["endpointType"] = "link" 293 postBody["admin"] = true 294 } else if endpointType != "" { 295 postBody["endpointType"] = endpointType 296 } 297 resultDir := containerv1.ComputeClusterConfigDir(dir, name, admin) 298 const kubeConfigName = "config.yml" 299 err = os.MkdirAll(resultDir, 0755) 300 if err != nil { 301 return clusterkey, fmt.Errorf("Error creating directory to download the cluster config") 302 } 303 downloadPath := filepath.Join(resultDir, "config.zip") 304 trace.Logger.Println("Will download the kubeconfig at", downloadPath) 305 306 var out *os.File 307 if out, err = os.Create(downloadPath); err != nil { 308 return clusterkey, err 309 } 310 defer out.Close() 311 defer helpers.RemoveFile(downloadPath) 312 _, err = r.client.Post(rawURL, postBody, out, target.ToMap()) 313 if err != nil { 314 return clusterkey, err 315 } 316 trace.Logger.Println("Downloaded the kubeconfig at", downloadPath) 317 if err = helpers.Unzip(downloadPath, resultDir); err != nil { 318 return clusterkey, err 319 } 320 defer helpers.RemoveFilesWithPattern(resultDir, "[^(.yml)|(.pem)]$") 321 var kubeyml string 322 files, _ := ioutil.ReadDir(resultDir) 323 324 for _, f := range files { 325 if !strings.HasSuffix(f.Name(), ".zip") { 326 fileContent, _ := ioutil.ReadFile(resultDir + "/" + f.Name()) 327 if f.Name() == "admin-key.pem" { 328 clusterkey.AdminKey = string(fileContent) 329 } 330 if f.Name() == "admin.pem" { 331 clusterkey.Admin = string(fileContent) 332 } 333 if strings.HasPrefix(f.Name(), "ca") && strings.HasSuffix(f.Name(), ".pem") { 334 clusterkey.ClusterCACertificate = string(fileContent) 335 } 336 old := filepath.Join(resultDir, f.Name()) 337 new := filepath.Join(resultDir, f.Name()) 338 if strings.HasSuffix(f.Name(), ".yaml") { 339 new = filepath.Join(path.Clean(resultDir), "/", path.Clean(kubeConfigName)) 340 kubeyml = new 341 } 342 err := os.Rename(old, new) 343 if err != nil { 344 return clusterkey, fmt.Errorf("Couldn't rename: %q", err) 345 } 346 } 347 } 348 if resultDir == "" { 349 return clusterkey, errors.New("Unable to locate kube config in zip archive") 350 } 351 352 kubefile, _ := ioutil.ReadFile(kubeyml) 353 var yamlConfig containerv1.ConfigFile 354 err = yaml.Unmarshal(kubefile, &yamlConfig) 355 if err != nil { 356 fmt.Printf("Error parsing YAML file: %s\n", err) 357 } 358 if len(yamlConfig.Clusters) != 0 { 359 clusterkey.Host = yamlConfig.Clusters[0].Cluster.Server 360 } 361 if len(yamlConfig.Users) != 0 { 362 clusterkey.Token = yamlConfig.Users[0].User.AuthProvider.Config.IDToken 363 } 364 365 // Block to add token for openshift clusters (This can be temporary until iks team handles openshift clusters) 366 clusterInfo, err = r.FindWithOutShowResourcesCompatible(name, target) 367 if err != nil { 368 // Assuming an error means that this is a vpc cluster, and we're returning existing kubeconfig 369 // When we add support for vpcs on openshift clusters, we may want revisit this 370 clusterkey.FilePath, _ = filepath.Abs(kubeyml) 371 return clusterkey, err 372 } 373 if clusterInfo.Type == "openshift" && clusterInfo.Provider != "satellite" { 374 trace.Logger.Println("Debug: type is openshift trying login to get token") 375 var yamlConfig []byte 376 if yamlConfig, err = ioutil.ReadFile(kubeyml); err != nil { 377 return clusterkey, err 378 } 379 yamlConfig, clusterkey.Host, err = r.FetchOCTokenForKubeConfig(yamlConfig, &clusterInfo, clusterInfo.IsStagingSatelliteCluster(), endpointType) 380 if err != nil { 381 return clusterkey, err 382 } 383 err = ioutil.WriteFile(kubeyml, yamlConfig, 0644) // 0644 is irrelevant here, since file already exists. 384 if err != nil { 385 return clusterkey, err 386 } 387 openshiftyml, _ := ioutil.ReadFile(kubeyml) 388 var openshiftyaml containerv1.ConfigFileOpenshift 389 err = yaml.Unmarshal(openshiftyml, &openshiftyaml) 390 if err != nil { 391 fmt.Printf("Error parsing YAML file: %s\n", err) 392 } 393 openshiftusers := openshiftyaml.Users 394 for _, usr := range openshiftusers { 395 if strings.HasPrefix(usr.Name, "IAM") { 396 clusterkey.Token = usr.User.Token 397 } 398 } 399 clusterkey.ClusterCACertificate = "" 400 401 } 402 clusterkey.FilePath, _ = filepath.Abs(kubeyml) 403 return clusterkey, err 404 } 405 406 // StoreConfigDetail ... 407 func (r *clusters) StoreConfigDetail(name, dir string, admin, createCalicoConfig bool, target ClusterTargetHeader, endpointType string) (string, containerv1.ClusterKeyInfo, error) { 408 clusterkey := containerv1.ClusterKeyInfo{} 409 clusterInfo, err := r.FindWithOutShowResourcesCompatible(name, target) 410 if err != nil { 411 return "", clusterkey, err 412 } 413 postBody := map[string]interface{}{ 414 "cluster": name, 415 "format": "zip", 416 } 417 418 var calicoConfig string 419 if !helpers.FileExists(dir) { 420 return "", clusterkey, fmt.Errorf("Path: %q, to download the config doesn't exist", dir) 421 } 422 rawURL := fmt.Sprintf("/v2/applyRBACAndGetKubeconfig") 423 if admin { 424 postBody["admin"] = true 425 } 426 if clusterInfo.Provider == "satellite" { 427 postBody["endpointType"] = "link" 428 postBody["admin"] = true 429 } else if endpointType != "" { 430 postBody["endpointType"] = endpointType 431 } 432 if createCalicoConfig { 433 postBody["network"] = true 434 } 435 resultDir := containerv1.ComputeClusterConfigDir(dir, name, admin) 436 err = os.MkdirAll(resultDir, 0755) 437 if err != nil { 438 return "", clusterkey, fmt.Errorf("Error creating directory to download the cluster config") 439 } 440 downloadPath := filepath.Join(resultDir, "config.zip") 441 trace.Logger.Println("Will download the kubeconfig at", downloadPath) 442 443 var out *os.File 444 if out, err = os.Create(downloadPath); err != nil { 445 return "", clusterkey, err 446 } 447 defer out.Close() 448 defer helpers.RemoveFile(downloadPath) 449 _, err = r.client.Post(rawURL, postBody, out, target.ToMap()) 450 if err != nil { 451 return "", clusterkey, err 452 } 453 trace.Logger.Println("Downloaded the kubeconfig at", downloadPath) 454 if err = helpers.Unzip(downloadPath, resultDir); err != nil { 455 return "", clusterkey, err 456 } 457 trace.Logger.Println("Downloaded the kubec", resultDir) 458 459 unzipConfigPath := resultDir 460 trace.Logger.Println("Located unzipped directory: ", unzipConfigPath) 461 files, _ := ioutil.ReadDir(unzipConfigPath) 462 for _, f := range files { 463 if !strings.HasSuffix(f.Name(), ".zip") { 464 fileContent, _ := ioutil.ReadFile(unzipConfigPath + "/" + f.Name()) 465 if f.Name() == "admin-key.pem" { 466 clusterkey.AdminKey = string(fileContent) 467 } 468 if f.Name() == "admin.pem" { 469 clusterkey.Admin = string(fileContent) 470 } 471 if strings.HasPrefix(f.Name(), "ca") && strings.HasSuffix(f.Name(), ".pem") { 472 clusterkey.ClusterCACertificate = string(fileContent) 473 } 474 old := filepath.Join(unzipConfigPath, f.Name()) 475 new := filepath.Join(unzipConfigPath, f.Name()) 476 err := os.Rename(old, new) 477 if err != nil { 478 return "", clusterkey, fmt.Errorf("Couldn't rename: %q", err) 479 } 480 } 481 } 482 baseDirFiles, err := ioutil.ReadDir(resultDir) 483 if err != nil { 484 return "", clusterkey, err 485 } 486 487 if createCalicoConfig { 488 // Proccess calico golang template file if it exists 489 calicoConfig, err = containerv1.GenerateCalicoConfig(resultDir) 490 if err != nil { 491 return "", clusterkey, err 492 } 493 } 494 var kubeconfigFileName string 495 for _, baseDirFile := range baseDirFiles { 496 if strings.Contains(baseDirFile.Name(), ".yaml") { 497 kubeconfigFileName = fmt.Sprintf("%s/%s", resultDir, baseDirFile.Name()) 498 break 499 } 500 } 501 if kubeconfigFileName == "" { 502 return "", clusterkey, errors.New("Unable to locate kube config in zip archive") 503 } 504 kubefile, _ := ioutil.ReadFile(kubeconfigFileName) 505 var yamlConfig containerv1.ConfigFile 506 err = yaml.Unmarshal(kubefile, &yamlConfig) 507 if err != nil { 508 fmt.Printf("Error parsing YAML file: %s\n", err) 509 } 510 if len(yamlConfig.Clusters) != 0 { 511 clusterkey.Host = yamlConfig.Clusters[0].Cluster.Server 512 } 513 if len(yamlConfig.Users) != 0 { 514 clusterkey.Token = yamlConfig.Users[0].User.AuthProvider.Config.IDToken 515 } 516 517 // Block to add token for openshift clusters (This can be temporary until iks team handles openshift clusters) 518 clusterInfo, err = r.FindWithOutShowResourcesCompatible(name, target) 519 if err != nil { 520 // Assuming an error means that this is a vpc cluster, and we're returning existing kubeconfig 521 // When we add support for vpcs on openshift clusters, we may want revisit this 522 clusterkey.FilePath = kubeconfigFileName 523 return calicoConfig, clusterkey, nil 524 } 525 526 if clusterInfo.Type == "openshift" && clusterInfo.Provider != "satellite" { 527 trace.Logger.Println("Cluster Type is openshift trying login to get token") 528 var yamlConfig []byte 529 if yamlConfig, err = ioutil.ReadFile(kubeconfigFileName); err != nil { 530 return "", clusterkey, err 531 } 532 yamlConfig, clusterkey.Host, err = r.FetchOCTokenForKubeConfig(yamlConfig, &clusterInfo, clusterInfo.IsStagingSatelliteCluster(), endpointType) 533 if err != nil { 534 return "", clusterkey, err 535 } 536 err = ioutil.WriteFile(kubeconfigFileName, yamlConfig, 0644) // check about permissions and truncate 537 if err != nil { 538 return "", clusterkey, err 539 } 540 openshiftyml, _ := ioutil.ReadFile(kubeconfigFileName) 541 var openshiftyaml containerv1.ConfigFileOpenshift 542 err = yaml.Unmarshal(openshiftyml, &openshiftyaml) 543 if err != nil { 544 fmt.Printf("Error parsing YAML file: %s\n", err) 545 } 546 openshiftusers := openshiftyaml.Users 547 for _, usr := range openshiftusers { 548 if strings.HasPrefix(usr.Name, "IAM") { 549 clusterkey.Token = usr.User.Token 550 } 551 } 552 clusterkey.ClusterCACertificate = "" 553 554 } 555 clusterkey.FilePath = kubeconfigFileName 556 return calicoConfig, clusterkey, nil 557 } 558 559 func (r *clusters) EnableImageSecurityEnforcement(name string, target ClusterTargetHeader) error { 560 rawURL := "/v2/enableImageSecurity" 561 body := map[string]string{"cluster": name} 562 _, err := r.client.Post(rawURL, body, nil, target.ToMap()) 563 return err 564 } 565 566 func (r *clusters) DisableImageSecurityEnforcement(name string, target ClusterTargetHeader) error { 567 rawURL := "/v2/disableImageSecurity" 568 body := map[string]string{"cluster": name} 569 _, err := r.client.Post(rawURL, body, nil, target.ToMap()) 570 return err 571 }