github.com/jenkins-x/jx/v2@v2.1.155/pkg/cloud/aks/aks.go (about) 1 package aks 2 3 import ( 4 b64 "encoding/base64" 5 "encoding/json" 6 "strings" 7 8 "github.com/jenkins-x/jx-logging/pkg/log" 9 "github.com/jenkins-x/jx/v2/pkg/util" 10 ) 11 12 // AzureRunner an Azure CLI runner to interact with Azure 13 type AzureRunner struct { 14 Runner util.Commander 15 } 16 17 type aks struct { 18 ID string `json:"id"` 19 URI string `json:"uri"` 20 Group string `json:"group"` 21 Name string `json:"name"` 22 } 23 24 type acr struct { 25 ID string `json:"id"` 26 URI string `json:"uri"` 27 Group string `json:"group"` 28 Name string `json:"name"` 29 } 30 31 type password struct { 32 Name string `json:"name"` 33 Value string `json:"value"` 34 } 35 36 type credential struct { 37 Passwords []password `json:"passwords"` 38 Username string `json:"username"` 39 } 40 41 type auth struct { 42 Auth string `json:"auth,omitempty"` 43 } 44 45 type config struct { 46 Auths map[string]*auth `json:"auths,omitempty"` 47 } 48 49 // NewAzureRunnerWithCommander specific the command runner for Azure CLI. 50 func NewAzureRunnerWithCommander(runner util.Commander) *AzureRunner { 51 return &AzureRunner{ 52 Runner: runner, 53 } 54 } 55 56 // NewAzureRunner return a new AzureRunner 57 func NewAzureRunner() *AzureRunner { 58 runner := &util.Command{} 59 return NewAzureRunnerWithCommander(runner) 60 } 61 62 // GetClusterClient return AKS resource group, name and client ID. 63 func (az *AzureRunner) GetClusterClient(server string) (string, string, string, error) { 64 clientID := "" 65 group := "" 66 name := "" 67 68 clusterstr, err := az.azureCLI("aks", "list", "--query", "[].{uri:fqdn,id:servicePrincipalProfile.clientId,group:resourceGroup,name:name}") 69 if err != nil { 70 return group, name, clientID, err 71 } 72 73 clusters := []aks{} 74 err = json.Unmarshal([]byte(clusterstr), &clusters) 75 if err != nil { 76 return group, name, clientID, err 77 } 78 79 for _, v := range clusters { 80 if "https://"+v.URI+":443" == server { 81 clientID = v.ID 82 name = v.Name 83 group = v.Group 84 break 85 } 86 } 87 88 return group, name, clientID, err 89 } 90 91 // GetRegistry Return the docker registry config, registry login server and resource id, error 92 func (az *AzureRunner) GetRegistry(azureRegistrySubscription string, resourceGroup string, name string, registry string) (string, string, string, error) { 93 registryID := "" 94 loginServer := registry 95 dockerConfig := "" 96 97 if registry == "" { 98 loginServer = name + ".azurecr.io" 99 } 100 101 if !strings.HasSuffix(loginServer, "azurecr.io") { 102 return dockerConfig, loginServer, registryID, nil 103 } 104 105 acrRG, acrName, registryID, err := az.getRegistryID(azureRegistrySubscription, loginServer) 106 if err != nil { 107 return dockerConfig, loginServer, registryID, err 108 } 109 // not exist and create a new one in resourceGroup 110 if registryID == "" { 111 acrRG = resourceGroup 112 acrName = name 113 registryID, loginServer, err = az.createRegistry(azureRegistrySubscription, acrRG, acrName) 114 if err != nil { 115 return dockerConfig, loginServer, registryID, err 116 } 117 } 118 dockerConfig, err = az.getACRCredential(azureRegistrySubscription, acrRG, acrName) 119 return dockerConfig, loginServer, registryID, err 120 } 121 122 // AssignRole Assign the client a reader role for registry. 123 func (az *AzureRunner) AssignRole(client string, registry string) { 124 if client == "" || registry == "" { 125 return 126 } 127 az.azureCLI("role", "assignment", "create", "--assignee", client, "--role", "Reader", "--scope", registry) //nolint:errcheck 128 } 129 130 // getRegistryID returns acrRG, acrName, acrID, error 131 func (az *AzureRunner) getRegistryID(azureRegistrySubscription string, loginServer string) (string, string, string, error) { 132 acrRG := "" 133 acrName := "" 134 acrID := "" 135 136 acrListArgs := []string{ 137 "acr", 138 "list", 139 "--query", 140 "[].{uri:loginServer,id:id,name:name,group:resourceGroup}", 141 } 142 143 if azureRegistrySubscription != "" { 144 acrListArgs = append(acrListArgs, "--subscription", azureRegistrySubscription) 145 } 146 147 acrList, err := az.azureCLI(acrListArgs...) 148 149 if err != nil { 150 log.Logger().Infof("Registry %s is not exist", util.ColorInfo(loginServer)) 151 } else { 152 registries := []acr{} 153 err = json.Unmarshal([]byte(acrList), ®istries) 154 if err != nil { 155 return "", "", "", err 156 } 157 for _, v := range registries { 158 if v.URI == loginServer { 159 acrID = v.ID 160 acrRG = v.Group 161 acrName = v.Name 162 break 163 } 164 } 165 } 166 return acrRG, acrName, acrID, nil 167 } 168 169 // createRegistry return resource ID, login server and error 170 func (az *AzureRunner) createRegistry(azureRegistrySubscription string, resourceGroup string, name string) (string, string, error) { 171 acrCreateArgs := []string{ 172 "acr", 173 "create", 174 "-g", 175 resourceGroup, 176 "-n", 177 name, 178 "--sku", 179 "Standard", 180 "--admin-enabled", 181 "--query", 182 "id", 183 "-o", 184 "tsv", 185 } 186 187 if azureRegistrySubscription != "" { 188 acrCreateArgs = append(acrCreateArgs, "--subscription", azureRegistrySubscription) 189 } 190 191 registryID, err := az.azureCLI(acrCreateArgs...) 192 if err != nil { 193 log.Logger().Infof("Failed to create ACR %s in resource group %s", util.ColorInfo(name), util.ColorInfo(resourceGroup)) 194 return "", "", err 195 } 196 return registryID, formatLoginServer(name), nil 197 } 198 199 // getACRCredential return .dockerconfig value for the ACR 200 func (az *AzureRunner) getACRCredential(azureRegistrySubscription string, resourceGroup string, name string) (string, error) { 201 showCredArgs := []string{ 202 "acr", 203 "credential", 204 "show", 205 "-g", 206 resourceGroup, 207 "-n", 208 name, 209 } 210 211 if azureRegistrySubscription != "" { 212 showCredArgs = append(showCredArgs, "--subscription", azureRegistrySubscription) 213 } 214 215 credstr, err := az.azureCLI(showCredArgs...) 216 if err != nil { 217 log.Logger().Infof("Failed to get credential for ACR %s in resource group %s", util.ColorInfo(name), util.ColorInfo(resourceGroup)) 218 return "", err 219 } 220 cred := credential{} 221 err = json.Unmarshal([]byte(credstr), &cred) 222 if err != nil { 223 return "", err 224 } 225 newSecret := &auth{} 226 dockerConfig := &config{} 227 newSecret.Auth = b64.StdEncoding.EncodeToString([]byte(cred.Username + ":" + cred.Passwords[0].Value)) 228 if dockerConfig.Auths == nil { 229 dockerConfig.Auths = map[string]*auth{} 230 } 231 dockerConfig.Auths[formatLoginServer(name)] = newSecret 232 dockerConfigStr, err := json.Marshal(dockerConfig) 233 return string(dockerConfigStr), err 234 } 235 236 func formatLoginServer(name string) string { 237 return name + ".azurecr.io" 238 } 239 240 func (az *AzureRunner) azureCLI(args ...string) (string, error) { 241 az.Runner.SetName("az") 242 az.Runner.SetArgs(args) 243 return az.Runner.RunWithoutRetry() 244 }