github.com/bradfeehan/terraform@v0.7.0-rc3.0.20170529055808-34b45c5ad841/builtin/providers/ovh/resource_ovh_publiccloud_user.go (about) 1 package ovh 2 3 import ( 4 "fmt" 5 "log" 6 "regexp" 7 "strconv" 8 "time" 9 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 13 "github.com/ovh/go-ovh/ovh" 14 ) 15 16 func resourcePublicCloudUser() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourcePublicCloudUserCreate, 19 Read: resourcePublicCloudUserRead, 20 Delete: resourcePublicCloudUserDelete, 21 22 Importer: &schema.ResourceImporter{ 23 State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { 24 return []*schema.ResourceData{d}, nil 25 }, 26 }, 27 28 Schema: map[string]*schema.Schema{ 29 "project_id": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 DefaultFunc: schema.EnvDefaultFunc("OVH_PROJECT_ID", nil), 34 }, 35 "description": &schema.Schema{ 36 Type: schema.TypeString, 37 Optional: true, 38 ForceNew: true, 39 }, 40 "username": &schema.Schema{ 41 Type: schema.TypeString, 42 Computed: true, 43 }, 44 "password": &schema.Schema{ 45 Type: schema.TypeString, 46 Computed: true, 47 Sensitive: true, 48 }, 49 "status": &schema.Schema{ 50 Type: schema.TypeString, 51 Computed: true, 52 }, 53 "creation_date": &schema.Schema{ 54 Type: schema.TypeString, 55 Computed: true, 56 }, 57 "openstack_rc": &schema.Schema{ 58 Type: schema.TypeMap, 59 Optional: true, 60 Computed: true, 61 }, 62 }, 63 } 64 } 65 66 func resourcePublicCloudUserCreate(d *schema.ResourceData, meta interface{}) error { 67 config := meta.(*Config) 68 69 projectId := d.Get("project_id").(string) 70 params := &PublicCloudUserCreateOpts{ 71 ProjectId: projectId, 72 Description: d.Get("description").(string), 73 } 74 75 r := &PublicCloudUserResponse{} 76 77 log.Printf("[DEBUG] Will create public cloud user: %s", params) 78 79 // Resource is partial because we will also compute Openstack RC & creds 80 d.Partial(true) 81 82 endpoint := fmt.Sprintf("/cloud/project/%s/user", params.ProjectId) 83 84 err := config.OVHClient.Post(endpoint, params, r) 85 if err != nil { 86 return fmt.Errorf("calling Post %s with params %s:\n\t %q", endpoint, params, err) 87 } 88 89 log.Printf("[DEBUG] Waiting for User %s:", r) 90 91 stateConf := &resource.StateChangeConf{ 92 Pending: []string{"creating"}, 93 Target: []string{"ok"}, 94 Refresh: waitForPublicCloudUserActive(config.OVHClient, projectId, strconv.Itoa(r.Id)), 95 Timeout: 10 * time.Minute, 96 Delay: 10 * time.Second, 97 MinTimeout: 3 * time.Second, 98 } 99 100 _, err = stateConf.WaitForState() 101 if err != nil { 102 return fmt.Errorf("waiting for user (%s): %s", params, err) 103 } 104 log.Printf("[DEBUG] Created User %s", r) 105 106 readPublicCloudUser(d, r, true) 107 108 openstackrc := make(map[string]string) 109 err = publicCloudUserGetOpenstackRC(projectId, d.Id(), config.OVHClient, openstackrc) 110 if err != nil { 111 return fmt.Errorf("Creating openstack creds for user %s: %s", d.Id(), err) 112 } 113 114 d.Set("openstack_rc", &openstackrc) 115 116 d.Partial(false) 117 118 return nil 119 } 120 121 func resourcePublicCloudUserRead(d *schema.ResourceData, meta interface{}) error { 122 config := meta.(*Config) 123 124 projectId := d.Get("project_id").(string) 125 126 d.Partial(true) 127 r := &PublicCloudUserResponse{} 128 129 log.Printf("[DEBUG] Will read public cloud user %s from project: %s", d.Id(), projectId) 130 131 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s", projectId, d.Id()) 132 133 err := config.OVHClient.Get(endpoint, r) 134 if err != nil { 135 return fmt.Errorf("calling Get %s:\n\t %q", endpoint, err) 136 } 137 138 readPublicCloudUser(d, r, false) 139 140 openstackrc := make(map[string]string) 141 err = publicCloudUserGetOpenstackRC(projectId, d.Id(), config.OVHClient, openstackrc) 142 if err != nil { 143 return fmt.Errorf("Reading openstack creds for user %s: %s", d.Id(), err) 144 } 145 146 d.Set("openstack_rc", &openstackrc) 147 d.Partial(false) 148 log.Printf("[DEBUG] Read Public Cloud User %s", r) 149 return nil 150 } 151 152 func resourcePublicCloudUserDelete(d *schema.ResourceData, meta interface{}) error { 153 config := meta.(*Config) 154 155 projectId := d.Get("project_id").(string) 156 id := d.Id() 157 158 log.Printf("[DEBUG] Will delete public cloud user %s from project: %s", id, projectId) 159 160 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s", projectId, id) 161 162 err := config.OVHClient.Delete(endpoint, nil) 163 if err != nil { 164 return fmt.Errorf("calling Delete %s:\n\t %q", endpoint, err) 165 } 166 167 log.Printf("[DEBUG] Deleting Public Cloud User %s from project %s:", id, projectId) 168 169 stateConf := &resource.StateChangeConf{ 170 Pending: []string{"deleting"}, 171 Target: []string{"deleted"}, 172 Refresh: waitForPublicCloudUserDelete(config.OVHClient, projectId, id), 173 Timeout: 10 * time.Minute, 174 Delay: 10 * time.Second, 175 MinTimeout: 3 * time.Second, 176 } 177 178 _, err = stateConf.WaitForState() 179 if err != nil { 180 return fmt.Errorf("Deleting Public Cloud user %s from project %s", id, projectId) 181 } 182 log.Printf("[DEBUG] Deleted Public Cloud User %s from project %s", id, projectId) 183 184 d.SetId("") 185 186 return nil 187 } 188 189 func publicCloudUserExists(projectId, id string, c *ovh.Client) error { 190 r := &PublicCloudUserResponse{} 191 192 log.Printf("[DEBUG] Will read public cloud user for project: %s, id: %s", projectId, id) 193 194 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s", projectId, id) 195 196 err := c.Get(endpoint, r) 197 if err != nil { 198 return fmt.Errorf("calling Get %s:\n\t %q", endpoint, err) 199 } 200 log.Printf("[DEBUG] Read public cloud user: %s", r) 201 202 return nil 203 } 204 205 var publicCloudUserOSTenantName = regexp.MustCompile("export OS_TENANT_NAME=\"?([[:alnum:]]+)\"?") 206 var publicCloudUserOSTenantId = regexp.MustCompile("export OS_TENANT_ID=\"??([[:alnum:]]+)\"??") 207 var publicCloudUserOSAuthURL = regexp.MustCompile("export OS_AUTH_URL=\"??([[:^space:]]+)\"??") 208 var publicCloudUserOSUsername = regexp.MustCompile("export OS_USERNAME=\"?([[:alnum:]]+)\"?") 209 210 func publicCloudUserGetOpenstackRC(projectId, id string, c *ovh.Client, rc map[string]string) error { 211 log.Printf("[DEBUG] Will read public cloud user openstack rc for project: %s, id: %s", projectId, id) 212 213 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s/openrc?region=to_be_overriden", projectId, id) 214 215 r := &PublicCloudUserOpenstackRC{} 216 217 err := c.Get(endpoint, r) 218 if err != nil { 219 return fmt.Errorf("calling Get %s:\n\t %q", endpoint, err) 220 } 221 222 authURL := publicCloudUserOSAuthURL.FindStringSubmatch(r.Content) 223 if authURL == nil { 224 return fmt.Errorf("couln't extract OS_AUTH_URL from content: \n\t%s", r.Content) 225 } 226 tenantName := publicCloudUserOSTenantName.FindStringSubmatch(r.Content) 227 if tenantName == nil { 228 return fmt.Errorf("couln't extract OS_TENANT_NAME from content: \n\t%s", r.Content) 229 } 230 tenantId := publicCloudUserOSTenantId.FindStringSubmatch(r.Content) 231 if tenantId == nil { 232 return fmt.Errorf("couln't extract OS_TENANT_ID from content: \n\t%s", r.Content) 233 } 234 username := publicCloudUserOSUsername.FindStringSubmatch(r.Content) 235 if username == nil { 236 return fmt.Errorf("couln't extract OS_USERNAME from content: \n\t%s", r.Content) 237 } 238 239 rc["OS_AUTH_URL"] = authURL[1] 240 rc["OS_TENANT_ID"] = tenantId[1] 241 rc["OS_TENANT_NAME"] = tenantName[1] 242 rc["OS_USERNAME"] = username[1] 243 244 return nil 245 } 246 247 func readPublicCloudUser(d *schema.ResourceData, r *PublicCloudUserResponse, setPassword bool) { 248 d.Set("description", r.Description) 249 d.Set("status", r.Status) 250 d.Set("creation_date", r.CreationDate) 251 d.Set("username", r.Username) 252 if setPassword { 253 d.Set("password", r.Password) 254 } 255 d.SetId(strconv.Itoa(r.Id)) 256 } 257 258 func waitForPublicCloudUserActive(c *ovh.Client, projectId, PublicCloudUserId string) resource.StateRefreshFunc { 259 return func() (interface{}, string, error) { 260 r := &PublicCloudUserResponse{} 261 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s", projectId, PublicCloudUserId) 262 err := c.Get(endpoint, r) 263 if err != nil { 264 return r, "", err 265 } 266 267 log.Printf("[DEBUG] Pending User: %s", r) 268 return r, r.Status, nil 269 } 270 } 271 272 func waitForPublicCloudUserDelete(c *ovh.Client, projectId, PublicCloudUserId string) resource.StateRefreshFunc { 273 return func() (interface{}, string, error) { 274 r := &PublicCloudUserResponse{} 275 endpoint := fmt.Sprintf("/cloud/project/%s/user/%s", projectId, PublicCloudUserId) 276 err := c.Get(endpoint, r) 277 if err != nil { 278 if err.(*ovh.APIError).Code == 404 { 279 log.Printf("[DEBUG] user id %s on project %s deleted", PublicCloudUserId, projectId) 280 return r, "deleted", nil 281 } else { 282 return r, "", err 283 } 284 } 285 286 log.Printf("[DEBUG] Pending User: %s", r) 287 return r, r.Status, nil 288 } 289 }