github.com/GoogleCloudPlatform/terraformer@v0.8.18/providers/ibm/cloud_functions.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 "net/http" 20 "net/url" 21 "os" 22 "strings" 23 24 "github.com/GoogleCloudPlatform/terraformer/terraformutils" 25 bluemix "github.com/IBM-Cloud/bluemix-go" 26 27 ns "github.com/IBM-Cloud/bluemix-go/api/functions" 28 "github.com/IBM-Cloud/bluemix-go/session" 29 30 "github.com/apache/openwhisk-client-go/whisk" 31 ) 32 33 // CloudFunctionGenerator .. 34 type CloudFunctionGenerator struct { 35 IBMService 36 } 37 38 func (g CloudFunctionGenerator) loadPackages(namespace, pkgName string) terraformutils.Resource { 39 resource := terraformutils.NewResource( 40 fmt.Sprintf("%s:%s", namespace, pkgName), 41 pkgName, 42 "ibm_function_package", 43 "ibm", 44 map[string]string{}, 45 []string{}, 46 map[string]interface{}{}) 47 return resource 48 } 49 50 func (g CloudFunctionGenerator) loadRules(namespace, ruleName string) terraformutils.Resource { 51 resource := terraformutils.NewResource( 52 fmt.Sprintf("%s:%s", namespace, ruleName), 53 normalizeResourceName(ruleName, false), 54 "ibm_function_rule", 55 "ibm", 56 map[string]string{}, 57 []string{}, 58 map[string]interface{}{}) 59 return resource 60 } 61 62 func (g CloudFunctionGenerator) loadTriggers(namespace, triggerName string) terraformutils.Resource { 63 resource := terraformutils.NewResource( 64 fmt.Sprintf("%s:%s", namespace, triggerName), 65 normalizeResourceName(triggerName, false), 66 "ibm_function_trigger", 67 "ibm", 68 map[string]string{}, 69 []string{}, 70 map[string]interface{}{}) 71 return resource 72 } 73 74 /* 75 * 76 * Configure a HTTP client using the OpenWhisk properties (i.e. host, auth, iamtoken) 77 * Only cf-based namespaces needs auth key value. 78 * iam-based namespace don't have an auth key and needs only iam token for authorization. 79 * 80 */ 81 func setupOpenWhiskClientConfigIAM(response ns.NamespaceResponse, c *bluemix.Config, region string) (*whisk.Client, error) { 82 u, _ := url.Parse(fmt.Sprintf("https://%s.functions.cloud.ibm.com/api", region)) 83 wskClient, _ := whisk.NewClient(http.DefaultClient, &whisk.Config{ 84 Host: u.Host, 85 Version: "v1", 86 }) 87 88 if os.Getenv("TF_LOG") != "" { 89 whisk.SetDebug(true) 90 } 91 92 // Configure whisk properties to handle iam-based/iam-migrated namespaces. 93 if response.IsIamEnabled() { 94 additionalHeaders := make(http.Header) 95 additionalHeaders.Add("Authorization", c.IAMAccessToken) 96 additionalHeaders.Add("X-Namespace-Id", response.GetID()) 97 98 wskClient.Config.Namespace = response.GetID() 99 wskClient.Config.AdditionalHeaders = additionalHeaders 100 return wskClient, nil 101 } 102 103 return nil, fmt.Errorf("Failed to create whisk config object for IAM based namespace '%v'", response.GetName()) 104 } 105 106 // InitResources .. 107 func (g *CloudFunctionGenerator) InitResources() error { 108 region := g.Args["region"].(string) 109 bmxConfig := &bluemix.Config{ 110 BluemixAPIKey: os.Getenv("IC_API_KEY"), 111 } 112 113 bmxConfig.Region = region 114 115 sess, err := session.New(bmxConfig) 116 if err != nil { 117 return err 118 } 119 120 err = authenticateAPIKey(sess) 121 if err != nil { 122 return err 123 } 124 125 err = authenticateCF(sess) 126 if err != nil { 127 return err 128 } 129 130 nsClient, err := ns.New(sess) 131 if err != nil { 132 return err 133 } 134 135 nsList, err := nsClient.Namespaces().GetNamespaces() 136 if err != nil { 137 return nil 138 } 139 140 for _, n := range nsList.Namespaces { 141 // Namespace 142 if !n.IsIamEnabled() { 143 continue 144 } 145 146 // Build whisk object 147 wskClient, err := setupOpenWhiskClientConfigIAM(n, sess.Config, region) 148 if err != nil { 149 return err 150 } 151 152 // Package 153 packageService := wskClient.Packages 154 pkgOptions := &whisk.PackageListOptions{ 155 Limit: 100, 156 Skip: 0, 157 } 158 pkgs, _, err := packageService.List(pkgOptions) 159 if err != nil { 160 return fmt.Errorf("Error retrieving IBM Cloud Function package: %s", err) 161 } 162 163 for _, p := range pkgs { 164 g.Resources = append(g.Resources, g.loadPackages(n.GetName(), p.GetName())) 165 } 166 167 // Action 168 actionService := wskClient.Actions 169 actionOptions := &whisk.ActionListOptions{ 170 Limit: 100, 171 Skip: 0, 172 } 173 actions, _, err := actionService.List("", actionOptions) 174 if err != nil { 175 return fmt.Errorf("Error retrieving IBM Cloud Function action: %s", err) 176 } 177 178 for _, a := range actions { 179 actionID := "" 180 parts := strings.Split(a.Namespace, "/") 181 if len(parts) == 2 { 182 var pkgDependsOn []string 183 pkgDependsOn = append(pkgDependsOn, 184 "ibm_function_package."+terraformutils.TfSanitize(parts[1])) 185 actionID = fmt.Sprintf("%s/%s", parts[1], a.Name) 186 g.Resources = append(g.Resources, terraformutils.NewResource( 187 fmt.Sprintf("%s:%s", n.GetName(), actionID), 188 normalizeResourceName(a.Name, false), 189 "ibm_function_action", 190 "ibm", 191 map[string]string{}, 192 []string{}, 193 map[string]interface{}{ 194 "depends_on": pkgDependsOn, 195 })) 196 } else { 197 g.Resources = append(g.Resources, terraformutils.NewResource( 198 fmt.Sprintf("%s:%s", n.GetName(), a.Name), 199 normalizeResourceName(a.Name, false), 200 "ibm_function_action", 201 "ibm", 202 map[string]string{}, 203 []string{}, 204 map[string]interface{}{})) 205 } 206 } 207 208 // Rule 209 ruleService := wskClient.Rules 210 ruleOptions := &whisk.RuleListOptions{ 211 Limit: 100, 212 Skip: 0, 213 } 214 rules, _, err := ruleService.List(ruleOptions) 215 if err != nil { 216 return fmt.Errorf("Error retrieving IBM Cloud Function rule: %s", err) 217 } 218 219 for _, r := range rules { 220 g.Resources = append(g.Resources, g.loadRules(n.GetName(), r.Name)) 221 } 222 223 // Triggers 224 triggerService := wskClient.Triggers 225 triggerOptions := &whisk.TriggerListOptions{ 226 Limit: 100, 227 Skip: 0, 228 } 229 triggers, _, err := triggerService.List(triggerOptions) 230 if err != nil { 231 return fmt.Errorf("Error retrieving IBM Cloud Function trigger: %s", err) 232 } 233 234 for _, t := range triggers { 235 g.Resources = append(g.Resources, g.loadTriggers(n.GetName(), t.Name)) 236 } 237 } 238 239 return nil 240 }