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