github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/resource_google_project_services.go (about) 1 package google 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/hashicorp/terraform/helper/schema" 8 "google.golang.org/api/servicemanagement/v1" 9 ) 10 11 func resourceGoogleProjectServices() *schema.Resource { 12 return &schema.Resource{ 13 Create: resourceGoogleProjectServicesCreate, 14 Read: resourceGoogleProjectServicesRead, 15 Update: resourceGoogleProjectServicesUpdate, 16 Delete: resourceGoogleProjectServicesDelete, 17 18 Schema: map[string]*schema.Schema{ 19 "project": &schema.Schema{ 20 Type: schema.TypeString, 21 Required: true, 22 ForceNew: true, 23 }, 24 "services": { 25 Type: schema.TypeSet, 26 Required: true, 27 Elem: &schema.Schema{Type: schema.TypeString}, 28 Set: schema.HashString, 29 }, 30 }, 31 } 32 } 33 34 func resourceGoogleProjectServicesCreate(d *schema.ResourceData, meta interface{}) error { 35 config := meta.(*Config) 36 pid := d.Get("project").(string) 37 38 // Get services from config 39 cfgServices := getConfigServices(d) 40 41 // Get services from API 42 apiServices, err := getApiServices(pid, config) 43 if err != nil { 44 return fmt.Errorf("Error creating services: %v", err) 45 } 46 47 // This call disables any APIs that aren't defined in cfgServices, 48 // and enables all of those that are 49 err = reconcileServices(cfgServices, apiServices, config, pid) 50 if err != nil { 51 return fmt.Errorf("Error creating services: %v", err) 52 } 53 54 d.SetId(pid) 55 return resourceGoogleProjectServicesRead(d, meta) 56 } 57 58 func resourceGoogleProjectServicesRead(d *schema.ResourceData, meta interface{}) error { 59 config := meta.(*Config) 60 61 services, err := getApiServices(d.Id(), config) 62 if err != nil { 63 return err 64 } 65 66 d.Set("services", services) 67 return nil 68 } 69 70 func resourceGoogleProjectServicesUpdate(d *schema.ResourceData, meta interface{}) error { 71 log.Printf("[DEBUG]: Updating google_project_services") 72 config := meta.(*Config) 73 pid := d.Get("project").(string) 74 75 // Get services from config 76 cfgServices := getConfigServices(d) 77 78 // Get services from API 79 apiServices, err := getApiServices(pid, config) 80 if err != nil { 81 return fmt.Errorf("Error updating services: %v", err) 82 } 83 84 // This call disables any APIs that aren't defined in cfgServices, 85 // and enables all of those that are 86 err = reconcileServices(cfgServices, apiServices, config, pid) 87 if err != nil { 88 return fmt.Errorf("Error updating services: %v", err) 89 } 90 91 return resourceGoogleProjectServicesRead(d, meta) 92 } 93 94 func resourceGoogleProjectServicesDelete(d *schema.ResourceData, meta interface{}) error { 95 log.Printf("[DEBUG]: Deleting google_project_services") 96 config := meta.(*Config) 97 services := resourceServices(d) 98 for _, s := range services { 99 disableService(s, d.Id(), config) 100 } 101 d.SetId("") 102 return nil 103 } 104 105 // This function ensures that the services enabled for a project exactly match that 106 // in a config by disabling any services that are returned by the API but not present 107 // in the config 108 func reconcileServices(cfgServices, apiServices []string, config *Config, pid string) error { 109 // Helper to convert slice to map 110 m := func(vals []string) map[string]struct{} { 111 sm := make(map[string]struct{}) 112 for _, s := range vals { 113 sm[s] = struct{}{} 114 } 115 return sm 116 } 117 118 cfgMap := m(cfgServices) 119 apiMap := m(apiServices) 120 121 for k, _ := range apiMap { 122 if _, ok := cfgMap[k]; !ok { 123 // The service in the API is not in the config; disable it. 124 err := disableService(k, pid, config) 125 if err != nil { 126 return err 127 } 128 } else { 129 // The service exists in the config and the API, so we don't need 130 // to re-enable it 131 delete(cfgMap, k) 132 } 133 } 134 135 for k, _ := range cfgMap { 136 err := enableService(k, pid, config) 137 if err != nil { 138 return err 139 } 140 } 141 return nil 142 } 143 144 // Retrieve services defined in a config 145 func getConfigServices(d *schema.ResourceData) (services []string) { 146 if v, ok := d.GetOk("services"); ok { 147 for _, svc := range v.(*schema.Set).List() { 148 services = append(services, svc.(string)) 149 } 150 } 151 return 152 } 153 154 // Retrieve a project's services from the API 155 func getApiServices(pid string, config *Config) ([]string, error) { 156 apiServices := make([]string, 0) 157 // Get services from the API 158 svcResp, err := config.clientServiceMan.Services.List().ConsumerId("project:" + pid).Do() 159 if err != nil { 160 return apiServices, err 161 } 162 for _, v := range svcResp.Services { 163 apiServices = append(apiServices, v.ServiceName) 164 } 165 return apiServices, nil 166 } 167 168 func enableService(s, pid string, config *Config) error { 169 esr := newEnableServiceRequest(pid) 170 sop, err := config.clientServiceMan.Services.Enable(s, esr).Do() 171 if err != nil { 172 return fmt.Errorf("Error enabling service %q for project %q: %v", s, pid, err) 173 } 174 // Wait for the operation to complete 175 waitErr := serviceManagementOperationWait(config, sop, "api to enable") 176 if waitErr != nil { 177 return waitErr 178 } 179 return nil 180 } 181 func disableService(s, pid string, config *Config) error { 182 dsr := newDisableServiceRequest(pid) 183 sop, err := config.clientServiceMan.Services.Disable(s, dsr).Do() 184 if err != nil { 185 return fmt.Errorf("Error disabling service %q for project %q: %v", s, pid, err) 186 } 187 // Wait for the operation to complete 188 waitErr := serviceManagementOperationWait(config, sop, "api to disable") 189 if waitErr != nil { 190 return waitErr 191 } 192 return nil 193 } 194 195 func newEnableServiceRequest(pid string) *servicemanagement.EnableServiceRequest { 196 return &servicemanagement.EnableServiceRequest{ConsumerId: "project:" + pid} 197 } 198 199 func newDisableServiceRequest(pid string) *servicemanagement.DisableServiceRequest { 200 return &servicemanagement.DisableServiceRequest{ConsumerId: "project:" + pid} 201 } 202 203 func resourceServices(d *schema.ResourceData) []string { 204 // Calculate the tags 205 var services []string 206 if s := d.Get("services"); s != nil { 207 ss := s.(*schema.Set) 208 services = make([]string, ss.Len()) 209 for i, v := range ss.List() { 210 services[i] = v.(string) 211 } 212 } 213 return services 214 }