github.com/GoogleCloudPlatform/terraformer@v0.8.18/providers/ibm/utils.go (about) 1 // Copyright 2019 The Terraformer Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ibm 16 17 import ( 18 "fmt" 19 gohttp "net/http" 20 "net/url" 21 "os" 22 "reflect" 23 "strconv" 24 "strings" 25 26 bluemix "github.com/IBM-Cloud/bluemix-go" 27 "github.com/IBM-Cloud/bluemix-go/authentication" 28 "github.com/IBM-Cloud/bluemix-go/http" 29 "github.com/IBM-Cloud/bluemix-go/rest" 30 "github.com/IBM-Cloud/bluemix-go/session" 31 "github.com/dgrijalva/jwt-go" 32 33 "github.com/IBM-Cloud/bluemix-go/api/resource/resourcev2/managementv2" 34 ) 35 36 // UserConfig ... 37 type UserConfig struct { 38 userID string 39 userEmail string 40 userAccount string 41 cloudName string `default:"bluemix"` 42 cloudType string `default:"public"` 43 generation int `default:"2"` 44 } 45 46 // EnvFallBack ... 47 func envFallBack(envs []string, defaultValue string) string { 48 for _, k := range envs { 49 if v := os.Getenv(k); v != "" { 50 return v 51 } 52 } 53 return defaultValue 54 } 55 56 func fetchUserDetails(sess *session.Session, generation int) (*UserConfig, error) { 57 config := sess.Config 58 user := UserConfig{} 59 var bluemixToken string 60 61 if strings.HasPrefix(config.IAMAccessToken, "Bearer") { 62 bluemixToken = config.IAMAccessToken[7:len(config.IAMAccessToken)] 63 } else { 64 bluemixToken = config.IAMAccessToken 65 } 66 67 token, err := jwt.Parse(bluemixToken, func(token *jwt.Token) (interface{}, error) { 68 return "", nil 69 }) 70 // TODO validate with key 71 if err != nil && !strings.Contains(err.Error(), "key is of invalid type") { 72 return &user, err 73 } 74 claims := token.Claims.(jwt.MapClaims) 75 if email, ok := claims["email"]; ok { 76 user.userEmail = email.(string) 77 } 78 user.userID = claims["id"].(string) 79 user.userAccount = claims["account"].(map[string]interface{})["bss"].(string) 80 iss := claims["iss"].(string) 81 if strings.Contains(iss, "https://iam.cloud.ibm.com") { 82 user.cloudName = "bluemix" 83 } else { 84 user.cloudName = "staging" 85 } 86 user.cloudType = "public" 87 88 user.generation = generation 89 return &user, nil 90 } 91 92 func authenticateAPIKey(sess *session.Session) error { 93 config := sess.Config 94 tokenRefresher, err := authentication.NewIAMAuthRepository(config, &rest.Client{ 95 DefaultHeader: gohttp.Header{ 96 "User-Agent": []string{http.UserAgent()}, 97 }, 98 }) 99 if err != nil { 100 return err 101 } 102 return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) 103 } 104 105 func authenticateCF(sess *session.Session) error { 106 config := sess.Config 107 tokenRefresher, err := authentication.NewUAARepository(config, &rest.Client{ 108 DefaultHeader: gohttp.Header{ 109 "User-Agent": []string{http.UserAgent()}, 110 }, 111 }) 112 if err != nil { 113 return err 114 } 115 return tokenRefresher.AuthenticateAPIKey(config.BluemixAPIKey) 116 } 117 118 func GetNext(next interface{}) string { 119 if reflect.ValueOf(next).IsNil() { 120 return "" 121 } 122 123 u, err := url.Parse(reflect.ValueOf(next).Elem().FieldByName("Href").Elem().String()) 124 if err != nil { 125 return "" 126 } 127 128 q := u.Query() 129 return q.Get("start") 130 } 131 132 // GetNextIAM ... 133 func GetNextIAM(next interface{}) string { 134 if reflect.ValueOf(next).IsNil() { 135 return "" 136 } 137 138 u, err := url.Parse(reflect.ValueOf(next).Elem().String()) 139 if err != nil { 140 return "" 141 } 142 q := u.Query() 143 return q.Get("pagetoken") 144 } 145 146 func GetResourceGroupID(apiKey, name, region string) (string, error) { 147 bmxConfig := &bluemix.Config{ 148 BluemixAPIKey: apiKey, 149 Region: region, 150 } 151 152 sess, err := session.New(bmxConfig) 153 if err != nil { 154 return "", err 155 } 156 157 err = authenticateAPIKey(sess) 158 if err != nil { 159 return "", err 160 } 161 162 generation := envFallBack([]string{"Generation"}, "2") 163 gen, err := strconv.Atoi(generation) 164 if err != nil { 165 return "", err 166 } 167 userInfo, err := fetchUserDetails(sess, gen) 168 if err != nil { 169 return "", err 170 } 171 172 accountID := userInfo.userAccount 173 rsManagementAPI, err := managementv2.New(sess) 174 if err != nil { 175 return "", err 176 } 177 178 rsGroup := rsManagementAPI.ResourceGroup() 179 resourceGroupQuery := &managementv2.ResourceGroupQuery{ 180 AccountID: accountID, 181 } 182 grp, err := rsGroup.FindByName(resourceGroupQuery, name) 183 if err != nil { 184 return "", err 185 } 186 if len(grp) > 0 { 187 return grp[0].ID, nil 188 } 189 190 return "", fmt.Errorf("Unable to get ID of resource group") 191 }