/vendor/github.com/hashicorp/terraform/builtin/providers/ovh/resource_ovh_publiccloud_user.go

https://github.com/heap/terraform-ebs-attachmentizer · Go · 289 lines · 230 code · 58 blank · 1 comment · 34 complexity · 6942d650206153af4ffa0279427b6391 MD5 · raw file

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