From e35eabca0da78a875630ff4d752f42ea72ac1322 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Thu, 2 Jul 2020 14:54:26 +0300 Subject: [PATCH 01/32] Add 'codefresh_team' resource --- codefresh/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/codefresh/provider.go b/codefresh/provider.go index be640a25..4eaf839b 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -29,6 +29,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), "codefresh_pipeline": resourcePipeline(), + "codefresh_team": resourceTeam(), }, ConfigureFunc: configureProvider, } From dfc2ca1f93f2afb04863daf5cf6391e85a279d53 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Tue, 7 Jul 2020 22:48:27 +0300 Subject: [PATCH 02/32] Add resource_team.go --- codefresh/resource_team.go | 190 +++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 codefresh/resource_team.go diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go new file mode 100644 index 00000000..5dd67a02 --- /dev/null +++ b/codefresh/resource_team.go @@ -0,0 +1,190 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceTeam() *schema.Resource { + return &schema.Resource{ + Create: resourceTeamCreate, + Read: resourceTeamRead, + Update: resourceTeamUpdate, + Delete: resourceTeamDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "account": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "users": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + } +} + +func resourceTeamCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + team := *mapResourceToTeam(d) + + resp, err := client.CreateTeam(&team) + if err != nil { + return err + } + + d.SetId(resp.ID) + + return nil +} + +func resourceTeamRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + teamID := d.Id() + if teamID == "" { + d.SetId("") + return nil + } + + team, err := client.GetTeamByID(teamID) + if err != nil { + return err + } + + err = mapTeamToResource(team, d) + if err != nil { + return err + } + + return nil +} + +func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + team := *mapResourceToTeam(d) + + _, err := client.CreateTeam(&team) + if err != nil { + return err + } + + return nil +} + +func resourceTeamDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + err := client.DeleteTeam(d.Id()) + if err != nil { + return err + } + + return nil +} + +func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { + + err := d.Set("name", team.Name) + if err != nil { + return err + } + + err = d.Set("type", team.Type) + if err != nil { + return err + } + + err = d.Set("account", team.Account) + if err != nil { + return err + } + + err = d.Set("tags", team.Tags) + if err != nil { + return err + } + + err = d.Set("users", flattenTeamUsers(team.Users)) + if err != nil { + return err + } + + return nil +} + +func flattenTeamUsers(users []cfClient.TeamUser) []map[string]interface{} { + var res = make([]map[string]interface{}, len(users)) + for i, user := range users { + m := make(map[string]interface{}) + m["name"] = user.UserName + m["user_id"] = user.ID + + res[i] = m + } + + return res +} + +func mapResourceToTeam(d *schema.ResourceData) *cfClient.Team { + tags := d.Get("tags").(*schema.Set).List() + team := &cfClient.Team{ + ID: d.Id(), + Name: d.Get("name").(string), + Type: d.Get("type").(string), + Account: d.Get("account").(string), + Tags: convertStringArr(tags), + } + + if _, ok := d.GetOk("users"); ok { + users := d.Get("users").([]interface{}) + for idx := range users { + user := cfClient.TeamUser{ + ID: d.Get(fmt.Sprintf("users.%v.user_id", idx)).(string), + UserName: d.Get(fmt.Sprintf("users.%v.name", idx)).(string), + } + + team.Users = append(team.Users, user) + } + } + + return team +} From a24bec69e0be961f9fc57f972ba8c9d4044d9f71 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Thu, 9 Jul 2020 10:37:29 +0300 Subject: [PATCH 03/32] Add team.go --- client/team.go | 250 +++++++++++++++++++++++++++++++++++++ codefresh/provider.go | 1 + codefresh/resource_team.go | 2 +- go.mod | 1 + go.sum | 2 + 5 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 client/team.go diff --git a/client/team.go b/client/team.go new file mode 100644 index 00000000..8df949a2 --- /dev/null +++ b/client/team.go @@ -0,0 +1,250 @@ +package client + +import ( + "fmt" +) + +type TeamUser struct { + ID string `json:"id,omitempty"` + UserName string `json:"userName,omitempty"` +} + +// Team spec +type Team struct { + ID string `json:"_id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Account string `json:"account,omitempty"` + Tags []string `json:"tags,omitempty"` + Users []TeamUser `json:"users,omitempty"` +} + +// NewTeam Codefresh API expects a list of users IDs to create a new team +type NewTeam struct { + ID string `json:"_id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Account string `json:"account,omitempty"` + Tags []string `json:"tags,omitempty"` + Users []string `json:"users,omitempty"` +} + +// GetID implement CodefreshObject interface +func (team *Team) GetID() string { + return team.ID +} + +func (client *Client) GetTeamList() ([]Team, error) { + fullPath := "/team" + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var teams []Team + + err = DecodeResponseInto(resp, &teams) + if err != nil { + return nil, err + } + + return teams, nil +} + +func (client *Client) GetTeamByName(name string) (*Team, error) { + + teams, err := client.GetTeamList() + if err != nil { + return nil, err + } + + for _, team := range teams { + if team.Name == name { + return &team, nil + } + } + + return nil, nil +} + +func (client *Client) GetTeamByID(id string) (*Team, error) { + + teams, err := client.GetTeamList() + if err != nil { + return nil, err + } + + for _, team := range teams { + if team.ID == id { + return &team, nil + } + } + + return nil, nil +} + +// +func ConvertToNewTeam(team *Team) *NewTeam { + var users []string + + for _, user := range team.Users { + users = append(users, user.ID) + } + + return &NewTeam{ + ID: team.ID, + Name: team.Name, + Type: team.Type, + Account: team.Account, + Tags: team.Tags, + Users: users, + } +} + +// CreateTeam POST team +func (client *Client) CreateTeam(team *Team) (*NewTeam, error) { + + newTeam := ConvertToNewTeam(team) + body, err := EncodeToJSON(newTeam) + + if err != nil { + return nil, err + } + opts := RequestOptions{ + Path: "/team", + Method: "POST", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var respTeam NewTeam + err = DecodeResponseInto(resp, &respTeam) + if err != nil { + return nil, err + } + + return &respTeam, nil +} + +// DeleteTeam +func (client *Client) DeleteTeam(id string) error { + fullPath := fmt.Sprintf("/team/%s", id) + opts := RequestOptions{ + Path: fullPath, + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + + if err != nil { + return err + } + + return nil +} + +func (client *Client) SynchronizeClientWithGroup(name, ssoType string, notifications bool) error { + + fullPath := fmt.Sprintf("/team/group/synchronize/name/%s/type/%s?disableNotifications=%b", name, ssoType, notifications) + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + _, err := client.RequestAPI(&opts) + + if err != nil { + return err + } + + return nil +} + +func (client *Client) AddUserToTeam(teamID, userID string) (*Team, error) { + + fullPath := fmt.Sprintf("/team/%s/%s/assignUserToTeam", teamID, userID) + opts := RequestOptions{ + Path: fullPath, + Method: "PUT", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var respTeam Team + err = DecodeResponseInto(resp, &respTeam) + if err != nil { + return nil, err + } + + return &respTeam, nil +} + +func (client *Client) DeleteUserFromTeam(teamID, userID string) (*Team, error) { + + fullPath := fmt.Sprintf("/team/%s/%s/deleteUserFromTeam", teamID, userID) + opts := RequestOptions{ + Path: fullPath, + Method: "PUT", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var respTeam Team + err = DecodeResponseInto(resp, &respTeam) + if err != nil { + return nil, err + } + + return &respTeam, nil +} + +func (client *Client) RenameTeam(teamID, name string) (*Team, error) { + + fullPath := fmt.Sprintf("/team/%s/renameTeam", teamID) + + team := Team{Name: name} + body, err := EncodeToJSON(team) + + if err != nil { + return nil, err + } + + opts := RequestOptions{ + Path: fullPath, + Method: "PUT", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var respTeam Team + err = DecodeResponseInto(resp, &respTeam) + if err != nil { + return nil, err + } + + return &respTeam, nil +} diff --git a/codefresh/provider.go b/codefresh/provider.go index 4eaf839b..fd3532d6 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -30,6 +30,7 @@ func Provider() terraform.ResourceProvider { "codefresh_project": resourceProject(), "codefresh_pipeline": resourcePipeline(), "codefresh_team": resourceTeam(), + "codefresh_account": resourceAccount(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 5dd67a02..47388e57 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -102,7 +102,7 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { team := *mapResourceToTeam(d) - _, err := client.CreateTeam(&team) + _, err := client.RenameTeam(team.ID, team.Name) if err != nil { return err } diff --git a/go.mod b/go.mod index f8ebfac7..bb76561f 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/golangci/golangci-lint v1.27.0 github.com/hashicorp/terraform v0.12.25 github.com/hashicorp/terraform-plugin-sdk v1.7.0 + github.com/imdario/mergo v0.3.9 ) go 1.13 diff --git a/go.sum b/go.sum index d0826620..4688b7a2 100644 --- a/go.sum +++ b/go.sum @@ -350,6 +350,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= From 358739ac5a9cc38ac1d400f8cab02f9e1d5eabf5 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Thu, 9 Jul 2020 14:50:32 +0300 Subject: [PATCH 04/32] Fix teams --- client/team.go | 78 +++++++++++++++++++++++--------------- codefresh/resource_team.go | 73 ++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 64 deletions(-) diff --git a/client/team.go b/client/team.go index 8df949a2..670e1589 100644 --- a/client/team.go +++ b/client/team.go @@ -7,6 +7,7 @@ import ( type TeamUser struct { ID string `json:"id,omitempty"` UserName string `json:"userName,omitempty"` + Email string `json:"email,omitempty"` } // Team spec @@ -171,7 +172,7 @@ func (client *Client) SynchronizeClientWithGroup(name, ssoType string, notificat return nil } -func (client *Client) AddUserToTeam(teamID, userID string) (*Team, error) { +func (client *Client) AddUserToTeam(teamID, userID string) error { fullPath := fmt.Sprintf("/team/%s/%s/assignUserToTeam", teamID, userID) opts := RequestOptions{ @@ -179,22 +180,15 @@ func (client *Client) AddUserToTeam(teamID, userID string) (*Team, error) { Method: "PUT", } - resp, err := client.RequestAPI(&opts) - - if err != nil { - return nil, err - } - - var respTeam Team - err = DecodeResponseInto(resp, &respTeam) + _, err := client.RequestAPI(&opts) if err != nil { - return nil, err + return err } - return &respTeam, nil + return nil } -func (client *Client) DeleteUserFromTeam(teamID, userID string) (*Team, error) { +func (client *Client) DeleteUserFromTeam(teamID, userID string) error { fullPath := fmt.Sprintf("/team/%s/%s/deleteUserFromTeam", teamID, userID) opts := RequestOptions{ @@ -202,22 +196,16 @@ func (client *Client) DeleteUserFromTeam(teamID, userID string) (*Team, error) { Method: "PUT", } - resp, err := client.RequestAPI(&opts) + _, err := client.RequestAPI(&opts) if err != nil { - return nil, err - } - - var respTeam Team - err = DecodeResponseInto(resp, &respTeam) - if err != nil { - return nil, err + return err } - return &respTeam, nil + return nil } -func (client *Client) RenameTeam(teamID, name string) (*Team, error) { +func (client *Client) RenameTeam(teamID, name string) error { fullPath := fmt.Sprintf("/team/%s/renameTeam", teamID) @@ -225,7 +213,7 @@ func (client *Client) RenameTeam(teamID, name string) (*Team, error) { body, err := EncodeToJSON(team) if err != nil { - return nil, err + return err } opts := RequestOptions{ @@ -234,17 +222,47 @@ func (client *Client) RenameTeam(teamID, name string) (*Team, error) { Body: body, } - resp, err := client.RequestAPI(&opts) + _, err = client.RequestAPI(&opts) if err != nil { - return nil, err + return err } - var respTeam Team - err = DecodeResponseInto(resp, &respTeam) - if err != nil { - return nil, err + return nil +} + +func GetUsersDiff(desiredUsers []string, existingUsers []TeamUser) (usersToAdd []string, usersToDelete []string) { + + existingUsersIDs := []string{} + usersToAdd = []string{} + usersToDelete = []string{} + + for _, user := range existingUsers{ + existingUsersIDs = append(existingUsersIDs, user.ID) } - return &respTeam, nil + for _, id := range existingUsersIDs{ + ok := find(desiredUsers, id) + if !ok { + usersToDelete = append(usersToDelete, id) + } + } + + for _, id := range desiredUsers{ + ok := find(existingUsersIDs, id) + if !ok { + usersToAdd = append(usersToAdd, id) + } + } + + return usersToAdd, usersToDelete +} + +func find(slice []string, val string) bool { + for _, item := range slice { + if item == val { + return true + } + } + return false } diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 47388e57..597a5026 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -1,7 +1,6 @@ package codefresh import ( - "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -22,10 +21,9 @@ func resourceTeam() *schema.Resource { }, "type": { Type: schema.TypeString, - ForceNew: true, Optional: true, }, - "account": { + "account_id": { Type: schema.TypeString, Optional: true, Computed: true, @@ -33,26 +31,15 @@ func resourceTeam() *schema.Resource { "tags": { Type: schema.TypeSet, Optional: true, - ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, }, }, "users": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, - ForceNew: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "user_id": { - Type: schema.TypeString, - Required: true, - }, - "name": { - Type: schema.TypeString, - Optional: true, - }, - }, + Elem: &schema.Schema{ + Type: schema.TypeString, }, }, }, @@ -102,11 +89,36 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { team := *mapResourceToTeam(d) - _, err := client.RenameTeam(team.ID, team.Name) + // Rename + err := client.RenameTeam(team.ID, team.Name) if err != nil { return err } + // Update users + existingTeam, err := client.GetTeamByID(team.ID) + if err != nil { + return nil + } + + desiredUsers := d.Get("users").(*schema.Set).List() + + usersToAdd, usersToDelete := cfClient.GetUsersDiff(convertStringArr(desiredUsers), existingTeam.Users) + + for _, userId := range usersToDelete{ + err := client.DeleteUserFromTeam(team.ID, userId) + if err != nil { + return err + } + } + + for _, userId := range usersToAdd{ + err := client.AddUserToTeam(team.ID, userId) + if err != nil { + return err + } + } + return nil } @@ -133,7 +145,7 @@ func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { return err } - err = d.Set("account", team.Account) + err = d.Set("account_id", team.Account) if err != nil { return err } @@ -151,16 +163,11 @@ func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { return nil } -func flattenTeamUsers(users []cfClient.TeamUser) []map[string]interface{} { - var res = make([]map[string]interface{}, len(users)) - for i, user := range users { - m := make(map[string]interface{}) - m["name"] = user.UserName - m["user_id"] = user.ID - - res[i] = m +func flattenTeamUsers(users []cfClient.TeamUser) []string { + res := []string{} + for _, user := range users { + res = append(res, user.ID) } - return res } @@ -170,18 +177,16 @@ func mapResourceToTeam(d *schema.ResourceData) *cfClient.Team { ID: d.Id(), Name: d.Get("name").(string), Type: d.Get("type").(string), - Account: d.Get("account").(string), + Account: d.Get("account_id").(string), Tags: convertStringArr(tags), } if _, ok := d.GetOk("users"); ok { - users := d.Get("users").([]interface{}) - for idx := range users { + users := d.Get("users").(*schema.Set).List() + for _, id := range users { user := cfClient.TeamUser{ - ID: d.Get(fmt.Sprintf("users.%v.user_id", idx)).(string), - UserName: d.Get(fmt.Sprintf("users.%v.name", idx)).(string), + ID: id.(string), } - team.Users = append(team.Users, user) } } From a15edd22c2afdd7305cf29a8105ccc83c9ef887c Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Fri, 10 Jul 2020 11:27:48 +0300 Subject: [PATCH 05/32] Add account resource --- client/account.go | 270 ++++++++++++++++++++++++++++++++++ codefresh/resource_account.go | 224 ++++++++++++++++++++++++++++ codefresh/utils.go | 2 +- go.mod | 1 + 4 files changed, 496 insertions(+), 1 deletion(-) create mode 100644 client/account.go create mode 100644 codefresh/resource_account.go diff --git a/client/account.go b/client/account.go new file mode 100644 index 00000000..82b4f58c --- /dev/null +++ b/client/account.go @@ -0,0 +1,270 @@ +package client + +import ( + "errors" + "fmt" + "strconv" + + "github.com/google/martian/log" + "github.com/imdario/mergo" +) + + +type DockerRegistry struct { + Kind string `json:"kind"` + BehindFirewall bool `json:"behindFirewall"` + Primary bool `json:"primary"` + Default bool `json:"default"` + Internal bool `json:"internal"` + DenyCompositeDomain bool `json:"denyCompositeDomain"` + ID string `json:"_id"` + Name string `json:"name"` + Provider string `json:"provider"` + Username string `json:"username"` + Password string `json:"password"` + Domain string `json:"domain"` + RepositoryPrefix string `json:"repositoryPrefix"` +} + +type Suspension struct { + IsSuspended bool `json:"isSuspended"` +} + +type Exist struct { + Exist bool `json:"exist"` +} + +type Active struct { + Active bool `json:"active"` +} + +type Integration struct { + Stash Active `json:"stash,omitempty"` + Github Active `json:"github,omitempty"` + Gitlab Active `json:"gitlab,omitempty"` + Aks Exist `json:"aks,omitempty"` + Gcloud Exist `json:"gcloud,omitempty"` + DigitalOcean Exist `json:"digitalOcean,omitempty"` + Registries []DockerRegistry `json:"registries,omitempty"` +} + +type Build struct { + Strategy string `json:"strategy,omitempty"` + Nodes int `json:"nodes,omitempty"` + Parallel int `json:"parallel,omitempty"` + Packs []interface{} `json:"packs,omitempty"` +} + +type PaymentPlan struct { + Trial struct { + Trialing bool `json:"trialing"` + TrialWillEndNotified bool `json:"trialWillEndNotified"` + TrialEndedNotified bool `json:"trialEndedNotified"` + Type string `json:"type"` + PreviousSegment string `json:"previousSegment"` + } `json:"trial,omitempty"` + ID string `json:"id,omitempty"` + Provider string `json:"provider,omitempty"` +} + +type ImageViewConfig struct { + Version string `json:"version"` +} + +type BuildStepConfig struct { + Version string `json:"version"` + DisablePush bool `json:"disablePush"` + AutoPush bool `json:"autoPush"` +} + +type CFCRState struct { + Enabled bool `json:"enabled"` + System string `json:"system"` + DisplayGlobalNotice bool `json:"displayGlobalNotice"` + AccountChoice string `json:"accountChoice"` +} + +type NotificationEvent struct { + Events []string `json:"events"` + Type string `json:"type"` +} + +type Collaborators struct { + Limit int `json:"limit"` + Used int `json:"used,omitempty"` +} + +type DataRetention struct { + Weeks int `json:"weeks"` +} + +type Limits struct { + Collaborators Collaborators `json:"collaborators,omitempty"` + DataRetention DataRetention `json:"dataRetention,omitempty"` +} + +type Account struct { + Suspension *Suspension `json:"suspension,omitempty"` + Integrations *Integration `json:"integrations,omitempty"` + Build *Build `json:"build,omitempty"` + PaymentPlan *PaymentPlan `json:"paymentPlan,omitempty"` + ImageViewConfig *ImageViewConfig `json:"imageViewConfig,omitempty"` + BuildStepConfig *BuildStepConfig `json:"buildStepConfig,omitempty"` + CFCRState *CFCRState `json:"CFCRState,omitempty"` + AllowedDomains []interface{} `json:"allowedDomains,omitempty"` + Admins []string `json:"admins,omitempty"` + Environment int `json:"environment,omitempty"` + DedicatedInfrastructure bool `json:"dedicatedInfrastructure,omitempty"` + CanUsePrivateRepos bool `json:"canUsePrivateRepos,omitempty"` + SupportPlan string `json:"supportPlan,omitempty"` + IncreasedAttention bool `json:"increasedAttention,omitempty"` + LocalUserPasswordIDPEnabled bool `json:"localUserPasswordIDPEnabled,omitempty"` + CodefreshEnv string `json:"codefreshEnv,omitempty"` + ID string `json:"_id,omitempty,omitempty"` + BadgeToken string `json:"badgeToken,omitempty"` + CreatedAt string `json:"createdAt,omitempty"` + UpdatedAt string `json:"updatedAt,omitempty"` + Name string `json:"name,omitempty"` + RuntimeEnvironment string `json:"runtimeEnvironment,omitempty"` + CfcrRepositoryPath string `json:"cfcrRepositoryPath,omitempty"` + Notifications []NotificationEvent `json:"notifications,omitempty"` + RepoPermission string `json:"repoPermission,omitempty"` + __V int `json:"__v,omitempty"` + Limits *Limits `json:"limits,omitempty"` + Features map[string]bool `json:"features,omitempty"` + // Features *Features `json:"features,omitempty"` + // RuntimeEnvironments ToDo + // Remaining ToDo + // ID string `json:"id"` +} + +type AccountDetails struct { + AccountDetails Account `json:"accountDetails"` +} + +// Decodes a TypeMap of map[string]interface{} into map[string]bool for account features +func (account *Account) SetFeatures(m map[string]interface{}) { + res := make(map[string]bool) + for k, v := range m { + value := v.(string) + b, err := strconv.ParseBool(value) + if err != nil { + log.Errorf("[ERROR] Can't parse '%s = %s' as boolean", k, value) + } + res[k] = b + } + account.Features = res +} + +func (account *Account) GetID() string { + return account.ID +} + +func (client *Client) GetAccountByID(id string) (*Account, error) { + fullPath := fmt.Sprintf("/admin/accounts/%s", id) + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var account Account + + err = DecodeResponseInto(resp, &account) + if err != nil { + return nil, err + } + + return &account, nil +} + +func (client *Client) CreateAccount(account *Account) (*Account, error) { + + body, err := EncodeToJSON(account) + + if err != nil { + return nil, err + } + opts := RequestOptions{ + Path: "/admin/accounts", + Method: "POST", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var respAccount Account + + err = DecodeResponseInto(resp, &respAccount) + if err != nil { + return nil, err + } + + return &respAccount, nil +} + +func (client *Client) UpdateAccount(account *Account) (*Account, error) { + + id := account.GetID() + if id == "" { + return nil, errors.New("[ERROR] Account ID is empty") + } + + existingAccount, err := client.GetAccountByID(id) + if err = mergo.Merge(account, existingAccount); err != nil { + return nil, err + } + + putAccount := AccountDetails{*account} + + body, err := EncodeToJSON(putAccount) + if err != nil { + return nil, err + } + + fullPath := fmt.Sprintf("/admin/accounts/%s/update", id) + opts := RequestOptions{ + Path: fullPath, + Method: "POST", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var respAccount Account + err = DecodeResponseInto(resp, &respAccount) + if err != nil { + return nil, err + } + + return &respAccount, nil +} + +func (client *Client) DeleteAccount(id string) error { + + fullPath := fmt.Sprintf("/admin/accounts/%s", id) + opts := RequestOptions{ + Path: fullPath, + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + + if err != nil { + return err + } + + return nil +} diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go new file mode 100644 index 00000000..ae324aec --- /dev/null +++ b/codefresh/resource_account.go @@ -0,0 +1,224 @@ +package codefresh + +import ( + // "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + // "os" +) + +func resourceAccount() *schema.Resource { + return &schema.Resource{ + Create: resourceAccountCreate, + Read: resourceAccountRead, + Update: resourceAccountUpdate, + Delete: resourceAccountDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + // "runtime_environment": { + // Type: schema.TypeString, + // Optional: true, + // }, + "admins": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "limits": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "collaborators": { + Type: schema.TypeInt, + Required: true, + }, + "data_retention_weeks": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + "build": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parallel": { + Type: schema.TypeInt, + Required: true, + }, + "nodes": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + // Features can not be managed by account API + // "features": { + // Type: schema.TypeMap, + // Optional: true, + // Elem: &schema.Schema { + // Type: schema.TypeString, + // }, + // }, + }, + } +} + +func resourceAccountCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + account := *mapResourceToAccount(d) + + resp, err := client.CreateAccount(&account) + if err != nil { + return err + } + + d.SetId(resp.ID) + + return nil +} + +func resourceAccountRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + accountID := d.Id() + if accountID == "" { + d.SetId("") + return nil + } + + team, err := client.GetAccountByID(accountID) + if err != nil { + return err + } + + err = mapAccountToResource(team, d) + if err != nil { + return err + } + + return nil +} + +func resourceAccountUpdate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + account := *mapResourceToAccount(d) + + _, err := client.UpdateAccount(&account) + if err != nil { + return err + } + + // TODO + // - rename account + // - add/remove admins + + return nil +} + +func resourceAccountDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + err := client.DeleteAccount(d.Id()) + if err != nil { + return err + } + + return nil +} + +func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) error { + + err := d.Set("name", account.Name) + if err != nil { + return err + } + + // err = d.Set("runtime_environment", account.RuntimeEnvironment) + // if err != nil { + // return err + // } + + err = d.Set("admins", account.Admins) + if err != nil { + return err + } + + err = d.Set("limits", []map[string]interface{}{flattenLimits(*account.Limits)}) + if err != nil { + return err + } + + err = d.Set("build", []map[string]interface{}{flattenBuild(*account.Build)}) + if err != nil { + return err + } + + return nil +} + +func flattenLimits(limits cfClient.Limits) map[string]interface{} { + res := make(map[string]interface{}) + res["collaborators"] = limits.Collaborators.Limit + res["data_retention_weeks"] = limits.DataRetention.Weeks + return res +} + +func flattenBuild(build cfClient.Build) map[string]interface{} { + res := make(map[string]interface{}) + res["parallel"] = build.Parallel + res["nodes"] = build.Nodes + return res +} +func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { + admins := d.Get("admins").(*schema.Set).List() + + account := &cfClient.Account{ + ID: d.Id(), + Name: d.Get("name").(string), + Admins: convertStringArr(admins), + // RuntimeEnvironment: d.Get("runtime_environment").(string), + } + + if _, ok := d.GetOk("limits"); ok { + account.Limits = &cfClient.Limits{ + Collaborators: cfClient.Collaborators{ + Limit: d.Get("limits.0.collaborators").(int), + }, + DataRetention: cfClient.DataRetention{ + Weeks: d.Get("limits.0.data_retention_weeks").(int), + }, + } + } + + if _, ok := d.GetOk("build"); ok { + account.Build = &cfClient.Build{ + Parallel: d.Get("build.0.parallel").(int), + Nodes: d.Get("build.0.nodes").(int), + } + } + + // Features can not be managed by account API + // features := d.Get("features").(map[string]interface{}) + // account.SetFeatures(features) + + return account +} + diff --git a/codefresh/utils.go b/codefresh/utils.go index c71fb2fc..b0395b9f 100644 --- a/codefresh/utils.go +++ b/codefresh/utils.go @@ -25,4 +25,4 @@ func convertVariables(vars []cfClient.Variable) map[string]string { res[v.Key] = v.Value } return res -} +} \ No newline at end of file diff --git a/go.mod b/go.mod index bb76561f..14fad38f 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/bflad/tfproviderlint v0.14.0 github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.27.0 + github.com/google/martian v2.1.0+incompatible github.com/hashicorp/terraform v0.12.25 github.com/hashicorp/terraform-plugin-sdk v1.7.0 github.com/imdario/mergo v0.3.9 From 9530d35a36343ba2b8f4ff6b05f254b71a6133e6 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Mon, 13 Jul 2020 09:24:44 +0300 Subject: [PATCH 06/32] Add api_key resource Refactor code --- client/account.go | 18 +-- client/api_key.go | 221 ++++++++++++++++++++++++++++++++++ client/client.go | 40 +++++- client/team.go | 22 ++-- client/user.go | 89 ++++++++++++++ codefresh/provider.go | 1 + codefresh/resource_account.go | 34 +----- codefresh/resource_api_key.go | 172 ++++++++++++++++++++++++++ codefresh/resource_team.go | 5 +- codefresh/utils.go | 2 +- 10 files changed, 548 insertions(+), 56 deletions(-) create mode 100644 client/api_key.go create mode 100644 client/user.go create mode 100644 codefresh/resource_api_key.go diff --git a/client/account.go b/client/account.go index 82b4f58c..a8947213 100644 --- a/client/account.go +++ b/client/account.go @@ -3,13 +3,11 @@ package client import ( "errors" "fmt" - "strconv" - - "github.com/google/martian/log" "github.com/imdario/mergo" + "log" + "strconv" ) - type DockerRegistry struct { Kind string `json:"kind"` BehindFirewall bool `json:"behindFirewall"` @@ -120,7 +118,7 @@ type Account struct { IncreasedAttention bool `json:"increasedAttention,omitempty"` LocalUserPasswordIDPEnabled bool `json:"localUserPasswordIDPEnabled,omitempty"` CodefreshEnv string `json:"codefreshEnv,omitempty"` - ID string `json:"_id,omitempty,omitempty"` + ID string `json:"_id,omitempty"` BadgeToken string `json:"badgeToken,omitempty"` CreatedAt string `json:"createdAt,omitempty"` UpdatedAt string `json:"updatedAt,omitempty"` @@ -129,7 +127,6 @@ type Account struct { CfcrRepositoryPath string `json:"cfcrRepositoryPath,omitempty"` Notifications []NotificationEvent `json:"notifications,omitempty"` RepoPermission string `json:"repoPermission,omitempty"` - __V int `json:"__v,omitempty"` Limits *Limits `json:"limits,omitempty"` Features map[string]bool `json:"features,omitempty"` // Features *Features `json:"features,omitempty"` @@ -149,7 +146,7 @@ func (account *Account) SetFeatures(m map[string]interface{}) { value := v.(string) b, err := strconv.ParseBool(value) if err != nil { - log.Errorf("[ERROR] Can't parse '%s = %s' as boolean", k, value) + log.Fatalf("[ERROR] Can't parse '%s = %s' as boolean", k, value) } res[k] = b } @@ -220,7 +217,12 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { } existingAccount, err := client.GetAccountByID(id) - if err = mergo.Merge(account, existingAccount); err != nil { + if err != nil { + return nil, err + } + + err = mergo.Merge(account, existingAccount) + if err != nil { return nil, err } diff --git a/client/api_key.go b/client/api_key.go new file mode 100644 index 00000000..adb1f912 --- /dev/null +++ b/client/api_key.go @@ -0,0 +1,221 @@ +package client + +import ( + "errors" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "log" + "net/http" +) + +type ApiKeySubject struct { + Type string `json:"type,omitempty"` + Ref string `json:"ref,omitempty"` +} + +type ApiKeyScopeSnapshot struct { + Scopes []string `json:"scopes,omitempty"` + ID string `json:"_id,omitempty"` + Date string `json:"date,omitempty"` + V int `json:"__v,omitempty"` +} + +type ApiKey struct { + Subject ApiKeySubject `json:"subject,omitempty"` + ID string `json:"_id,omitempty"` + Name string `json:"name"` + Scopes []string `json:"scopes,omitempty"` + TokenPrefix string `json:"tokenPrefix,omitempty"` + ScopeSnapshot ApiKeyScopeSnapshot `json:"scopeSnapshot,omitempty"` + Created string `json:"created,omitempty"` +} + +func (client *Client) GetAPIKey(keyID string) (*ApiKey, error) { + + opts := RequestOptions{ + Path: fmt.Sprintf("/auth/key/%s", keyID), + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var apiKey ApiKey + + err = DecodeResponseInto(resp, &apiKey) + if err != nil { + return nil, err + } + + return &apiKey, nil +} + +func (client *Client) DeleteAPIKey(keyID string) error { + + opts := RequestOptions{ + Path: fmt.Sprintf("/auth/key/%s", keyID), + Method: "DELETE", + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + fmt.Println(string(resp)) + return err + } + + return nil +} + +func (client *Client) UpdateAPIKey(key *ApiKey) error { + + keyID := key.ID + if keyID == "" { + return errors.New("[ERROR] Key ID is empty") + } + + body, err := EncodeToJSON(key) + if err != nil { + return err + } + + opts := RequestOptions{ + Path: fmt.Sprintf("/auth/key/%s", keyID), + Method: "PATCH", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + fmt.Println(string(resp)) + return err + } + + return nil +} + +func (client *Client) CreateApiKey(accountId string, apiKey *ApiKey) (string, error) { + + // Check collaborataros + account, err := client.GetAccountByID(accountId) + if err != nil { + return "", err + } + if account.Limits == nil { + log.Fatal("[ERROR] Collaborators are not set") + } + + // add user + userPrefix := acctest.RandString(10) + userName := "tfuser" + userPrefix + userEmail := userName + "@codefresh.io" + + user, err := client.AddNewUserToAccount(accountId, userName, userEmail) + if err != nil { + return "", err + } + userID := user.ID + + // activate + _, err = client.ActivateUser(userID) + if err != nil { + return "", err + } + + // set user as account admin + err = client.SetUserAsAccountAdmin(accountId, userID) + if err != nil { + return "", nil + } + + // login as user + xAccessToken, err := client.GetXAccessToken(userID) + if err != nil { + return "", err + } + + // generate token + apiToken, err := client.GenerateToken(xAccessToken, apiKey) + if err != nil { + return "", err + } + + return apiToken, nil + +} + +func (client *Client) GetXAccessToken(userID string) (string, error) { + + url := fmt.Sprintf("%s/admin/user/loginAsUser?userId=%s", client.Host, userID) + request, err := http.NewRequest("GET", url, nil) + if err != nil { + return "", err + } + + request.Header.Set("Authorization", client.Token) + request.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, err := client.Client.Do(request) + if err != nil { + return "", err + } + + defer resp.Body.Close() + + for _, cookie := range resp.Cookies() { + if cookie.Name == "cf-access-token" { + return cookie.Value, nil + } + } + + return "", nil +} + +func (client *Client) GenerateToken(xToken string, apiKey *ApiKey) (string, error) { + + body, err := EncodeToJSON(apiKey) + if err != nil { + return "", err + } + + opts := RequestOptions{ + Path: "/auth/key", + Method: "POST", + XAccessToken: xToken, + Body: body, + } + + resp, err := client.RequestApiXAccessToken(&opts) + + if err != nil { + return "", err + } + + return string(resp), nil +} + +func (client *Client) GetApiKeysList() ([]ApiKey, error) { + fullPath := "/auth/keys" + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var apiKeys []ApiKey + + err = DecodeResponseInto(resp, &apiKeys) + if err != nil { + return nil, err + } + + return apiKeys, nil +} diff --git a/client/client.go b/client/client.go index e6ed7e28..5bb78b04 100644 --- a/client/client.go +++ b/client/client.go @@ -18,10 +18,11 @@ type Client struct { // RequestOptions path, method, etc type RequestOptions struct { - Path string - Method string - Body []byte - QS map[string]string + Path string + Method string + Body []byte + QS map[string]string + XAccessToken string } // NewClient returns a new client configured to communicate on a server with the @@ -68,6 +69,37 @@ func (client *Client) RequestAPI(opt *RequestOptions) ([]byte, error) { return body, nil } +func (client *Client) RequestApiXAccessToken(opt *RequestOptions) ([]byte, error) { + finalURL := fmt.Sprintf("%s%s", client.Host, opt.Path) + if opt.QS != nil { + finalURL += ToQS(opt.QS) + } + request, err := http.NewRequest(opt.Method, finalURL, bytes.NewBuffer(opt.Body)) + if err != nil { + return nil, err + } + + request.Header.Set("x-access-token", opt.XAccessToken) + request.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, err := client.Client.Do(request) + + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("Failed to read body %v %v", resp.StatusCode, resp.Status) + } + + if resp.StatusCode != 200 { + return nil, fmt.Errorf("%v, %s", resp.Status, string(body)) + } + return body, nil +} + // ToQS add extra parameters to path func ToQS(qs map[string]string) string { var arr = []string{} diff --git a/client/team.go b/client/team.go index 670e1589..7aa09f33 100644 --- a/client/team.go +++ b/client/team.go @@ -157,7 +157,7 @@ func (client *Client) DeleteTeam(id string) error { func (client *Client) SynchronizeClientWithGroup(name, ssoType string, notifications bool) error { - fullPath := fmt.Sprintf("/team/group/synchronize/name/%s/type/%s?disableNotifications=%b", name, ssoType, notifications) + fullPath := fmt.Sprintf("/team/group/synchronize/name/%s/type/%s?disableNotifications=%t", name, ssoType, notifications) opts := RequestOptions{ Path: fullPath, Method: "GET", @@ -188,7 +188,7 @@ func (client *Client) AddUserToTeam(teamID, userID string) error { return nil } -func (client *Client) DeleteUserFromTeam(teamID, userID string) error { +func (client *Client) DeleteUserFromTeam(teamID, userID string) error { fullPath := fmt.Sprintf("/team/%s/%s/deleteUserFromTeam", teamID, userID) opts := RequestOptions{ @@ -237,18 +237,18 @@ func GetUsersDiff(desiredUsers []string, existingUsers []TeamUser) (usersToAdd [ usersToAdd = []string{} usersToDelete = []string{} - for _, user := range existingUsers{ + for _, user := range existingUsers { existingUsersIDs = append(existingUsersIDs, user.ID) } - for _, id := range existingUsersIDs{ + for _, id := range existingUsersIDs { ok := find(desiredUsers, id) if !ok { usersToDelete = append(usersToDelete, id) } } - for _, id := range desiredUsers{ + for _, id := range desiredUsers { ok := find(existingUsersIDs, id) if !ok { usersToAdd = append(usersToAdd, id) @@ -259,10 +259,10 @@ func GetUsersDiff(desiredUsers []string, existingUsers []TeamUser) (usersToAdd [ } func find(slice []string, val string) bool { - for _, item := range slice { - if item == val { - return true - } - } - return false + for _, item := range slice { + if item == val { + return true + } + } + return false } diff --git a/client/user.go b/client/user.go new file mode 100644 index 00000000..a0f22422 --- /dev/null +++ b/client/user.go @@ -0,0 +1,89 @@ +package client + +import "fmt" + +type User struct { + ID string `json:"_id"` + UserName string `json:"userName"` + Email string `json:"email"` + Roles []interface{} `json:"roles"` + DefaultAccount int `json:"defaultAccount"` + Account []Account `json:"account"` + Status string `json:"status"` + RegisterDate string `json:"register_date"` + HasPassword bool `json:"hasPassword"` + Notifications []NotificationEvent `json:"notifications"` + ShortProfile struct { + UserName string `json:"userName"` + } `json:"shortProfile"` + Settings struct { + SendWeeklyReport bool `json:"sendWeeklyReport"` + } `json:"settings"` + Logins []interface{} `json:"logins"` + InviteURL string `json:"inviteUrl"` +} + +func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { + + userDetails := fmt.Sprintf(`{"userName": "%s", "email": "%s"}`, userName, userEmail) + + fullPath := fmt.Sprintf("/accounts/%s/adduser", accountId) + + opts := RequestOptions{ + Path: fullPath, + Method: "POST", + Body: []byte(userDetails), + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var user User + + err = DecodeResponseInto(resp, &user) + if err != nil { + return nil, err + } + + return &user, nil +} + +func (client *Client) ActivateUser(userId string) (*User, error) { + + opts := RequestOptions{ + Path: fmt.Sprintf("/admin/user/%s/activate", userId), + Method: "POST", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var user User + + err = DecodeResponseInto(resp, &user) + if err != nil { + return nil, err + } + + return &user, nil +} + +func (client *Client) SetUserAsAccountAdmin(accountId, userId string) error { + + opts := RequestOptions{ + Path: fmt.Sprintf("/accounts/%s/%s/admin", accountId, userId), + Method: "POST", + } + + _, err := client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index fd3532d6..6fbf6e32 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -31,6 +31,7 @@ func Provider() terraform.ResourceProvider { "codefresh_pipeline": resourcePipeline(), "codefresh_team": resourceTeam(), "codefresh_account": resourceAccount(), + "codefresh_api_key": resourceApiKey(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index ae324aec..e1f00dd5 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -1,10 +1,8 @@ package codefresh import ( - // "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - // "os" ) func resourceAccount() *schema.Resource { @@ -21,10 +19,6 @@ func resourceAccount() *schema.Resource { Type: schema.TypeString, Required: true, }, - // "runtime_environment": { - // Type: schema.TypeString, - // Optional: true, - // }, "admins": { Type: schema.TypeSet, Optional: true, @@ -64,14 +58,6 @@ func resourceAccount() *schema.Resource { }, }, }, - // Features can not be managed by account API - // "features": { - // Type: schema.TypeMap, - // Optional: true, - // Elem: &schema.Schema { - // Type: schema.TypeString, - // }, - // }, }, } } @@ -151,11 +137,6 @@ func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) err return err } - // err = d.Set("runtime_environment", account.RuntimeEnvironment) - // if err != nil { - // return err - // } - err = d.Set("admins", account.Admins) if err != nil { return err @@ -191,12 +172,11 @@ func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { admins := d.Get("admins").(*schema.Set).List() account := &cfClient.Account{ - ID: d.Id(), - Name: d.Get("name").(string), - Admins: convertStringArr(admins), - // RuntimeEnvironment: d.Get("runtime_environment").(string), + ID: d.Id(), + Name: d.Get("name").(string), + Admins: convertStringArr(admins), } - + if _, ok := d.GetOk("limits"); ok { account.Limits = &cfClient.Limits{ Collaborators: cfClient.Collaborators{ @@ -214,11 +194,5 @@ func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { Nodes: d.Get("build.0.nodes").(int), } } - - // Features can not be managed by account API - // features := d.Get("features").(map[string]interface{}) - // account.SetFeatures(features) - return account } - diff --git a/codefresh/resource_api_key.go b/codefresh/resource_api_key.go new file mode 100644 index 00000000..a230f5df --- /dev/null +++ b/codefresh/resource_api_key.go @@ -0,0 +1,172 @@ +package codefresh + +import ( + "errors" + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceApiKey() *schema.Resource { + return &schema.Resource{ + Create: resourceApiKeyCreate, + Read: resourceApiKeyRead, + Update: resourceApiKeyUpdate, + Delete: resourceApiKeyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "account_id": { + Type: schema.TypeString, + Required: true, + }, + "token": { + Type: schema.TypeString, + Computed: true, + }, + "scopes": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func resourceApiKeyCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + apiKey := *mapResourceToApiKey(d) + accountID := d.Get("account_id").(string) + + resp, err := client.CreateApiKey(accountID, &apiKey) + if err != nil { + fmt.Println(string(resp)) + return err + } + + err = d.Set("token", resp) + if err != nil { + return err + } + + client.Token = resp + + apiKeys, err := client.GetApiKeysList() + if err != nil { + return nil + } + + var keyID string + for _, key := range apiKeys { + if key.Name == apiKey.Name { + keyID = key.ID + } + } + + if keyID == "" { + return errors.New("[ERROR] Key ID is not found.") + } + + d.SetId(keyID) + + return nil +} + +func resourceApiKeyRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + keyID := d.Id() + if keyID == "" { + d.SetId("") + return nil + } + + token := d.Get("token").(string) + + if token == "" { + return errors.New("[ERROR] Can't read API Key. Token is empty.") + } + + client.Token = token + + apiKey, err := client.GetAPIKey(keyID) + if err != nil { + return err + } + + err = mapApiKeyToResource(apiKey, d) + if err != nil { + return err + } + + return nil +} + +func resourceApiKeyUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + apiKey := *mapResourceToApiKey(d) + + token := d.Get("token").(string) + if token == "" { + return errors.New("[ERROR] Can't read API Key. Token is empty.") + } + + client.Token = token + + err := client.UpdateAPIKey(&apiKey) + if err != nil { + return err + } + + return nil +} + +func resourceApiKeyDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + token := d.Get("token").(string) + if token == "" { + return errors.New("[ERROR] Can't read API Key. Token is empty.") + } + + err := client.DeleteAPIKey(d.Id()) + if err != nil { + return err + } + + return nil +} + +func mapApiKeyToResource(apiKey *cfClient.ApiKey, d *schema.ResourceData) error { + + err := d.Set("name", apiKey.Name) + if err != nil { + return err + } + + err = d.Set("scopes", apiKey.Scopes) + if err != nil { + return err + } + return nil +} + +func mapResourceToApiKey(d *schema.ResourceData) *cfClient.ApiKey { + scopes := d.Get("scopes").(*schema.Set).List() + apiKey := &cfClient.ApiKey{ + ID: d.Id(), + Name: d.Get("name").(string), + Scopes: convertStringArr(scopes), + } + return apiKey +} \ No newline at end of file diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 597a5026..ab9a0def 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -57,6 +57,7 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) error { } d.SetId(resp.ID) + d.Set("account_id",resp.Account) return nil } @@ -105,14 +106,14 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { usersToAdd, usersToDelete := cfClient.GetUsersDiff(convertStringArr(desiredUsers), existingTeam.Users) - for _, userId := range usersToDelete{ + for _, userId := range usersToDelete { err := client.DeleteUserFromTeam(team.ID, userId) if err != nil { return err } } - for _, userId := range usersToAdd{ + for _, userId := range usersToAdd { err := client.AddUserToTeam(team.ID, userId) if err != nil { return err diff --git a/codefresh/utils.go b/codefresh/utils.go index b0395b9f..c71fb2fc 100644 --- a/codefresh/utils.go +++ b/codefresh/utils.go @@ -25,4 +25,4 @@ func convertVariables(vars []cfClient.Variable) map[string]string { res[v.Key] = v.Value } return res -} \ No newline at end of file +} From 4b95aa101aeec0323d67735e29005cce3e0f6bfd Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Mon, 13 Jul 2020 09:48:15 +0300 Subject: [PATCH 07/32] Add account doc --- docs/resources/account.md | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 docs/resources/account.md diff --git a/docs/resources/account.md b/docs/resources/account.md new file mode 100644 index 00000000..66bfab96 --- /dev/null +++ b/docs/resources/account.md @@ -0,0 +1,58 @@ +# Account resource + +By creating different accounts for different teams within the same company a customer can achieve complete segregation of assets between the teams. +See the [documentation](https://codefresh.io/docs/docs/administration/ent-account-mng/). + +## Example usage + +```hcl +resource "codefresh_account" "test" { + name = "my_account_name" + + + admins = [ + "5efc3cb6355c6647041b6e49", + "5f0acee3b6132b460546c1c6", + "59009221c102763beda7cf04" + ] + + limits { + collaborators = 25 + data_retention_weeks = 5 + } + + build { + parallel = 27 + } + +} +``` + +## Argument Reference + +- `name` - (Required) The display name for the account. +- `admins` - (Optional) A list of users IDs to set them as account admins. +- `limits` - (Optional) A collection of `limits` blocks as documented below. +- `build` - (Optional) A collection of `build` blocks as documented below. + +--- + +`limits` supports the following: +- `collaborators` - (Optional) Max account's collaborators number. +- `data_retention_weeks` -(Optional) How long in weeks will the builds be stored. + +--- + +`build` supports the following: +- `parallel` - (Optional) How many pipelines can be run in parallel. +` `node` - (Optional) Number of nodes. + +## Attributes Reference + +- `id` - The Account ID. + +## Import + +```sh +terraform import codefresh_account.test xxxxxxxxxxxxxxxxxxx +``` From ee583319d610bfe08521e6ece635518e6882f04b Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Mon, 13 Jul 2020 10:23:34 +0300 Subject: [PATCH 08/32] Add api-key doc --- docs/resources/api-key.md | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 docs/resources/api-key.md diff --git a/docs/resources/api-key.md b/docs/resources/api-key.md new file mode 100644 index 00000000..d160f075 --- /dev/null +++ b/docs/resources/api-key.md @@ -0,0 +1,94 @@ +# API Key resource + +By default **terraform-provider-codefresh** uses API key, passed as provider's attribute, but it's possible to generate a new one. +Codefresh API allows to operate only with entities in the current account, which owns the provided API Key. +To be able to operate with entities in different accounts - you should create a new key in the relevant account and use providers [alias](https://www.terraform.io/docs/configuration/providers.html#alias-multiple-provider-instances). + +## Example usage + +```hcl +provider "codefresh" { + api_url = "my API URL" + token = "my init API token" +} + +resource "codefresh_account" "test" { + name = "my new account" +} + +resource "random_string" "random" { + length = 16 + special = false +} + +resource "codefresh_api_key" "new" { + account_id = codefresh_account.test.id + + name = "tfkey_${random_string.random.result}" + + scopes = [ + "agent", + "agents", + "audit", + "build", + "cluster", + "clusters", + "environments-v2", + "github-action", + "helm", + "kubernetes", + "pipeline", + "project", + "repos", + "runner-installation", + "step-type", + "step-types", + "view", + "workflow", + ] +} + +provider "codefresh" { + alias = "new_account" + api_url = "my API URL" + token = codefresh_api_key.new.token +} + + +resource "codefresh_team" "team_1" { + + provider = codefresh.new_account + + name = "team name" +} +``` + +## Argument Reference + +- `name` - (Required) The display name for the API key. +- `account_id` - (Required) The ID of account than should own the new API key. +- `scopes` - (Optional) A list of access scopes, that can be targeted. The possible values: + - `agent` + - `agents` + - `audit` + - `build` + - `cluster` + - `clusters` + - `environments-v2` + - `github-action` + - `helm` + - `kubernetes` + - `pipeline` + - `project` + - `repos` + - `runner-installation` + - `step-type` + - `step-types` + - `view` + - `workflow` + +## Attributes Reference + +- `id` - The Key ID. +- `token` - The Token, that should used as a new provider's token attribute. + From 4c5fc24bdf4d471957d56d54126469291d9cca11 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Mon, 13 Jul 2020 10:41:45 +0300 Subject: [PATCH 09/32] Add team doc --- codefresh/resource_team.go | 2 +- docs/resources/api-key.md | 1 - docs/resources/team.md | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 docs/resources/team.md diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index ab9a0def..5232ca36 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -39,7 +39,7 @@ func resourceTeam() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString,g }, }, }, diff --git a/docs/resources/api-key.md b/docs/resources/api-key.md index d160f075..0417f5b9 100644 --- a/docs/resources/api-key.md +++ b/docs/resources/api-key.md @@ -91,4 +91,3 @@ resource "codefresh_team" "team_1" { - `id` - The Key ID. - `token` - The Token, that should used as a new provider's token attribute. - diff --git a/docs/resources/team.md b/docs/resources/team.md new file mode 100644 index 00000000..72e52622 --- /dev/null +++ b/docs/resources/team.md @@ -0,0 +1,32 @@ +# Team resource + +Team is used as a part of access control and allow to define what teams have access to which clusters and pipelines. +See the [documentation](https://codefresh.io/docs/docs/administration/access-control/). + +## Example usage + +```hcl +resource "codefresh_team" "developers" { + + name = "developers" + + users = [ + "5efc3cb6355c6647041b6e49", + "59009221c102763beda7cf04" + ] +} +``` + +## Argument Reference + +- `name` - (Required) The display name for the team. +- `type` - (Optional) The type of the team. Possible values: + - __default__ + - __admin__ +- `tags` - (Optional) A list of tags to mark a team for easy management. +- `users` - (Optional) A list of user IDs that should be in the team. + +## Attributes Reference + +- `id` - The Team ID. +- `account_id` - The relevant Account ID. \ No newline at end of file From 5bd5cae1125f8a85cad2b86a7d8453e93087d157 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Tue, 14 Jul 2020 15:34:41 +0300 Subject: [PATCH 10/32] Added IDP resource --- client/account.go | 4 +- client/idp.go | 139 ++++++++++++++++++++++++++++ client/team.go | 15 +-- client/user.go | 141 +++++++++++++++++++++++++---- client/utils.go | 9 ++ codefresh/provider.go | 1 + codefresh/resource_account.go | 4 - codefresh/resource_idp_accounts.go | 110 ++++++++++++++++++++++ codefresh/resource_team.go | 2 +- docs/resources/idp-accounts.md | 33 +++++++ 10 files changed, 422 insertions(+), 36 deletions(-) create mode 100644 client/idp.go create mode 100644 codefresh/resource_idp_accounts.go create mode 100644 docs/resources/idp-accounts.md diff --git a/client/account.go b/client/account.go index a8947213..e2e63899 100644 --- a/client/account.go +++ b/client/account.go @@ -217,12 +217,12 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { } existingAccount, err := client.GetAccountByID(id) - if err != nil { + if err != nil { return nil, err } err = mergo.Merge(account, existingAccount) - if err != nil { + if err != nil { return nil, err } diff --git a/client/idp.go b/client/idp.go new file mode 100644 index 00000000..f730b32c --- /dev/null +++ b/client/idp.go @@ -0,0 +1,139 @@ +package client + +import ( + "errors" + "fmt" +) + +type IDP struct { + Access_token string `json:"access_token,omitempty"` + Accounts []string `json:"accounts,omitempty"` + ApiHost string `json:"apiHost,omitempty"` + ApiPathPrefix string `json:"apiPathPrefix,omitempty"` + ApiURL string `json:"apiURL,omitempty"` + AppId string `json:"appId,omitempty"` + AuthURL string `json:"authURL,omitempty"` + ClientHost string `json:"clientHost,omitempty"` + ClientId string `json:"clientId,omitempty"` + ClientName string `json:"clientName,omitempty"` + ClientSecret string `json:"clientSecret,omitempty"` + ClientType string `json:"clientType,omitempty"` + CookieIv string `json:"cookieIv,omitempty"` + CookieKey string `json:"cookieKey,omitempty"` + DisplayName string `json:"displayName,omitempty"` + ID string `json:"id,omitempty"` + IDPLoginUrl string `json:"IDPLoginUrl,omitempty"` + LoginUrl string `json:"loginUrl,omitempty"` + RedirectUiUrl string `json:"redirectUiUrl,omitempty"` + RedirectUrl string `json:"redirectUrl,omitempty"` + RefreshTokenURL string `json:"refreshTokenURL,omitempty"` + Scopes []string `json:"scopes,omitempty"` + Tenant string `json:"tenant,omitempty"` + TokenSecret string `json:"tokenSecret,omitempty"` + TokenURL string `json:"tokenURL,omitempty"` + UserProfileURL string `json:"userProfileURL,omitempty"` +} + +// get all idps +func (client *Client) GetIDPs() (*[]IDP, error) { + fullPath := "/admin/idp" + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var idps []IDP + + err = DecodeResponseInto(resp, &idps) + if err != nil { + return nil, err + } + + return &idps, nil +} + +// get idp id by idp name +func (client *Client) GetIdpByName(idpName string) (*IDP, error) { + + idpList, err := client.GetIDPs() + if err != nil { + return nil, err + } + + for _, idp := range *idpList { + if idp.ClientName == idpName { + return &idp, nil + } + } + + return nil, errors.New(fmt.Sprintf("[ERROR] IDP with name %s isn't found.", idpName )) +} + +func (client *Client) GetIdpByID(idpID string) (*IDP, error) { + + idpList, err := client.GetIDPs() + if err != nil { + return nil, err + } + + for _, idp := range *idpList { + if idp.ID == idpID{ + return &idp, nil + } + } + + return nil, errors.New(fmt.Sprintf("[ERROR] IDP with ID %s isn't found.", idpID)) +} + + +// get account idps +func (client *Client) GetAccountIDPs() (*[]IDP, error) { + fullPath := "/idp/account" + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var idps []IDP + + err = DecodeResponseInto(resp, &idps) + if err != nil { + return nil, err + } + + return &idps, nil +} + +// add account to idp +func (client *Client) AddAccountToIDP(accountId, idpId string) error { + + body := fmt.Sprintf(`{"accountId":"%s","IDPConfigId":"%s"}`, accountId, idpId) + + opts := RequestOptions{ + Path: "/admin/idp/addAccount", + Method: "POST", + Body: []byte(body), + } + + _, err := client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} + +// remove account form idp +// doesn't implemente diff --git a/client/team.go b/client/team.go index 7aa09f33..36fa2f91 100644 --- a/client/team.go +++ b/client/team.go @@ -242,27 +242,18 @@ func GetUsersDiff(desiredUsers []string, existingUsers []TeamUser) (usersToAdd [ } for _, id := range existingUsersIDs { - ok := find(desiredUsers, id) + ok := FindInSlice(desiredUsers, id) if !ok { usersToDelete = append(usersToDelete, id) } } for _, id := range desiredUsers { - ok := find(existingUsersIDs, id) + ok := FindInSlice(existingUsersIDs, id) if !ok { usersToAdd = append(usersToAdd, id) } } return usersToAdd, usersToDelete -} - -func find(slice []string, val string) bool { - for _, item := range slice { - if item == val { - return true - } - } - return false -} +} \ No newline at end of file diff --git a/client/user.go b/client/user.go index a0f22422..bb23c3c2 100644 --- a/client/user.go +++ b/client/user.go @@ -2,25 +2,52 @@ package client import "fmt" +type Credentials struct { + Permissions []string `json:"permissions,omitempty"` +} + +type Login struct { + Credentials Credentials `json:"credentials,omitempty"` + PersonalGit bool `json:"personalGit,omitempty"` + Permissions []string `json:"permissions,omitempty"` + IDP IDP `json:"idp,omitempty"` +} + +type ShortProfile struct { + UserName string `json:"userName,omitempty"` +} + +type Personal struct { + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` + CompanyName string `json:"companyName,omitempty"` + PhoneNumber string `json:"phoneNumber,omitempty"` + Country string `json:"country,omitempty"` +} + type User struct { - ID string `json:"_id"` + ID string `json:"_id,omitempty"` UserName string `json:"userName"` Email string `json:"email"` - Roles []interface{} `json:"roles"` - DefaultAccount int `json:"defaultAccount"` - Account []Account `json:"account"` - Status string `json:"status"` - RegisterDate string `json:"register_date"` - HasPassword bool `json:"hasPassword"` - Notifications []NotificationEvent `json:"notifications"` - ShortProfile struct { - UserName string `json:"userName"` - } `json:"shortProfile"` - Settings struct { - SendWeeklyReport bool `json:"sendWeeklyReport"` - } `json:"settings"` - Logins []interface{} `json:"logins"` - InviteURL string `json:"inviteUrl"` + Personal Personal `json:"personal,omitempty"` + Roles []string `json:"roles,omitempty"` + DefaultAccount int `json:"defaultAccount,omitempty"` + Account []Account `json:"account,omitempty"` + Status string `json:"status,omitempty"` + RegisterDate string `json:"register_date,omitempty"` + HasPassword bool `json:"hasPassword,omitempty"` + Notifications []NotificationEvent `json:"notifications,omitempty"` + ShortProfile ShortProfile `json:"shortProfile,omitempty"` + Logins []Login `json:"logins,omitempty"` + InviteURL string `json:"inviteUrl,omitempty"` +} + +type NewUser struct { + UserName string `json:"userName"` + Email string `json:"email"` + Logins []Login `json:"logins,omitempty"` + Roles []string `json:"roles,omitempty"` + Account []string `json:"account,omitempty"` } func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { @@ -50,6 +77,33 @@ func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) return &user, nil } +func (client *Client) AddPendingUser(user *NewUser) (*User, error) { + + body, err := EncodeToJSON(user) + if err != nil { + return nil, err + } + opts := RequestOptions{ + Path: "/admin/accounts/addpendinguser", + Method: "POST", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var respUser User + + err = DecodeResponseInto(resp, &respUser) + if err != nil { + return nil, err + } + + return &respUser, nil +} + func (client *Client) ActivateUser(userId string) (*User, error) { opts := RequestOptions{ @@ -86,4 +140,57 @@ func (client *Client) SetUserAsAccountAdmin(accountId, userId string) error { } return nil -} \ No newline at end of file +} + +func (client *Client) DeleteUserAsAccountAdmin(accountId, userId string) error { + + opts := RequestOptions{ + Path: fmt.Sprintf("/accounts/%s/%s/admin", accountId, userId), + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} + +func (client *Client) ListUsers() (*[]User, error) { + + opts := RequestOptions{ + Path: "/admin/user", + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var users []User + + err = DecodeResponseInto(resp, &users) + if err != nil { + return nil, err + } + + return &users, nil +} + +func (client *Client) DeleteUser(userName string) error { + + opts := RequestOptions{ + Path: fmt.Sprintf("/admi/user/%s", userName), + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} + diff --git a/client/utils.go b/client/utils.go index 0ee5e3ee..60a97c60 100644 --- a/client/utils.go +++ b/client/utils.go @@ -10,3 +10,12 @@ type Variable struct { type CodefreshObject interface { GetID() string } + +func FindInSlice(slice []string, val string) bool { + for _, item := range slice { + if item == val { + return true + } + } + return false +} diff --git a/codefresh/provider.go b/codefresh/provider.go index 6fbf6e32..098dd5d5 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -32,6 +32,7 @@ func Provider() terraform.ResourceProvider { "codefresh_team": resourceTeam(), "codefresh_account": resourceAccount(), "codefresh_api_key": resourceApiKey(), + "codefresh_idp_accounts": resourceIDPAccounts(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index e1f00dd5..1c9dd67b 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -112,10 +112,6 @@ func resourceAccountUpdate(d *schema.ResourceData, meta interface{}) error { return err } - // TODO - // - rename account - // - add/remove admins - return nil } diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go new file mode 100644 index 00000000..43921a87 --- /dev/null +++ b/codefresh/resource_idp_accounts.go @@ -0,0 +1,110 @@ +package codefresh + +import ( + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceIDPAccounts() *schema.Resource { + return &schema.Resource{ + Create: resourceAccountIDPCreate, + Read: resourceAccountIDPRead, + Update: resourceAccountIDPUpdate, + Delete: resourceAccountIDPDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "idp": { + Type: schema.TypeString, + Required: true, + }, + "accounts": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func resourceAccountIDPCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + accounts:= convertStringArr(d.Get("accounts").(*schema.Set).List()) + + idpName := d.Get("idp").(string) + + idp, err := client.GetIdpByName(idpName) + if err != nil { + return err + } + + for _, account := range accounts { + client.AddAccountToIDP(account, idp.ID) + } + + d.SetId(idp.ID) + + return nil +} + +func resourceAccountIDPRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + idpID := d.Id() + if idpID == "" { + d.SetId("") + return nil + } + + idp, err := client.GetIdpByID(idpID) + if err != nil { + return err + } + + err = d.Set("idp", idp.ClientName) + if err != nil { + return err + } + + err = d.Set("accounts", idp.Accounts) + if err != nil { + return err + } + + return nil +} + + +func resourceAccountIDPDelete(_ *schema.ResourceData, _ interface{}) error { + return nil +} + +func resourceAccountIDPUpdate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + idpID := d.Id() + + idp, err := client.GetIdpByID(idpID) + if err != nil { + return err + } + + existingAccounts := idp.Accounts + + desiredAccounts := convertStringArr(d.Get("accounts").(*schema.Set).List()) + + for _, account := range desiredAccounts { + if ok := cfClient.FindInSlice(existingAccounts, account); !ok { + client.AddAccountToIDP(account, idp.ID) + } + } + + return nil +} \ No newline at end of file diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 5232ca36..ab9a0def 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -39,7 +39,7 @@ func resourceTeam() *schema.Resource { Type: schema.TypeSet, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString,g + Type: schema.TypeString, }, }, }, diff --git a/docs/resources/idp-accounts.md b/docs/resources/idp-accounts.md new file mode 100644 index 00000000..e196bd16 --- /dev/null +++ b/docs/resources/idp-accounts.md @@ -0,0 +1,33 @@ +# IDP Admins resource + +The resource adds the list of provided account IDs to the IDP. +Because of the current Codefresh API limitation it's impossible to remove account from IDP, only adding is supporting. + +## Example usage + +```hcl +resource "codefresh_account" "test" { + name = "" +} + +resource "codefresh_idp_accounts" "test" { + + idp = "azure" + + accounts = [ + codefresh_account.test.id, + "" + ] +} +``` + +## Argument Reference + +- `idp` - (Required) The IDP client name. +- `accounts` - (Required) A list of account IDs. + +## Import + +```sh +terraform import codefresh_idp_accounts.test xxxxxxxxxxxxxxxxxxx +``` From e110d81dc550bed5a9f1fa2b59dc12b1f73076b1 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Wed, 15 Jul 2020 11:14:11 +0300 Subject: [PATCH 11/32] Add data users --- client/idp.go | 7 +- client/team.go | 2 +- client/user.go | 9 +- codefresh/data_users.go | 195 +++++++++++++++++++++++++++++ codefresh/provider.go | 15 ++- codefresh/resource_api_key.go | 2 +- codefresh/resource_idp_accounts.go | 5 +- codefresh/resource_team.go | 2 +- 8 files changed, 216 insertions(+), 21 deletions(-) create mode 100644 codefresh/data_users.go diff --git a/client/idp.go b/client/idp.go index f730b32c..674e5a75 100644 --- a/client/idp.go +++ b/client/idp.go @@ -72,7 +72,7 @@ func (client *Client) GetIdpByName(idpName string) (*IDP, error) { } } - return nil, errors.New(fmt.Sprintf("[ERROR] IDP with name %s isn't found.", idpName )) + return nil, errors.New(fmt.Sprintf("[ERROR] IDP with name %s isn't found.", idpName)) } func (client *Client) GetIdpByID(idpID string) (*IDP, error) { @@ -83,7 +83,7 @@ func (client *Client) GetIdpByID(idpID string) (*IDP, error) { } for _, idp := range *idpList { - if idp.ID == idpID{ + if idp.ID == idpID { return &idp, nil } } @@ -91,7 +91,6 @@ func (client *Client) GetIdpByID(idpID string) (*IDP, error) { return nil, errors.New(fmt.Sprintf("[ERROR] IDP with ID %s isn't found.", idpID)) } - // get account idps func (client *Client) GetAccountIDPs() (*[]IDP, error) { fullPath := "/idp/account" @@ -124,7 +123,7 @@ func (client *Client) AddAccountToIDP(accountId, idpId string) error { opts := RequestOptions{ Path: "/admin/idp/addAccount", Method: "POST", - Body: []byte(body), + Body: []byte(body), } _, err := client.RequestAPI(&opts) diff --git a/client/team.go b/client/team.go index 36fa2f91..251fdbe2 100644 --- a/client/team.go +++ b/client/team.go @@ -256,4 +256,4 @@ func GetUsersDiff(desiredUsers []string, existingUsers []TeamUser) (usersToAdd [ } return usersToAdd, usersToDelete -} \ No newline at end of file +} diff --git a/client/user.go b/client/user.go index bb23c3c2..05285e91 100644 --- a/client/user.go +++ b/client/user.go @@ -18,18 +18,18 @@ type ShortProfile struct { } type Personal struct { - FirstName string `json:"firstName,omitempty"` - LastName string `json:"lastName,omitempty"` + FirstName string `json:"firstName,omitempty"` + LastName string `json:"lastName,omitempty"` CompanyName string `json:"companyName,omitempty"` PhoneNumber string `json:"phoneNumber,omitempty"` - Country string `json:"country,omitempty"` + Country string `json:"country,omitempty"` } type User struct { ID string `json:"_id,omitempty"` UserName string `json:"userName"` Email string `json:"email"` - Personal Personal `json:"personal,omitempty"` + Personal *Personal `json:"personal,omitempty"` Roles []string `json:"roles,omitempty"` DefaultAccount int `json:"defaultAccount,omitempty"` Account []Account `json:"account,omitempty"` @@ -193,4 +193,3 @@ func (client *Client) DeleteUser(userName string) error { return nil } - diff --git a/codefresh/data_users.go b/codefresh/data_users.go new file mode 100644 index 00000000..41dfe2fa --- /dev/null +++ b/codefresh/data_users.go @@ -0,0 +1,195 @@ +package codefresh + +import ( + "errors" + "fmt" + + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceUsers() *schema.Resource { + return &schema.Resource{ + Read: dataSourceUsersRead, + + Schema: map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Required: true, + }, + "personal": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "first_name": { + Type: schema.TypeString, + Optional: true, + }, + "last_name": { + Type: schema.TypeString, + Optional: true, + }, + "company_name": { + Type: schema.TypeString, + Optional: true, + }, + "phone_number": { + Type: schema.TypeString, + Optional: true, + }, + "country": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "short_profile": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "roles": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "logins": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "permissions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "idp": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + "client_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + users, err := client.ListUsers() + if err != nil { + return err + } + + email := d.Get("email").(string) + + for _, user := range *users { + if user.Email == email { + err = mapDataUsersToResource(user, d) + if err != nil { + return err + } + } + } + + if d.Id() == "" { + return errors.New(fmt.Sprintf("[EROOR] User %s wasn't found", email)) + } + + return nil +} + +func mapDataUsersToResource(user cfClient.User, d *schema.ResourceData) error { + + d.SetId(user.ID) + d.Set("user_name", user.UserName) + d.Set("email", user.Email) + d.Set("status", user.Status) + if user.Personal != nil { + d.Set("personal", flattenPersonal(user.Personal)) + } + d.Set("short_profile", + []map[string]interface{}{ + {"user_name": user.ShortProfile.UserName}, + }) + d.Set("roles", user.Roles) + d.Set("logins", flattenLogins(&user.Logins)) + + return nil +} + +func flattenPersonal(personal *cfClient.Personal) []map[string]interface{} { + return []map[string]interface{}{ + { + "first_name": personal.FirstName, + "last_name": personal.LastName, + "company_name": personal.CompanyName, + "phone_number": personal.PhoneNumber, + "country": personal.Country, + }, + } +} + +func flattenLogins(logins *[]cfClient.Login) []map[string]interface{} { + + var res = make([]map[string]interface{}, len(*logins)) + for i, login := range *logins { + m := make(map[string]interface{}) + m["credentials"] = []map[string]interface{}{ + {"permissions": login.Credentials.Permissions}} + + m["idp"] = []map[string]interface{}{ + { + "id": login.IDP.ID, + "client_type": login.IDP.ClientType, + }, + } + + res[i] = m + } + + return res +} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index 098dd5d5..f17251f7 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -26,13 +26,16 @@ func Provider() terraform.ResourceProvider { DefaultFunc: schema.EnvDefaultFunc("CODEFRESH_API_KEY", ""), }, }, + DataSourcesMap: map[string]*schema.Resource{ + "codefresh_users": dataSourceUsers(), + }, ResourcesMap: map[string]*schema.Resource{ - "codefresh_project": resourceProject(), - "codefresh_pipeline": resourcePipeline(), - "codefresh_team": resourceTeam(), - "codefresh_account": resourceAccount(), - "codefresh_api_key": resourceApiKey(), - "codefresh_idp_accounts": resourceIDPAccounts(), + "codefresh_project": resourceProject(), + "codefresh_pipeline": resourcePipeline(), + "codefresh_team": resourceTeam(), + "codefresh_account": resourceAccount(), + "codefresh_api_key": resourceApiKey(), + "codefresh_idp_accounts": resourceIDPAccounts(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_api_key.go b/codefresh/resource_api_key.go index a230f5df..eddb6c92 100644 --- a/codefresh/resource_api_key.go +++ b/codefresh/resource_api_key.go @@ -169,4 +169,4 @@ func mapResourceToApiKey(d *schema.ResourceData) *cfClient.ApiKey { Scopes: convertStringArr(scopes), } return apiKey -} \ No newline at end of file +} diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go index 43921a87..ed7acb07 100644 --- a/codefresh/resource_idp_accounts.go +++ b/codefresh/resource_idp_accounts.go @@ -34,7 +34,7 @@ func resourceAccountIDPCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*cfClient.Client) - accounts:= convertStringArr(d.Get("accounts").(*schema.Set).List()) + accounts := convertStringArr(d.Get("accounts").(*schema.Set).List()) idpName := d.Get("idp").(string) @@ -80,7 +80,6 @@ func resourceAccountIDPRead(d *schema.ResourceData, meta interface{}) error { return nil } - func resourceAccountIDPDelete(_ *schema.ResourceData, _ interface{}) error { return nil } @@ -107,4 +106,4 @@ func resourceAccountIDPUpdate(d *schema.ResourceData, meta interface{}) error { } return nil -} \ No newline at end of file +} diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index ab9a0def..22dbc006 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -57,7 +57,7 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) error { } d.SetId(resp.ID) - d.Set("account_id",resp.Account) + d.Set("account_id", resp.Account) return nil } From 76379ac35c42ad648c81b8fce16c48314bc28dfa Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Wed, 15 Jul 2020 12:39:30 +0300 Subject: [PATCH 12/32] Update data users --- codefresh/data_users.go | 196 +++++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 95 deletions(-) diff --git a/codefresh/data_users.go b/codefresh/data_users.go index 41dfe2fa..3cd45919 100644 --- a/codefresh/data_users.go +++ b/codefresh/data_users.go @@ -1,9 +1,7 @@ package codefresh import ( - "errors" - "fmt" - + "time" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -13,97 +11,110 @@ func dataSourceUsers() *schema.Resource { Read: dataSourceUsersRead, Schema: map[string]*schema.Schema{ - "user_name": { - Type: schema.TypeString, - Computed: true, - }, - "email": { - Type: schema.TypeString, - Required: true, - }, - "personal": { + + "users": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "first_name": { - Type: schema.TypeString, - Optional: true, - }, - "last_name": { - Type: schema.TypeString, - Optional: true, - }, - "company_name": { + "user_name": { Type: schema.TypeString, - Optional: true, + Computed: true, }, - "phone_number": { + "email": { Type: schema.TypeString, - Optional: true, + Computed: true, }, - "country": { + "id": { Type: schema.TypeString, - Optional: true, + Computed: true, }, - }, - }, - }, - "short_profile": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "user_name": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "roles": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "logins": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "credentials": { + "personal": { Type: schema.TypeList, - Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "permissions": { - Type: schema.TypeSet, + "first_name": { + Type: schema.TypeString, + Optional: true, + }, + "last_name": { + Type: schema.TypeString, + Optional: true, + }, + "company_name": { + Type: schema.TypeString, + Optional: true, + }, + "phone_number": { + Type: schema.TypeString, + Optional: true, + }, + "country": { + Type: schema.TypeString, Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, }, }, }, }, - "idp": { + "short_profile": { Type: schema.TypeList, - Optional: true, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "id": { + "user_name": { Type: schema.TypeString, Optional: true, }, - "client_type": { - Type: schema.TypeString, + }, + }, + }, + "roles": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "logins": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials": { + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "permissions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "idp": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + "client_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, }, }, }, @@ -124,39 +135,34 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error { return err } - email := d.Get("email").(string) + err = mapDataUsersToResource(*users, d) - for _, user := range *users { - if user.Email == email { - err = mapDataUsersToResource(user, d) - if err != nil { - return err - } - } - } - - if d.Id() == "" { - return errors.New(fmt.Sprintf("[EROOR] User %s wasn't found", email)) - } + d.SetId(time.Now().UTC().String()) return nil } -func mapDataUsersToResource(user cfClient.User, d *schema.ResourceData) error { +func mapDataUsersToResource(users []cfClient.User, d *schema.ResourceData) error { + + var res = make([]map[string]interface{}, len(users)) + for i, user := range users { + m := make(map[string]interface{}) + m["user_name"] = user.UserName + m["email"] = user.Email + m["status"] = user.Status + if user.Personal != nil { + m["personal"] = flattenPersonal(user.Personal) + } + m["short_profile"] = []map[string]interface{}{ + {"user_name": user.ShortProfile.UserName},} + m["roles"] = user.Roles + m["logins"] = flattenLogins(&user.Logins) + m["id"] = user.ID - d.SetId(user.ID) - d.Set("user_name", user.UserName) - d.Set("email", user.Email) - d.Set("status", user.Status) - if user.Personal != nil { - d.Set("personal", flattenPersonal(user.Personal)) + res[i] = m } - d.Set("short_profile", - []map[string]interface{}{ - {"user_name": user.ShortProfile.UserName}, - }) - d.Set("roles", user.Roles) - d.Set("logins", flattenLogins(&user.Logins)) + + d.Set("users", res) return nil } From 5ed40b2fdf372028eb8dbee80aa8cb3feb65bfa5 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Wed, 15 Jul 2020 13:01:07 +0300 Subject: [PATCH 13/32] Split data users to user and users --- codefresh/data_user.go | 202 ++++++++++++++++++++++++++++++++++++++++ codefresh/data_users.go | 146 +---------------------------- codefresh/provider.go | 1 + 3 files changed, 207 insertions(+), 142 deletions(-) create mode 100644 codefresh/data_user.go diff --git a/codefresh/data_user.go b/codefresh/data_user.go new file mode 100644 index 00000000..989aa60c --- /dev/null +++ b/codefresh/data_user.go @@ -0,0 +1,202 @@ +package codefresh + +import ( + "errors" + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceUser() *schema.Resource { + return &schema.Resource{ + Read: dataSourceUserRead, + Schema: *UserSchema(), + } +} + +func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + users, err := client.ListUsers() + if err != nil { + return err + } + + email := d.Get("email").(string) + + for _, user := range *users { + if user.Email == email { + err = mapDataUserToResource(user, d) + if err != nil { + return err + } + } + } + + if d.Id() == "" { + return errors.New(fmt.Sprintf("[EROOR] User %s wasn't found", email)) + } + + return nil +} + +func mapDataUserToResource(user cfClient.User, d *schema.ResourceData) error { + + d.SetId(user.ID) + d.Set("user_id", user.ID) + d.Set("user_name", user.UserName) + d.Set("email", user.Email) + d.Set("status", user.Status) + if user.Personal != nil { + d.Set("personal", flattenPersonal(user.Personal)) + } + d.Set("short_profile", + []map[string]interface{}{ + {"user_name": user.ShortProfile.UserName}, + }) + d.Set("roles", user.Roles) + d.Set("logins", flattenLogins(&user.Logins)) + + return nil +} + +func flattenPersonal(personal *cfClient.Personal) []map[string]interface{} { + return []map[string]interface{}{ + { + "first_name": personal.FirstName, + "last_name": personal.LastName, + "company_name": personal.CompanyName, + "phone_number": personal.PhoneNumber, + "country": personal.Country, + }, + } +} + +func flattenLogins(logins *[]cfClient.Login) []map[string]interface{} { + + var res = make([]map[string]interface{}, len(*logins)) + for i, login := range *logins { + m := make(map[string]interface{}) + m["credentials"] = []map[string]interface{}{ + {"permissions": login.Credentials.Permissions}} + + m["idp"] = []map[string]interface{}{ + { + "id": login.IDP.ID, + "client_type": login.IDP.ClientType, + }, + } + + res[i] = m + } + + return res +} + +func UserSchema() *map[string]*schema.Schema { + return &map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Required: true, + }, + "user_id": { + Type: schema.TypeString, + Computed: true, + }, + "personal": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "first_name": { + Type: schema.TypeString, + Optional: true, + }, + "last_name": { + Type: schema.TypeString, + Optional: true, + }, + "company_name": { + Type: schema.TypeString, + Optional: true, + }, + "phone_number": { + Type: schema.TypeString, + Optional: true, + }, + "country": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "short_profile": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "roles": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "logins": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "permissions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "idp": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + }, + "client_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/codefresh/data_users.go b/codefresh/data_users.go index 3cd45919..a74dee69 100644 --- a/codefresh/data_users.go +++ b/codefresh/data_users.go @@ -1,125 +1,20 @@ package codefresh import ( - "time" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "time" ) func dataSourceUsers() *schema.Resource { return &schema.Resource{ Read: dataSourceUsersRead, - Schema: map[string]*schema.Schema{ - "users": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "user_name": { - Type: schema.TypeString, - Computed: true, - }, - "email": { - Type: schema.TypeString, - Computed: true, - }, - "id": { - Type: schema.TypeString, - Computed: true, - }, - "personal": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "first_name": { - Type: schema.TypeString, - Optional: true, - }, - "last_name": { - Type: schema.TypeString, - Optional: true, - }, - "company_name": { - Type: schema.TypeString, - Optional: true, - }, - "phone_number": { - Type: schema.TypeString, - Optional: true, - }, - "country": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "short_profile": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "user_name": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - "roles": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "status": { - Type: schema.TypeString, - Computed: true, - }, - "logins": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "credentials": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "permissions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, - }, - "idp": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Optional: true, - }, - "client_type": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - }, - }, - }, - }, + Schema: *UserSchema(), }, }, }, @@ -154,10 +49,10 @@ func mapDataUsersToResource(users []cfClient.User, d *schema.ResourceData) error m["personal"] = flattenPersonal(user.Personal) } m["short_profile"] = []map[string]interface{}{ - {"user_name": user.ShortProfile.UserName},} + {"user_name": user.ShortProfile.UserName}} m["roles"] = user.Roles m["logins"] = flattenLogins(&user.Logins) - m["id"] = user.ID + m["user_id"] = user.ID res[i] = m } @@ -166,36 +61,3 @@ func mapDataUsersToResource(users []cfClient.User, d *schema.ResourceData) error return nil } - -func flattenPersonal(personal *cfClient.Personal) []map[string]interface{} { - return []map[string]interface{}{ - { - "first_name": personal.FirstName, - "last_name": personal.LastName, - "company_name": personal.CompanyName, - "phone_number": personal.PhoneNumber, - "country": personal.Country, - }, - } -} - -func flattenLogins(logins *[]cfClient.Login) []map[string]interface{} { - - var res = make([]map[string]interface{}, len(*logins)) - for i, login := range *logins { - m := make(map[string]interface{}) - m["credentials"] = []map[string]interface{}{ - {"permissions": login.Credentials.Permissions}} - - m["idp"] = []map[string]interface{}{ - { - "id": login.IDP.ID, - "client_type": login.IDP.ClientType, - }, - } - - res[i] = m - } - - return res -} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index f17251f7..13a7972e 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -28,6 +28,7 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ "codefresh_users": dataSourceUsers(), + "codefresh_user": dataSourceUser(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), From 9e9f1ae06d05616d0c7c33646403fa1fdd15b249 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Wed, 15 Jul 2020 13:29:04 +0300 Subject: [PATCH 14/32] Add user data docs --- docs/data/user.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++ docs/data/users.md | 14 +++++++++++ 2 files changed, 73 insertions(+) create mode 100644 docs/data/user.md create mode 100644 docs/data/users.md diff --git a/docs/data/user.md b/docs/data/user.md new file mode 100644 index 00000000..2f1d2ef6 --- /dev/null +++ b/docs/data/user.md @@ -0,0 +1,59 @@ +# User Data Source + +Use this data source to get the User from existing users for use in other resources. + +## Example usage + +```hcl +data "codefresh_user" "admin" { + email = "admin@codefresh.io" +} + +resource "codefresh_team" "admins" { + + name = "testsuperteam123" + + users = [ + data.codefresh_user.admin.user_id, + "", + ] +} +``` + +## Argument Reference + +- `email` - (Required) The email of user to filter. + +## Attributes Reference + +- `user_name`. +- `email`. +- `user_id`. +- `personal`. A collection of `personal` blocks as documented below. +- `short_profile`. A collection of `short_profile` blocks as documented below. +- `roles`. A list of roles. +- `status`. User status - `new`, `pending`, etc. +- `logins`. A collection of `short_profile` blocks as documented below. + +--- + +`personal` includes the following: +- `first_name`. +- `last_name`. +- `company_name`. +- `phone_number`. +- `country`. + +--- + +`short_profile` includes the following: +- `user_name`. + +--- + +`logins` includes the following: +- `credentials` + - `permissions` +- `idp` + - `id` + - `client_type \ No newline at end of file diff --git a/docs/data/users.md b/docs/data/users.md new file mode 100644 index 00000000..30e39257 --- /dev/null +++ b/docs/data/users.md @@ -0,0 +1,14 @@ +`# Users Data Source + +Use this data source to get all existing users from Codefresh. + +## Example usage + +```hcl +data "codefresh_users" "users" {} +} +``` + +## Attributes Reference + +- `users` - A list of [user](./user.md) \ No newline at end of file From bf618e4375e8fb4b922f63fd8a9a8ded124b8464 Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Fri, 17 Jul 2020 11:34:48 +0300 Subject: [PATCH 15/32] Add account_admins resource --- client/account.go | 21 +++++ client/user.go | 78 ++++++++++++++++- codefresh/data_user.go | 4 +- codefresh/data_users.go | 2 +- codefresh/provider.go | 13 +-- codefresh/resource_account.go | 26 +++--- codefresh/resource_account_admins.go | 121 +++++++++++++++++++++++++++ codefresh/resource_idp_accounts.go | 2 + docs/resources/account-admins.md | 65 ++++++++++++++ docs/resources/account.md | 8 -- 10 files changed, 307 insertions(+), 33 deletions(-) create mode 100644 codefresh/resource_account_admins.go create mode 100644 docs/resources/account-admins.md diff --git a/client/account.go b/client/account.go index e2e63899..a47c3a42 100644 --- a/client/account.go +++ b/client/account.go @@ -270,3 +270,24 @@ func (client *Client) DeleteAccount(id string) error { return nil } + +func GetAccountAdminsDiff(desiredAdmins []string, existingAdmins []string) (adminsToAdd []string, adminsToDelete []string) { + + adminsToAdd = []string{} + adminsToDelete = []string{} + + for _, id := range existingAdmins { + if ok := FindInSlice(desiredAdmins, id); !ok { + adminsToDelete = append(adminsToDelete, id) + } + } + + for _, id := range desiredAdmins { + + if ok := FindInSlice(existingAdmins, id); !ok { + adminsToAdd = append(adminsToAdd, id) + } + } + + return adminsToAdd, adminsToDelete +} diff --git a/client/user.go b/client/user.go index 05285e91..34a8767e 100644 --- a/client/user.go +++ b/client/user.go @@ -1,6 +1,9 @@ package client -import "fmt" +import ( + "errors" + "fmt" +) type Credentials struct { Permissions []string `json:"permissions,omitempty"` @@ -50,6 +53,11 @@ type NewUser struct { Account []string `json:"account,omitempty"` } +type UserAccounts struct { + UserName string `json:"userName` + Account []Account `json:"account` +} + func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { userDetails := fmt.Sprintf(`{"userName": "%s", "email": "%s"}`, userName, userEmail) @@ -157,7 +165,7 @@ func (client *Client) DeleteUserAsAccountAdmin(accountId, userId string) error { return nil } -func (client *Client) ListUsers() (*[]User, error) { +func (client *Client) GetAllUsers() (*[]User, error) { opts := RequestOptions{ Path: "/admin/user", @@ -179,10 +187,41 @@ func (client *Client) ListUsers() (*[]User, error) { return &users, nil } +func (client *Client) GetUserByID(userId string) (*User, error) { + + users, err := client.GetAllUsers() + if err != nil { + return nil, err + } + + for _, user := range *users { + if user.ID == userId { + return &user, nil + } + } + + return nil, errors.New(fmt.Sprint("[ERROR] User with ID %s wasn't found.", userId)) +} + func (client *Client) DeleteUser(userName string) error { opts := RequestOptions{ - Path: fmt.Sprintf("/admi/user/%s", userName), + Path: fmt.Sprintf("/admin/user/%s", userName), + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} + +func (client *Client) DeleteUserFromAccount(accountId, userId string) error { + + opts := RequestOptions{ + Path: fmt.Sprintf("/accounts/%s/%s", accountId, userId), Method: "DELETE", } @@ -193,3 +232,36 @@ func (client *Client) DeleteUser(userName string) error { return nil } + +func (client *Client) UpdateUserAccounts(userId string, accounts []Account) error { + + // API call '/accounts/{accountId}/{userId}/adduser' doesn't work + + user, err := client.GetUserByID(userId) + if err != nil { + return err + } + + postUser := UserAccounts{ + UserName: user.UserName, + Account: accounts, + } + + body, err := EncodeToJSON(postUser) + if err != nil { + return err + } + + opts := RequestOptions{ + Path: "/admin/user/account", + Method: "POST", + Body: body, + } + + _, err = client.RequestAPI(&opts) + if err != nil { + return err + } + + return nil +} diff --git a/codefresh/data_user.go b/codefresh/data_user.go index 989aa60c..73c57dfd 100644 --- a/codefresh/data_user.go +++ b/codefresh/data_user.go @@ -9,7 +9,7 @@ import ( func dataSourceUser() *schema.Resource { return &schema.Resource{ - Read: dataSourceUserRead, + Read: dataSourceUserRead, Schema: *UserSchema(), } } @@ -18,7 +18,7 @@ func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*cfClient.Client) - users, err := client.ListUsers() + users, err := client.GetAllUsers() if err != nil { return err } diff --git a/codefresh/data_users.go b/codefresh/data_users.go index a74dee69..ececb7ec 100644 --- a/codefresh/data_users.go +++ b/codefresh/data_users.go @@ -25,7 +25,7 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*cfClient.Client) - users, err := client.ListUsers() + users, err := client.GetAllUsers() if err != nil { return err } diff --git a/codefresh/provider.go b/codefresh/provider.go index 13a7972e..f948a491 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -31,12 +31,13 @@ func Provider() terraform.ResourceProvider { "codefresh_user": dataSourceUser(), }, ResourcesMap: map[string]*schema.Resource{ - "codefresh_project": resourceProject(), - "codefresh_pipeline": resourcePipeline(), - "codefresh_team": resourceTeam(), - "codefresh_account": resourceAccount(), - "codefresh_api_key": resourceApiKey(), - "codefresh_idp_accounts": resourceIDPAccounts(), + "codefresh_project": resourceProject(), + "codefresh_pipeline": resourcePipeline(), + "codefresh_team": resourceTeam(), + "codefresh_account": resourceAccount(), + "codefresh_api_key": resourceApiKey(), + "codefresh_idp_accounts": resourceIDPAccounts(), + "codefresh_account_admins": resourceAccountAdmins(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index 1c9dd67b..3b5d1093 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -19,13 +19,13 @@ func resourceAccount() *schema.Resource { Type: schema.TypeString, Required: true, }, - "admins": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, + // "admins": { + // Type: schema.TypeSet, + // Optional: true, + // Elem: &schema.Schema{ + // Type: schema.TypeString, + // }, + // }, "limits": { Type: schema.TypeList, Optional: true, @@ -133,10 +133,10 @@ func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) err return err } - err = d.Set("admins", account.Admins) - if err != nil { - return err - } + // err = d.Set("admins", account.Admins) + // if err != nil { + // return err + // } err = d.Set("limits", []map[string]interface{}{flattenLimits(*account.Limits)}) if err != nil { @@ -165,12 +165,12 @@ func flattenBuild(build cfClient.Build) map[string]interface{} { return res } func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { - admins := d.Get("admins").(*schema.Set).List() + // admins := d.Get("admins").(*schema.Set).List() account := &cfClient.Account{ ID: d.Id(), Name: d.Get("name").(string), - Admins: convertStringArr(admins), + // Admins: convertStringArr(admins), } if _, ok := d.GetOk("limits"); ok { diff --git a/codefresh/resource_account_admins.go b/codefresh/resource_account_admins.go new file mode 100644 index 00000000..44c1287b --- /dev/null +++ b/codefresh/resource_account_admins.go @@ -0,0 +1,121 @@ +package codefresh + +import ( + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAccountAdmins() *schema.Resource { + return &schema.Resource{ + Create: resourceAccountAdminsCreate, + Read: resourceAccountAdminsRead, + Update: resourceAccountAdminsUpdate, + Delete: resourceAccountAdminsDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "account_id": { + Type: schema.TypeString, + Required: true, + }, + "users": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func resourceAccountAdminsCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + admins := d.Get("users").(*schema.Set).List() + + accountId := d.Get("account_id").(string) + + for _, admin := range convertStringArr(admins) { + err := client.SetUserAsAccountAdmin(accountId, admin) + if err != nil { + return err + } + } + + // d.SetId(time.Now().UTC().String()) + d.SetId(accountId) + + return nil +} + +func resourceAccountAdminsDelete(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + admins := d.Get("users").(*schema.Set).List() + + accountId := d.Get("account_id").(string) + + for _, admin := range convertStringArr(admins) { + err := client.DeleteUserAsAccountAdmin(accountId, admin) + if err != nil { + return err + } + } + + return nil +} + +func resourceAccountAdminsRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + accountId := d.Id() + + d.Set("account_id", accountId) + + account, err := client.GetAccountByID(accountId) + if err != nil { + return nil + } + err = d.Set("users", account.Admins) + if err != nil { + return err + } + + return nil +} + +func resourceAccountAdminsUpdate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + accountId := d.Get("account_id").(string) + desiredAdmins := d.Get("users").(*schema.Set).List() + + account, err := client.GetAccountByID(accountId) + if err != nil { + return err + } + + adminsToAdd, AdminsToDelete := cfClient.GetAccountAdminsDiff(convertStringArr(desiredAdmins), account.Admins) + + for _, userId := range AdminsToDelete { + err := client.DeleteUserAsAccountAdmin(accountId, userId) + if err != nil { + return err + } + } + + for _, userId := range adminsToAdd { + err := client.SetUserAsAccountAdmin(accountId, userId) + if err != nil { + return err + } + } + + return nil +} diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go index ed7acb07..09b40b0a 100644 --- a/codefresh/resource_idp_accounts.go +++ b/codefresh/resource_idp_accounts.go @@ -81,6 +81,8 @@ func resourceAccountIDPRead(d *schema.ResourceData, meta interface{}) error { } func resourceAccountIDPDelete(_ *schema.ResourceData, _ interface{}) error { + // todo + // warning message return nil } diff --git a/docs/resources/account-admins.md b/docs/resources/account-admins.md new file mode 100644 index 00000000..c6c763b2 --- /dev/null +++ b/docs/resources/account-admins.md @@ -0,0 +1,65 @@ +# Account Admins resource + +Use this resource to set a list of admins for any account. + +## Example usage + +#### Example 1 + +```hcl +resource "codefresh_account_admins" "test" { + + account_id = + + users = [ + , + ] +} +``` + +#### Example 2 + +```hcl +resource "codefresh_account" "test" { + + name = "mynewaccount" + + limits { + collaborators = 25 + data_retention_weeks = 5 + } + + build { + parallel = 2 + } + +} + +data "codefresh_user" "admin" { + email = "" +} + +resource "codefresh_account_admins" "test" { + + account_id = codefresh_account.test.id + + users = [ + data.codefresh_user.admin.user_id + ] +} +``` + +## Argument Reference + +- `account_id` - (Required) The account id where to set up a list of admins. +- `users` - (Required) A list of users to set up as account admins. + +## Attributes Reference + +- `id` - The Account ID. + +## Import + +```sh +terraform import codefresh_account_admins.test xxxxxxxxxxxxxxxxxxx +``` diff --git a/docs/resources/account.md b/docs/resources/account.md index 66bfab96..69b1d3a4 100644 --- a/docs/resources/account.md +++ b/docs/resources/account.md @@ -9,13 +9,6 @@ See the [documentation](https://codefresh.io/docs/docs/administration/ent-accoun resource "codefresh_account" "test" { name = "my_account_name" - - admins = [ - "5efc3cb6355c6647041b6e49", - "5f0acee3b6132b460546c1c6", - "59009221c102763beda7cf04" - ] - limits { collaborators = 25 data_retention_weeks = 5 @@ -31,7 +24,6 @@ resource "codefresh_account" "test" { ## Argument Reference - `name` - (Required) The display name for the account. -- `admins` - (Optional) A list of users IDs to set them as account admins. - `limits` - (Optional) A collection of `limits` blocks as documented below. - `build` - (Optional) A collection of `build` blocks as documented below. From c5490af1df803970680aebd86d1872a2c18d174c Mon Sep 17 00:00:00 2001 From: Pavel Nosovets Date: Fri, 17 Jul 2020 18:24:11 +0300 Subject: [PATCH 16/32] Add user resource --- client/account.go | 42 ++++- client/idp.go | 2 +- client/user.go | 16 +- codefresh/provider.go | 13 +- codefresh/resource_account.go | 4 +- codefresh/resource_user.go | 311 ++++++++++++++++++++++++++++++++++ docs/resources/user.md | 95 +++++++++++ 7 files changed, 466 insertions(+), 17 deletions(-) create mode 100644 codefresh/resource_user.go create mode 100644 docs/resources/user.md diff --git a/client/account.go b/client/account.go index a47c3a42..755570b7 100644 --- a/client/account.go +++ b/client/account.go @@ -3,9 +3,10 @@ package client import ( "errors" "fmt" - "github.com/imdario/mergo" "log" "strconv" + + "github.com/imdario/mergo" ) type DockerRegistry struct { @@ -180,6 +181,45 @@ func (client *Client) GetAccountByID(id string) (*Account, error) { return &account, nil } +func (client *Client) GetAllAccounts() (*[]Account, error) { + + opts := RequestOptions{ + Path: "/admin/accounts", + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var accounts []Account + + err = DecodeResponseInto(resp, &accounts) + if err != nil { + return nil, err + } + + return &accounts, nil +} + +func (client *Client) GetAccountsList(accountsId []string) (*[]Account, error) { + + var accounts []Account + + for _, accountId := range accountsId { + account, err := client.GetAccountByID(accountId) + if err != nil { + return nil, err + } + + accounts = append(accounts, *account) + } + + return &accounts, nil +} + func (client *Client) CreateAccount(account *Account) (*Account, error) { body, err := EncodeToJSON(account) diff --git a/client/idp.go b/client/idp.go index 674e5a75..d1f22c2a 100644 --- a/client/idp.go +++ b/client/idp.go @@ -21,7 +21,7 @@ type IDP struct { CookieIv string `json:"cookieIv,omitempty"` CookieKey string `json:"cookieKey,omitempty"` DisplayName string `json:"displayName,omitempty"` - ID string `json:"id,omitempty"` + ID string `json:"_id,omitempty"` IDPLoginUrl string `json:"IDPLoginUrl,omitempty"` LoginUrl string `json:"loginUrl,omitempty"` RedirectUiUrl string `json:"redirectUiUrl,omitempty"` diff --git a/client/user.go b/client/user.go index 34a8767e..18445690 100644 --- a/client/user.go +++ b/client/user.go @@ -46,16 +46,18 @@ type User struct { } type NewUser struct { - UserName string `json:"userName"` - Email string `json:"email"` - Logins []Login `json:"logins,omitempty"` - Roles []string `json:"roles,omitempty"` - Account []string `json:"account,omitempty"` + ID string `json:"_id,omitempty"` + UserName string `json:"userName"` + Email string `json:"email"` + Logins []Login `json:"logins,omitempty"` + Roles []string `json:"roles,omitempty"` + Account []string `json:"account,omitempty"` + Personal *Personal `json:"personal,omitempty"` } type UserAccounts struct { - UserName string `json:"userName` - Account []Account `json:"account` + UserName string `json:"userName"` + Account []Account `json:"account"` } func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { diff --git a/codefresh/provider.go b/codefresh/provider.go index f948a491..eb90c538 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -31,13 +31,14 @@ func Provider() terraform.ResourceProvider { "codefresh_user": dataSourceUser(), }, ResourcesMap: map[string]*schema.Resource{ - "codefresh_project": resourceProject(), - "codefresh_pipeline": resourcePipeline(), - "codefresh_team": resourceTeam(), - "codefresh_account": resourceAccount(), - "codefresh_api_key": resourceApiKey(), - "codefresh_idp_accounts": resourceIDPAccounts(), + "codefresh_project": resourceProject(), + "codefresh_pipeline": resourcePipeline(), + "codefresh_team": resourceTeam(), + "codefresh_account": resourceAccount(), + "codefresh_api_key": resourceApiKey(), + "codefresh_idp_accounts": resourceIDPAccounts(), "codefresh_account_admins": resourceAccountAdmins(), + "codefresh_user": resourceUser(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index 3b5d1093..f9d92c81 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -168,8 +168,8 @@ func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { // admins := d.Get("admins").(*schema.Set).List() account := &cfClient.Account{ - ID: d.Id(), - Name: d.Get("name").(string), + ID: d.Id(), + Name: d.Get("name").(string), // Admins: convertStringArr(admins), } diff --git a/codefresh/resource_user.go b/codefresh/resource_user.go new file mode 100644 index 00000000..60fea5f1 --- /dev/null +++ b/codefresh/resource_user.go @@ -0,0 +1,311 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceUser() *schema.Resource { + return &schema.Resource{ + Create: resourceUsersCreate, + Read: resourceUsersRead, + Update: resourceUsersUpdate, + Delete: resourceUsersDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Required: true, + }, + "email": { + Type: schema.TypeString, + Required: true, + }, + "activate": { + Type: schema.TypeBool, + Optional: true, + }, + "accounts": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "personal": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "first_name": { + Type: schema.TypeString, + Optional: true, + }, + "last_name": { + Type: schema.TypeString, + Optional: true, + }, + "company_name": { + Type: schema.TypeString, + Optional: true, + }, + "phone_number": { + Type: schema.TypeString, + Optional: true, + }, + "country": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "short_profile": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "user_name": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "roles": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "login": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "credentials": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "permissions": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "idp": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idp_id": { + Type: schema.TypeString, + Optional: true, + }, + "client_type": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func resourceUsersCreate(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + user := mapResourceToUser(d) + + resp, err := client.AddPendingUser(user) + if err != nil { + return err + } + + d.SetId(resp.ID) + + if d.Get("activate").(bool) { + client.ActivateUser(d.Id()) + } + + return nil +} + +func resourceUsersRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + userId := d.Id() + + if userId == "" { + d.SetId("") + return nil + } + + user, err := client.GetUserByID(userId) + if err != nil { + return err + } + + err = mapUserToResource(*user, d) + if err != nil { + return err + } + + return nil +} + +func resourceUsersUpdate(d *schema.ResourceData, meta interface{}) error { + // only accounts list + + client := meta.(*cfClient.Client) + + accountList := d.Get("accounts").(*schema.Set).List() + + userId := d.Id() + + accounts, err := client.GetAccountsList(convertStringArr(accountList)) + if err != nil { + return err + } + + err = client.UpdateUserAccounts(userId, *accounts) + if err != nil { + return err + } + + return nil +} + +func resourceUsersDelete(d *schema.ResourceData, meta interface{}) error { + + // To research + // it's impossible sometimes to delete user - limit of runtimes or collaborators should be increased. + + client := meta.(*cfClient.Client) + + userName := d.Get("user_name").(string) + + err := client.DeleteUser(userName) + if err != nil { + return err + } + + return nil +} + +func mapUserToResource(user cfClient.User, d *schema.ResourceData) error { + + d.Set("user_name", user.UserName) + d.Set("email", user.Email) + d.Set("accounts", flattenUserAccounts(user.Account)) + d.Set("status", user.Status) + if user.Personal != nil { + d.Set("personal", flattenPersonal(user.Personal)) + } + d.Set("short_profile", + []map[string]interface{}{ + {"user_name": user.ShortProfile.UserName}, + }) + d.Set("roles", user.Roles) + d.Set("login", flattenUserLogins(&user.Logins)) + + return nil +} + +func flattenUserAccounts(accounts []cfClient.Account) []string { + + var accountList []string + + for _, account := range accounts { + accountList = append(accountList, account.ID) + } + + return accountList +} + +func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { + + var res = make([]map[string]interface{}, len(*logins)) + for i, login := range *logins { + m := make(map[string]interface{}) + m["credentials"] = []map[string]interface{}{ + {"permissions": login.Credentials.Permissions}, + } + + m["idp"] = []map[string]interface{}{ + { + "idp_id": login.IDP.ID, + "client_type": login.IDP.ClientType, + }, + } + + res[i] = m + } + + return res +} + + + +func mapResourceToUser(d *schema.ResourceData) *cfClient.NewUser { + + roles := d.Get("roles").(*schema.Set).List() + accounts := d.Get("accounts").(*schema.Set).List() + + user := &cfClient.NewUser{ + ID: d.Id(), + UserName: d.Get("user_name").(string), + Email: d.Get("email").(string), + Roles: convertStringArr(roles), + Account: convertStringArr(accounts), + } + + if _, ok := d.GetOk("personal"); ok { + user.Personal = &cfClient.Personal{ + FirstName: d.Get("personal.0.first_name").(string), + LastName: d.Get("personal.0.last_name").(string), + CompanyName: d.Get("personal.0.company_name").(string), + PhoneNumber: d.Get("personal.0.phone_number").(string), + Country: d.Get("personal.0.country").(string), + } + } + + logins := d.Get("login").([]interface{}) + + + for idx := range logins { + + permissions := convertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) + login := cfClient.Login{ + Credentials: cfClient.Credentials{ + Permissions: permissions, + }, + IDP: cfClient.IDP{ + ID: d.Get(fmt.Sprintf("login.%v.idp.0.idp_id", idx)).(string), + ClientType: d.Get(fmt.Sprintf("login.%v.idp.0.client_type", idx)).(string), + }, + } + user.Logins = append(user.Logins, login) + } + + return user +} diff --git a/docs/resources/user.md b/docs/resources/user.md new file mode 100644 index 00000000..70542950 --- /dev/null +++ b/docs/resources/user.md @@ -0,0 +1,95 @@ +# User resource + +Use this resource to create a new user. + +## Example usage + +```hcl +resource "codefresh_account" "test" { + + name = "mynewaccount" + + limits { + collaborators = 25 + data_retention_weeks = 5 + } + + build { + parallel = 2 + } +} + +resource "codefresh_user" "new" { + email = "" + user_name = "" + + activate = true + + roles = [ + "Admin", + "User" + ] + + login { + idp { + idp_id = + client_type = "azure" + } + } + + personal { + first_name = "John" + last_name = "Smith" + } + + accounts = [ + codefresh_account.test.id, + "59009117c102763beda7ce71", + ] +} +``` + +## Argument Reference + +- `email` - (Required) A new user email. +- `user_name` - (Required) The new user name. +- `activate` - (Optional) Boolean. Activate the new use or not. If a new user is not activate, it'll be left pending. +- `accounts` - (Optional) A list of accounts to add to the user. +- `personal` - (Optional) A collection of `personal` blocks as documented below. +- `accounts` - (Optional) A list of user roles. Possible values - `Admin`, `User`. +- `login` - (Optional) A collection of `login` blocks as documented below. + +--- + +`personal` supports the following: + +- `first_name` - (Optional). +- `last_name` - (Optional). +- `company_name` - (Optional). +- `phone_number` - (Optional). +- `country` - (Optional). + +--- + +`login` supports the following: +- `credentials` + - `permissions` - (Optional) A list of permissions. +- `idp` + - `idp_id` - (Optional) The id of IDP to the user to. + - `client_type` - (Optional) IDP type. ex. - `github`, `azure`, etc. + +## Attributes Reference + +- `id` - The User ID. +- `short_profile` + - `user_name` +- `status`. Current status of the user. ex - `new`, `pengind`. + + + +## Import + +```sh +terraform import codefresh_user.new xxxxxxxxxxxxxxxxxxx +``` + From 44f6743e970b81c3b6e48b1516c55c70249ffbae Mon Sep 17 00:00:00 2001 From: Kosta Klevensky Date: Wed, 22 Jul 2020 20:31:41 +0300 Subject: [PATCH 17/32] provider-sdk-v2 + featuresFlag --- client/account.go | 31 +++- client/api_key.go | 2 +- codefresh/data_user.go | 2 +- codefresh/data_users.go | 2 +- codefresh/provider.go | 6 +- codefresh/provider_test.go | 4 +- codefresh/resource_account.go | 24 ++- codefresh/resource_account_admins.go | 2 +- codefresh/resource_api_key.go | 2 +- codefresh/resource_idp_accounts.go | 2 +- codefresh/resource_pipeline.go | 2 +- codefresh/resource_pipeline_test.go | 6 +- codefresh/resource_project.go | 2 +- codefresh/resource_project_test.go | 6 +- codefresh/resource_team.go | 2 +- codefresh/resource_user.go | 7 +- go.mod | 8 +- go.sum | 215 +++++---------------------- main.go | 27 +++- 19 files changed, 128 insertions(+), 224 deletions(-) diff --git a/client/account.go b/client/account.go index 755570b7..e59dbae8 100644 --- a/client/account.go +++ b/client/account.go @@ -3,8 +3,6 @@ package client import ( "errors" "fmt" - "log" - "strconv" "github.com/imdario/mergo" ) @@ -144,12 +142,7 @@ type AccountDetails struct { func (account *Account) SetFeatures(m map[string]interface{}) { res := make(map[string]bool) for k, v := range m { - value := v.(string) - b, err := strconv.ParseBool(value) - if err != nil { - log.Fatalf("[ERROR] Can't parse '%s = %s' as boolean", k, value) - } - res[k] = b + res[k] = v.(bool) } account.Features = res } @@ -290,6 +283,28 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { if err != nil { return nil, err } + + // Update Features + var featureUpdatePath string + for k, v := range account.Features{ + //body + if v { + featureUpdatePath = fmt.Sprintf("/features/%s", id) + } else { + featureUpdatePath = fmt.Sprintf("/features/switchOff/%s", id) + } + bodyFeatures := []byte(fmt.Sprintf("{\"feature\": \"%s\"}", k)) + _, err = client.RequestAPI(&RequestOptions{ + Path: featureUpdatePath, + Method: "POST", + Body: bodyFeatures, + }) + if err != nil { + return nil, err + } + respAccount.Features[k] = v + } + return &respAccount, nil } diff --git a/client/api_key.go b/client/api_key.go index adb1f912..97ba4f98 100644 --- a/client/api_key.go +++ b/client/api_key.go @@ -3,7 +3,7 @@ package client import ( "errors" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "log" "net/http" ) diff --git a/codefresh/data_user.go b/codefresh/data_user.go index 73c57dfd..597535bf 100644 --- a/codefresh/data_user.go +++ b/codefresh/data_user.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func dataSourceUser() *schema.Resource { diff --git a/codefresh/data_users.go b/codefresh/data_users.go index ececb7ec..d1bf5857 100644 --- a/codefresh/data_users.go +++ b/codefresh/data_users.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "time" ) diff --git a/codefresh/provider.go b/codefresh/provider.go index eb90c538..47a96eda 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -2,12 +2,12 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + //"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "os" ) -func Provider() terraform.ResourceProvider { +func Provider() *schema.Provider { return &schema.Provider{ Schema: map[string]*schema.Schema{ "api_url": { diff --git a/codefresh/provider_test.go b/codefresh/provider_test.go index 0d113f38..957593ef 100644 --- a/codefresh/provider_test.go +++ b/codefresh/provider_test.go @@ -1,8 +1,8 @@ package codefresh import ( - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "os" "testing" ) diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index f9d92c81..db66a807 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceAccount() *schema.Resource { @@ -26,6 +26,21 @@ func resourceAccount() *schema.Resource { // Type: schema.TypeString, // }, // }, + + "features": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeBool, + }, + Default: map[string]bool{ + "OfflineLogging": true, + "ssoManagement": true, + "teamsManagement": true, + "abac": true, + "customKubernetesCluster": true, + }, + }, "limits": { Type: schema.TypeList, Optional: true, @@ -137,6 +152,10 @@ func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) err // if err != nil { // return err // } + err = d.Set("features", account.Features) + if err != nil { + return err + } err = d.Set("limits", []map[string]interface{}{flattenLimits(*account.Limits)}) if err != nil { @@ -173,6 +192,9 @@ func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { // Admins: convertStringArr(admins), } + if _, ok := d.GetOk("features"); ok { + account.SetFeatures(d.Get("features").(map[string]interface{})) + } if _, ok := d.GetOk("limits"); ok { account.Limits = &cfClient.Limits{ Collaborators: cfClient.Collaborators{ diff --git a/codefresh/resource_account_admins.go b/codefresh/resource_account_admins.go index 44c1287b..d34b32f7 100644 --- a/codefresh/resource_account_admins.go +++ b/codefresh/resource_account_admins.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceAccountAdmins() *schema.Resource { diff --git a/codefresh/resource_api_key.go b/codefresh/resource_api_key.go index eddb6c92..af49c189 100644 --- a/codefresh/resource_api_key.go +++ b/codefresh/resource_api_key.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceApiKey() *schema.Resource { diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go index 09b40b0a..b706cca5 100644 --- a/codefresh/resource_idp_accounts.go +++ b/codefresh/resource_idp_accounts.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceIDPAccounts() *schema.Resource { diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go index 480d7db4..8662d295 100644 --- a/codefresh/resource_pipeline.go +++ b/codefresh/resource_pipeline.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "strings" ) diff --git a/codefresh/resource_pipeline_test.go b/codefresh/resource_pipeline_test.go index 4f1bdb53..0e58377a 100644 --- a/codefresh/resource_pipeline_test.go +++ b/codefresh/resource_pipeline_test.go @@ -3,9 +3,9 @@ package codefresh import ( "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "regexp" "testing" ) diff --git a/codefresh/resource_project.go b/codefresh/resource_project.go index 51f625e0..2212094b 100644 --- a/codefresh/resource_project.go +++ b/codefresh/resource_project.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceProject() *schema.Resource { diff --git a/codefresh/resource_project_test.go b/codefresh/resource_project_test.go index 79080953..cb806206 100644 --- a/codefresh/resource_project_test.go +++ b/codefresh/resource_project_test.go @@ -3,9 +3,9 @@ package codefresh import ( "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "regexp" "testing" ) diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 22dbc006..2e9d2934 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -2,7 +2,7 @@ package codefresh import ( cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceTeam() *schema.Resource { diff --git a/codefresh/resource_user.go b/codefresh/resource_user.go index 60fea5f1..56ca5a02 100644 --- a/codefresh/resource_user.go +++ b/codefresh/resource_user.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceUser() *schema.Resource { @@ -253,7 +253,7 @@ func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { m["idp"] = []map[string]interface{}{ { - "idp_id": login.IDP.ID, + "idp_id": login.IDP.ID, "client_type": login.IDP.ClientType, }, } @@ -264,8 +264,6 @@ func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { return res } - - func mapResourceToUser(d *schema.ResourceData) *cfClient.NewUser { roles := d.Get("roles").(*schema.Set).List() @@ -291,7 +289,6 @@ func mapResourceToUser(d *schema.ResourceData) *cfClient.NewUser { logins := d.Get("login").([]interface{}) - for idx := range logins { permissions := convertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) diff --git a/go.mod b/go.mod index 14fad38f..db39b88e 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,15 @@ module github.com/codefresh-io/terraform-provider-codefresh require ( - github.com/aws/aws-sdk-go v1.30.12 + github.com/aws/aws-sdk-go v1.30.12 // indirect github.com/bflad/tfproviderdocs v0.6.0 github.com/bflad/tfproviderlint v0.14.0 github.com/client9/misspell v0.3.4 github.com/golangci/golangci-lint v1.27.0 - github.com/google/martian v2.1.0+incompatible - github.com/hashicorp/terraform v0.12.25 - github.com/hashicorp/terraform-plugin-sdk v1.7.0 + github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 // indirect + github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1 github.com/imdario/mergo v0.3.9 + golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect ) go 1.13 diff --git a/go.sum b/go.sum index 4688b7a2..767223e6 100644 --- a/go.sum +++ b/go.sum @@ -7,63 +7,21 @@ cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v36.2.0+incompatible h1:09cv2WoH0g6jl6m2iT+R9qcIPZKhXEL0sbmLhxP895s= -github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.2 h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4= -github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503 h1:Hxqlh1uAA8aGpa1dFhDNhll7U/rkWtG8ZItFvRMr7l0= -github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/azure/cli v0.2.0 h1:pSwNMF0qotgehbQNllUWwJ4V3vnrLKOzHrwDLEZK904= -github.com/Azure/go-autorest/autorest/azure/cli v0.2.0/go.mod h1:WWTbGPvkAg3I4ms2j2s+Zr5xCGwGqTQh+6M2ZqOczkE= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= -github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= -github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= -github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 h1:pSm8mp0T2OH2CPmPDPtwHPr3VAQaOwVF/JbllOPP4xA= -github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022 h1:y8Gs8CzNfDF5AZvjr+5UyGQvQEBL7pwo+v+wX6q9JI8= -github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157 h1:hY39LwQHh+1kaovmIjOrlqnXNX6tygSRfLkkK33IkZU= github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us= github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= -github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI= -github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= -github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a h1:APorzFpCcv6wtD5vmRWYqNm4N55kbepL7c7kTq9XI6A= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70 h1:FrF4uxA24DF3ARNXVbUin3wa5fDLaB1Cy8mKks/LRz4= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM= -github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw= -github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= @@ -71,11 +29,8 @@ github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFU github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171/go.mod h1:JXY95WvQrPJQtudvNARshgWajS7jNNlM90altXIPNyI= -github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= -github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -84,7 +39,6 @@ github.com/aws/aws-sdk-go v1.25.3 h1:uM16hIw9BotjZKMZlX05SN2EFtaWfi/NonPKIARiBLQ github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.12 h1:KrjyosZvkpJjcwMk0RNxMZewQ47v7+ZkbQDXjWsJMs8= github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bflad/gopaniccheck v0.1.0 h1:tJftp+bv42ouERmUMWLoUn/5bi/iQZjHPznM00cP/bU= @@ -97,30 +51,21 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1U github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/bmatcuk/doublestar v1.2.1 h1:eetYiv8DDYOZcBADY+pRvRytf3Dlz1FhnpvL2FsClBc= github.com/bmatcuk/doublestar v1.2.1/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bombsimon/wsl/v3 v3.0.0 h1:w9f49xQatuaeTJFaNP4SpiWSR5vfT6IstPtM62JjcqA= github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -131,12 +76,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= -github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= -github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1/go.mod h1:lcy9/2gH1jn/VCLouHA6tOEwLoNVd4GW6zhuKLmHC2Y= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -153,7 +94,6 @@ github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dT github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= @@ -183,12 +123,10 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw= github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -199,7 +137,9 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= @@ -237,8 +177,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -251,10 +189,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= -github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968 h1:Pu+HW4kcQozw0QyrTTgLE+3RXNqFhQNNzhbnoLFL83c= -github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 h1:OgCNGSnEalfkRpn//WGJHhpo7fkP+LhTpvEITZ7CkK4= -github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -262,48 +196,32 @@ github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:J github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/aws-sdk-go-base v0.4.0 h1:zH9hNUdsS+2G0zJaU85ul8D59BGnZBaKM+KMNPAHGwk= -github.com/hashicorp/aws-sdk-go-base v0.4.0/go.mod h1:eRhlz3c4nhqxFZJAahJEFL7gh6Jyj5rQmQc7F9eHFyQ= -github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089 h1:1eDpXAxTh0iPv+1kc9/gfSI2pxRERDsTk/lNGolwHn8= -github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-azure-helpers v0.10.0 h1:KhjDnQhCqEMKlt4yH00MCevJQPJ6LkHFdSveXINO6vE= -github.com/hashicorp/go-azure-helpers v0.10.0/go.mod h1:YuAtHxm2v74s+IjQwUG88dHBJPd5jL+cXr5BGVzSKhE= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8= github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.10.0 h1:b86HUuA126IcSHyC55WjPo7KtCOVeTCKIjr+3lBhPxI= github.com/hashicorp/go-hclog v0.10.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw= -github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.0.1-0.20190610192547-a1bc61569a26/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4= -github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= +github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= -github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc= -github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= -github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-tfe v0.3.27 h1:7XZ/ZoPyYoeuNXaWWW0mJOq016y0qb7I4Q0P/cagyu8= -github.com/hashicorp/go-tfe v0.3.27/go.mod h1:DVPSW2ogH+M9W1/i50ASgMht8cHP7NxxK0nrY9aFikQ= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -320,31 +238,29 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= github.com/hashicorp/hcl/v2 v2.3.0 h1:iRly8YaMwTBAKhn1Ybk7VSdzbnopghktCD031P8ggUE= github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= -github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI= -github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= -github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb h1:ZbgmOQt8DOg796figP87/EFCVx2v2h9yRvwHF/zceX4= -github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= -github.com/hashicorp/terraform v0.12.25 h1:4RCbJeJvBTl+t9SDa3xqEU9G9sH5khqjlabr/89bshk= -github.com/hashicorp/terraform v0.12.25/go.mod h1:B9VZ/cn0j1wpi16bdgLBCw5D5wNOqM8DVP0al92nPXc= github.com/hashicorp/terraform-config-inspect v0.0.0-20191115094559-17f92b0546e8/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 h1:Pc5TCv9mbxFN6UVX0LH6CpQrdTM5YjbVI2w15237Pjk= github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= +github.com/hashicorp/terraform-exec v0.1.1 h1:soHqDz5365aZVt9pyTT7ArOXSpMqaHGMYq4VhI+HNkE= +github.com/hashicorp/terraform-exec v0.1.1/go.mod h1:yKWvMPtkTaHpeAmllw+1qdHZ7E5u+pAZ+x8e2jQF6gM= github.com/hashicorp/terraform-json v0.4.0 h1:KNh29iNxozP5adfUFBJ4/fWd0Cu3taGgjHB38JYqOF4= github.com/hashicorp/terraform-json v0.4.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= github.com/hashicorp/terraform-json v0.5.0 h1:7TV3/F3y7QVSuN4r9BEXqnWqrAyeOtON8f0wvREtyzs= github.com/hashicorp/terraform-json v0.5.0/go.mod h1:eAbqb4w0pSlRmdvl8fOyHAi/+8jnkVYN28gJkSJrLhU= github.com/hashicorp/terraform-plugin-sdk v1.7.0 h1:B//oq0ZORG+EkVrIJy0uPGSonvmXqxSzXe8+GhknoW0= github.com/hashicorp/terraform-plugin-sdk v1.7.0/go.mod h1:OjgQmey5VxnPej/buEhe+YqKm0KNvV3QqU4hkqHqPCY= -github.com/hashicorp/terraform-plugin-sdk v1.13.0 h1:8v2/ZNiI12OHxEn8pzJ3noCHyRc0biKbKj+iFv5ZWKw= -github.com/hashicorp/terraform-plugin-sdk v1.13.1 h1:kWq+V+4BMFKtzIuO8wb/k4SRGB/VVF8g468VSFmAnKM= +github.com/hashicorp/terraform-plugin-sdk v1.15.0 h1:bmYnTT7MqNXlUHDc7pT8E6uKT2g/upjlRLypJFK1OQU= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2 h1:HHppQ5ly03DFdZpuxiO2qHEbZ8uJHcZiRp37O9OfnCc= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1 h1:h8TtYDlIACXQ6LNJesvSHuxskaPUAX/nltvqp0Kp1vk= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1/go.mod h1:aWg/hVISyjdpUOt89SSrplxffuq8HPEnIWGyKDpDzCo= github.com/hashicorp/terraform-plugin-test v1.2.0 h1:AWFdqyfnOj04sxTdaAF57QqvW7XXrT8PseUHkbKsE8I= github.com/hashicorp/terraform-plugin-test v1.2.0/go.mod h1:QIJHYz8j+xJtdtLrFTlzQVC0ocr3rf/OjIpgZLK56Hs= +github.com/hashicorp/terraform-plugin-test v1.4.4 h1:5Pvg9nESNFDnf6bafUYX5Qk15WaZtv0alxwOKiZo7vQ= +github.com/hashicorp/terraform-plugin-test v1.4.4/go.mod h1:UA7z/02pgqsRLut4DJIPm0Hjnj27uOvhi19c8kTqIfM= github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg= github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= -github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= @@ -354,6 +270,8 @@ github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3 h1:jNYPNLe3d8smommaoQlK7LOA5ESyUJJ+Wf79ZtA7Vp4= @@ -365,17 +283,10 @@ github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2 github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 h1:kie3qOosvRKqwij2HGzXWffwpXvcqfPPXRUw8I4F/mg= -github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= -github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= -github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= @@ -399,26 +310,12 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/likexian/gokit v0.0.0-20190309162924-0a377eecf7aa/go.mod h1:QdfYv6y6qPA9pbBA2qXtoT8BMKha6UyNbxWGWl/9Jfk= -github.com/likexian/gokit v0.0.0-20190418170008-ace88ad0983b/go.mod h1:KKqSnk/VVSW8kEyO2vVCXoanzEutKdlBAPohmGXkxCk= -github.com/likexian/gokit v0.0.0-20190501133040-e77ea8b19cdc/go.mod h1:3kvONayqCaj+UgrRZGpgfXzHdMYCAO0KAt4/8n0L57Y= -github.com/likexian/gokit v0.20.15 h1:DgtIqqTRFqtbiLJFzuRESwVrxWxfs8OlY6hnPYBa3BM= -github.com/likexian/gokit v0.20.15/go.mod h1:kn+nTv3tqh6yhor9BC4Lfiu58SmH8NmQ2PmEl+uM6nU= -github.com/likexian/simplejson-go v0.0.0-20190409170913-40473a74d76d/go.mod h1:Typ1BfnATYtZ/+/shXfFYLrovhFyuKvzwrdOnIDHlmg= -github.com/likexian/simplejson-go v0.0.0-20190419151922-c1f9f0b4f084/go.mod h1:U4O1vIJvIKwbMZKUJ62lppfdvkCdVd2nfMimHK81eec= -github.com/likexian/simplejson-go v0.0.0-20190502021454-d8787b4bfa0b/go.mod h1:3BWwtmKP9cXWwYCr5bkoVDEfLywacOv0s06OBEDpyt8= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 h1:wnfcqULT+N2seWf6y4yHzmi7GD2kNx4Ute0qArktD48= -github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ= github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9 h1:SmVbOZFWAlyQshuMfOkiAx1f5oUTsOGG5IXplAEYeeM= -github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= -github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b h1:/1RFh2SLCJ+tEnT73+Fh5R2AO89sQqs8ba7o+hx1G0Y= -github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b/go.mod h1:wr1VqkwW0AB5JS0QLy5GpVMS9E3VtRoSYXUYyVk46KY= github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUCe2BNSOz4tVy2yGyXhvYDvxGgeE= github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -434,12 +331,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-shellwords v1.0.4 h1:xmZZyxuP+bYKAKkA9ABYXVNJ+G/Wf3R8d8vAP3LDJJk= -github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= @@ -449,33 +343,21 @@ github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFW github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb h1:GRiLv4rgyqjqzxbhJke65IYUf4NCOOvrPOJbV/sPxkM= -github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.4 h1:ZU1VNC02qyufSZsjjs7+khruk2fKvbQ3TwRV/IBCeFA= +github.com/mitchellh/go-testing-interface v1.0.4/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= -github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE= -github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA= -github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51 h1:eD92Am0Qf3rqhsOeA1zwBHSfRkoHrt4o6uORamdmJP8= -github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= -github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= -github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakabonne/nestif v0.3.0 h1:+yOViDGhg8ygGrmII72nV9B/zGxY188TYpfolntsaPw= github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= @@ -483,8 +365,6 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1 github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= -github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -494,16 +374,11 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58 h1:m3CEgv3ah1Rhy82L+c0QG/U3VyY1UsvsIdkh0/rU97Y= -github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= -github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -515,16 +390,13 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= @@ -533,9 +405,6 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryancurrah/gomodguard v1.0.4 h1:oCreMAt9GuFXDe9jW4HBpc3GjdX3R/sUEcLAGh1zPx8= github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0fVb9d5fSEaLhoE= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/securego/gosec/v2 v2.3.0 h1:y/9mCF2WPDbSDpL3QDWZD3HHGrSYw0QSHnCqTfs4JPE= github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= @@ -551,7 +420,6 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -559,7 +427,6 @@ github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QC github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= @@ -586,25 +453,15 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI= -github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2 h1:Xr9gkxfOP0KQWXKNqmwe8vEeSUiUj4Rlee9CMVX2ZUQ= github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= -github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible h1:5Td2b0yfaOvw9M9nZ5Oav6Li9bxUNxt4DgxMfIPpsa0= -github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= -github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c h1:iRD1CqtWUjgEVEmjwTMbP1DMzz1HRytOsgx/rlw/vNs= -github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c/go.mod h1:wk2XFUg6egk4tSDNZtXeKfe2G6690UVyt163PuUxBZk= -github.com/terraform-providers/terraform-provider-openstack v1.15.0 h1:adpjqej+F8BAX9dHmuPF47sUIkgifeqBu6p7iCsyj0Y= -github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew= github.com/tetafro/godot v0.3.7 h1:+mecr7RKrUKB5UQ1gwqEMn13sDKTyDR8KNIquB9mm+8= github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e h1:RumXZ56IrCj4CL+g1b9OL/oH0QnsF976bC8xQFYUD5Q= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa h1:RC4maTWLKKwb7p1cnoygsbKIgNlJqSYBeAFON3Ar8As= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= -github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= @@ -624,12 +481,7 @@ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs= -github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -644,15 +496,11 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -677,6 +525,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zH golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -685,7 +534,6 @@ golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -699,6 +547,8 @@ golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -718,7 +568,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -733,6 +582,8 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -789,6 +640,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -797,6 +649,9 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200310143817-43be25429f5a h1:lRlI5zu6AFy3iU/F8YWyNrAmn/tPCnhiTxfwhWb76eU= +google.golang.org/genproto v0.0.0-20200310143817-43be25429f5a/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -804,6 +659,9 @@ google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= @@ -815,7 +673,6 @@ gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= diff --git a/main.go b/main.go index 12231e6b..82cc813a 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,28 @@ package main import ( + "os" + "log" + "context" "github.com/codefresh-io/terraform-provider-codefresh/codefresh" - "github.com/hashicorp/terraform-plugin-sdk/plugin" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + //"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func main() { - plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: func() terraform.ResourceProvider { - return codefresh.Provider() - }, - }) + debugMode := (os.Getenv("CODEFRESH_PLUGIN_DEBUG") != "") + if debugMode { + err := plugin.Debug(context.Background(), "registry.terraform.io/-/codefresh", + &plugin.ServeOpts{ + ProviderFunc: codefresh.Provider, + }) + if err != nil { + log.Println(err.Error()) + } + } else { + plugin.Serve(&plugin.ServeOpts{ + ProviderFunc: codefresh.Provider, + }, + ) + } } From 38499aea7e169711b4476c08ce07cb44d1a81435 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Wed, 22 Jul 2020 22:29:56 +0300 Subject: [PATCH 18/32] feature-flags --- client/account.go | 27 ++++++++++++--------------- docs/developer.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 docs/developer.md diff --git a/client/account.go b/client/account.go index e59dbae8..d5c547cb 100644 --- a/client/account.go +++ b/client/account.go @@ -249,17 +249,17 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { return nil, errors.New("[ERROR] Account ID is empty") } - existingAccount, err := client.GetAccountByID(id) + accountToUpdate, err := client.GetAccountByID(id) if err != nil { return nil, err } - err = mergo.Merge(account, existingAccount) + err = mergo.MergeWithOverwrite(accountToUpdate, account) if err != nil { return nil, err } - putAccount := AccountDetails{*account} + putAccount := AccountDetails{*accountToUpdate} body, err := EncodeToJSON(putAccount) if err != nil { @@ -285,20 +285,17 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { } // Update Features - var featureUpdatePath string - for k, v := range account.Features{ - //body + requestOptions := &RequestOptions{} + for k, v := range account.Features{ + requestOptions.Body = []byte(fmt.Sprintf("{\"feature\": \"%s\"}", k)) if v { - featureUpdatePath = fmt.Sprintf("/features/%s", id) + requestOptions.Path = fmt.Sprintf("/features/%s", id) + requestOptions.Method = "POST" } else { - featureUpdatePath = fmt.Sprintf("/features/switchOff/%s", id) - } - bodyFeatures := []byte(fmt.Sprintf("{\"feature\": \"%s\"}", k)) - _, err = client.RequestAPI(&RequestOptions{ - Path: featureUpdatePath, - Method: "POST", - Body: bodyFeatures, - }) + requestOptions.Path = fmt.Sprintf("/features/switchOff/%s", id) + requestOptions.Method = "PUT" + } + _, err = client.RequestAPI(requestOptions) if err != nil { return nil, err } diff --git a/docs/developer.md b/docs/developer.md new file mode 100644 index 00000000..eaa04b13 --- /dev/null +++ b/docs/developer.md @@ -0,0 +1,43 @@ +## Developer guide + +We are using [Terraform Plugin SDK v2](https://github.com/hashicorp/terraform-plugin-sdk/tree/v2.0.0-rc.2) + +### Run with Delve Debugger +[Reference guide](https://www.terraform.io/docs/extend/guides/v2-upgrade-guide.html#support-for-debuggable-provider-binaries) +[sdk code](https://github.com/hashicorp/terraform-plugin-sdk/blob/v2.0.0-rc.2/plugin/debug.go#L97) + +run pluging with set env CODEFRESH_PLUGIN_DEBUG=true in delve +- for vscode set launch.json like this: +```json +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "terraform-provider-codefresh", + "type": "go", + "request": "launch", + "mode": "debug", + "port": 2345, + "host": "127.0.0.1", + "env": {"CODEFRESH_PLUGIN_DEBUG": "true"}, + "program": "/d1/home/kosta/devel/go/src/github.com/codefresh-io/terraform-provider-codefresh/main.go", + "showLog": true, + "trace": "verbose" + } + ] +} +``` +- copy value of TF_REATTACH_PROVIDERS from the output of debug console and set it for terraform exec: +``` +export TF_REATTACH_PROVIDERS='{"registry.terraform.io/-/codefresh":{"Protocol":"grpc","Pid":614875,"Test":true,"Addr":{"Network":"unix","String":"/tmp/plugin369955425"}}}' + +terraform apply +``` + + + + + From afacceaa87a2222a0ee29ceed366181af70f611e Mon Sep 17 00:00:00 2001 From: kosta709 Date: Thu, 23 Jul 2020 22:20:59 +0300 Subject: [PATCH 19/32] idp-1 --- codefresh/data_idp.go | 153 ++++++++++++++++++++++++++++++++++++++++++ codefresh/provider.go | 1 + codefresh/utils.go | 8 +++ 3 files changed, 162 insertions(+) create mode 100644 codefresh/data_idp.go diff --git a/codefresh/data_idp.go b/codefresh/data_idp.go new file mode 100644 index 00000000..83c06d65 --- /dev/null +++ b/codefresh/data_idp.go @@ -0,0 +1,153 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceIdps() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIdpRead, + Schema: IdpSchema(), + } +} + +//IdpSchema - +func IdpSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "_id": { + Type: schema.TypeString, + Optional: true, + }, + "display_name": { + Type: schema.TypeString, + Optional: true, + }, + "client_type": { + Type: schema.TypeString, + Optional: true, + }, + "client_host": { + Type: schema.TypeString, + Computed: true, + }, + "access_token": { + Type: schema.TypeString, + Computed: true, + }, + "client_id": { + Type: schema.TypeString, + Computed: true, + }, + "client_secret": { + Type: schema.TypeString, + Computed: true, + }, + "app_id": { + Type: schema.TypeString, + Computed: true, + }, + "cookie_key": { + Type: schema.TypeString, + Computed: true, + }, + "cookie_iv": { + Type: schema.TypeString, + Computed: true, + }, + "tenant": { + Type: schema.TypeString, + Computed: true, + }, + "scopes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "accounts": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + } +} + +func dataSourceIdpRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + idps, err := client.GetIDPs() + if err != nil { + return err + } + + _id, _idOk := d.GetOk("_id") + displayName, displayNameOk := d.GetOk("displayName") + clientType, clientTypeOk := d.GetOk("clientType") + + if !(_idOk || displayNameOk || clientTypeOk) { + return fmt.Errorf("[EROOR] Idp data_source - no parameters specified") + } + for _, idp := range *idps { + if _idOk && _id.(string) != idp.ID { + continue + } + if displayNameOk && displayName.(string) != idp.DisplayName { + continue + } + if clientTypeOk && clientType.(string) != idp.ClientType { + continue + } + err = mapDataIdpToResource(idp, d) + if err != nil { + return err + } + } + + if d.Id() == "" { + return fmt.Errorf("[EROOR] Idp wasn't found") + } + + return nil +} + +func mapDataIdpToResource(idp cfClient.IDP, d *schema.ResourceData) error { + + d.SetId(idp.ID) + + d.Set("access_token", idp.Access_token)// string `json:"access_token,omitempty"` + + + d.Set("accounts", flattenStringArr(idp.Accounts)) // + //d.Set("apiHost", idp.ApiHost) // string `json:"apiHost,omitempty"` + //d.Set("apiPathPrefix", idp.ApiPathPrefix) // string `json:"apiPathPrefix,omitempty"` + //d.Set("apiURL", idp.ApiURL) // string `json:"apiURL,omitempty"` + //d.Set("appId", idp.AppId) // string `json:"appId,omitempty"` + //d.Set("authURL", idp.AuthURL) // string `json:"authURL,omitempty"` + d.Set("client_host", idp.ClientHost) // string `json:"clientHost,omitempty"` + d.Set("client_id", idp.ClientId) // string `json:"clientId,omitempty"` + d.Set("client_name", idp.ClientName) // string `json:"clientName,omitempty"` + d.Set("client_secret",idp.ClientSecret) // string `json:"clientSecret,omitempty"` + d.Set("client_type", idp.ClientType) // string `json:"clientType,omitempty"` + d.Set("cookie_iv", idp.CookieIv) // string `json:"cookieIv,omitempty"` + d.Set("cookie_key", idp.CookieKey) // string `json:"cookieKey,omitempty"` + d.Set("display_name", idp.DisplayName) // string `json:"displayName,omitempty"` + d.Set("_id", idp.ID) // string `json:"_id,omitempty"` + //d.Set("IDPLoginUrl", idp.IDPLoginUrl) // string `json:"IDPLoginUrl,omitempty"` + //d.Set("loginUrl", idp.LoginUrl) // string `json:"loginUrl,omitempty"` + //d.Set("redirectUiUrl", idp.RedirectUiUrl) // string `json:"redirectUiUrl,omitempty"` + //d.Set("redirectUrl", idp.RedirectUrl) // string `json:"redirectUrl,omitempty"` + //d.Set("refreshTokenURL", idp.RefreshTokenURL) // string `json:"refreshTokenURL,omitempty"` + d.Set("scopes", flattenStringArr(idp.Scopes)) // []string `json:"scopes,omitempty"` + d.Set("tenant", idp.Tenant) // string `json:"tenant,omitempty"` + //d.Set("tokenSecret", idp.TokenSecret) // string `json:"tokenSecret,omitempty"` + //d.Set("tokenURL", idp.TokenURL) // string `json:"tokenURL,omitempty"` + //d.Set("userProfileURL", idp.UserProfileURL) // string `json:"userProfileURL,omitempty"` + + return nil +} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index 47a96eda..5a59c74a 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -29,6 +29,7 @@ func Provider() *schema.Provider { DataSourcesMap: map[string]*schema.Resource{ "codefresh_users": dataSourceUsers(), "codefresh_user": dataSourceUser(), + "codefresh_idps": dataSourceIdps(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), diff --git a/codefresh/utils.go b/codefresh/utils.go index c71fb2fc..73637d35 100644 --- a/codefresh/utils.go +++ b/codefresh/utils.go @@ -26,3 +26,11 @@ func convertVariables(vars []cfClient.Variable) map[string]string { } return res } + +func flattenStringArr(sArr []string) []interface{} { + iArr := []interface{}{} + for _, s := range sArr { + iArr = append(iArr, s) + } + return iArr +} \ No newline at end of file From 11f52babe8a10324848477866bc49e1889e730c4 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Sun, 26 Jul 2020 00:04:47 +0300 Subject: [PATCH 20/32] user-idp --- client/user.go | 6 +- codefresh/{data_idp.go => resource_idp.go} | 25 +++-- codefresh/resource_idp_accounts.go | 20 ++-- codefresh/resource_user.go | 113 +++++++++++---------- docs/resources/user.md | 12 ++- 5 files changed, 100 insertions(+), 76 deletions(-) rename codefresh/{data_idp.go => resource_idp.go} (89%) diff --git a/client/user.go b/client/user.go index 18445690..a0c338dd 100644 --- a/client/user.go +++ b/client/user.go @@ -3,6 +3,7 @@ package client import ( "errors" "fmt" + "log" ) type Credentials struct { @@ -14,6 +15,8 @@ type Login struct { PersonalGit bool `json:"personalGit,omitempty"` Permissions []string `json:"permissions,omitempty"` IDP IDP `json:"idp,omitempty"` + Idp_ID string `json:"idp_id,omitempty"` + Sso bool `json:"sso,omitempty"` } type ShortProfile struct { @@ -180,7 +183,8 @@ func (client *Client) GetAllUsers() (*[]User, error) { } var users []User - + respStr := string(resp) + log.Printf("[INFO] GetAllUsers resp: %s", respStr) err = DecodeResponseInto(resp, &users) if err != nil { return nil, err diff --git a/codefresh/data_idp.go b/codefresh/resource_idp.go similarity index 89% rename from codefresh/data_idp.go rename to codefresh/resource_idp.go index 83c06d65..6a1ac189 100644 --- a/codefresh/data_idp.go +++ b/codefresh/resource_idp.go @@ -20,6 +20,10 @@ func IdpSchema() map[string]*schema.Schema { Type: schema.TypeString, Optional: true, }, + "client_name": { + Type: schema.TypeString, + Optional: true, + }, "display_name": { Type: schema.TypeString, Optional: true, @@ -61,14 +65,14 @@ func IdpSchema() map[string]*schema.Schema { Computed: true, }, "scopes": { - Type: schema.TypeList, + Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, }, }, "accounts": { - Type: schema.TypeList, + Type: schema.TypeSet, Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, @@ -87,16 +91,20 @@ func dataSourceIdpRead(d *schema.ResourceData, meta interface{}) error { } _id, _idOk := d.GetOk("_id") - displayName, displayNameOk := d.GetOk("displayName") - clientType, clientTypeOk := d.GetOk("clientType") + clientName, clientNameOk := d.GetOk("client_name") + displayName, displayNameOk := d.GetOk("display_name") + clientType, clientTypeOk := d.GetOk("client_type") - if !(_idOk || displayNameOk || clientTypeOk) { - return fmt.Errorf("[EROOR] Idp data_source - no parameters specified") + if !(_idOk || clientNameOk || displayNameOk || clientTypeOk) { + return fmt.Errorf("[ERROR] data.codefresh_idp - no parameters specified") } for _, idp := range *idps { - if _idOk && _id.(string) != idp.ID { + if clientNameOk && clientName.(string) != idp.ClientName { continue } + if _idOk && _id.(string) != idp.ID { + continue + } if displayNameOk && displayName.(string) != idp.DisplayName { continue } @@ -150,4 +158,5 @@ func mapDataIdpToResource(idp cfClient.IDP, d *schema.ResourceData) error { //d.Set("userProfileURL", idp.UserProfileURL) // string `json:"userProfileURL,omitempty"` return nil -} \ No newline at end of file +} + diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go index b706cca5..b17d764b 100644 --- a/codefresh/resource_idp_accounts.go +++ b/codefresh/resource_idp_accounts.go @@ -15,11 +15,11 @@ func resourceIDPAccounts() *schema.Resource { State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ - "idp": { + "idp_id": { Type: schema.TypeString, Required: true, }, - "accounts": { + "account_ids": { Type: schema.TypeSet, Required: true, Elem: &schema.Schema{ @@ -34,17 +34,17 @@ func resourceAccountIDPCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*cfClient.Client) - accounts := convertStringArr(d.Get("accounts").(*schema.Set).List()) + accountIds := convertStringArr(d.Get("account_ids").(*schema.Set).List()) - idpName := d.Get("idp").(string) + idpID := d.Get("idp_id").(string) - idp, err := client.GetIdpByName(idpName) + idp, err := client.GetIdpByID(idpID) if err != nil { return err } - for _, account := range accounts { - client.AddAccountToIDP(account, idp.ID) + for _, accountID := range accountIds { + client.AddAccountToIDP(accountID, idp.ID) } d.SetId(idp.ID) @@ -67,12 +67,12 @@ func resourceAccountIDPRead(d *schema.ResourceData, meta interface{}) error { return err } - err = d.Set("idp", idp.ClientName) + err = d.Set("idp_id", idp.ID) if err != nil { return err } - err = d.Set("accounts", idp.Accounts) + err = d.Set("account_ids", idp.Accounts) if err != nil { return err } @@ -99,7 +99,7 @@ func resourceAccountIDPUpdate(d *schema.ResourceData, meta interface{}) error { existingAccounts := idp.Accounts - desiredAccounts := convertStringArr(d.Get("accounts").(*schema.Set).List()) + desiredAccounts := convertStringArr(d.Get("account_ids").(*schema.Set).List()) for _, account := range desiredAccounts { if ok := cfClient.FindInSlice(existingAccounts, account); !ok { diff --git a/codefresh/resource_user.go b/codefresh/resource_user.go index 56ca5a02..b2b46256 100644 --- a/codefresh/resource_user.go +++ b/codefresh/resource_user.go @@ -1,7 +1,7 @@ package codefresh import ( - "fmt" + "log" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -38,6 +38,7 @@ func resourceUser() *schema.Resource { "personal": { Type: schema.TypeList, Optional: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "first_name": { @@ -87,40 +88,33 @@ func resourceUser() *schema.Resource { Computed: true, }, "login": { - Type: schema.TypeList, + Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "credentials": { - Type: schema.TypeList, + // "credentials": { + // Type: schema.TypeList, + // Optional: true, + // MaxItems: 1, + // Elem: &schema.Resource{ + // Schema: map[string]*schema.Schema{ + // "permissions": { + // Type: schema.TypeList, + // Optional: true, + // Elem: &schema.Schema{ + // Type: schema.TypeString, + // }, + // }, + // }, + // }, + // }, + "idp_id": { + Type: schema.TypeString, Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "permissions": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - }, - }, }, - "idp": { - Type: schema.TypeList, + "sso": { + Type: schema.TypeBool, Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idp_id": { - Type: schema.TypeString, - Optional: true, - }, - "client_type": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, }, }, }, @@ -247,16 +241,12 @@ func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { var res = make([]map[string]interface{}, len(*logins)) for i, login := range *logins { m := make(map[string]interface{}) - m["credentials"] = []map[string]interface{}{ - {"permissions": login.Credentials.Permissions}, - } + // m["credentials"] = []map[string]interface{}{ + // {"permissions": login.Credentials.Permissions}, + // } - m["idp"] = []map[string]interface{}{ - { - "idp_id": login.IDP.ID, - "client_type": login.IDP.ClientType, - }, - } + m["idp_id"] = login.IDP.ID + m["sso"] = login.Sso res[i] = m } @@ -287,22 +277,39 @@ func mapResourceToUser(d *schema.ResourceData) *cfClient.NewUser { } } - logins := d.Get("login").([]interface{}) - - for idx := range logins { - - permissions := convertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) - login := cfClient.Login{ - Credentials: cfClient.Credentials{ - Permissions: permissions, - }, - IDP: cfClient.IDP{ - ID: d.Get(fmt.Sprintf("login.%v.idp.0.idp_id", idx)).(string), - ClientType: d.Get(fmt.Sprintf("login.%v.idp.0.client_type", idx)).(string), - }, - } - user.Logins = append(user.Logins, login) + if logins, ok := d.GetOk("login"); ok { + loginsList := logins.(*schema.Set).List() + for _, loginDataI := range loginsList { + if loginData, isMap := loginDataI.(map[string]interface{}); isMap { + idpID := loginData["idp_id"].(string) + login := cfClient.Login{ + // Credentials: cfClient.Credentials{ + // Permissions: loginData.Get("credentials.permissions").([]string), + // }, + IDP: cfClient.IDP{ + ID: idpID, + }, + Sso: loginData["sso"].(bool), + } + user.Logins = append(user.Logins, login) + log.Printf("[DEBUG] login = %v", login) + } + } } + // logins := d.Get("login").(*schema.Set) + + // for idx := range logins { + + // permissions := convertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) + // login := cfClient.Login{ + // Credentials: cfClient.Credentials{ + // Permissions: permissions, + // }, + // Idp: d.Get(fmt.Sprintf("login.%v.idp_id", idx)).(string), + // Sso: d.Get(fmt.Sprintf("login.%v.sso", idx)).(bool), + // } + // user.Logins = append(user.Logins, login) + // } return user } diff --git a/docs/resources/user.md b/docs/resources/user.md index 70542950..7ff25933 100644 --- a/docs/resources/user.md +++ b/docs/resources/user.md @@ -31,11 +31,15 @@ resource "codefresh_user" "new" { ] login { - idp { - idp_id = - client_type = "azure" - } + idp_id = data.codefresh_idps.idp_azure.id + sso = true } + + login { + idp_id = data.codefresh_idps.local.id + //sso = false + } + personal { first_name = "John" From 3e20eebd1214fe1518bde4915dd2d76f87354a88 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Sun, 26 Jul 2020 20:14:03 +0300 Subject: [PATCH 21/32] tf_module access_control and examples --- codefresh/provider.go | 7 ++- codefresh/resource_account.go | 2 + docs/resources/account.md | 10 +++- tf_modules/access_control/main.tf | 69 +++++++++++++++++++++++ tf_modules/access_control/output.tf | 14 +++++ tf_modules/access_control/provider.tf | 4 ++ tf_modules/access_control/vars.tf | 81 +++++++++++++++++++++++++++ 7 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 tf_modules/access_control/main.tf create mode 100644 tf_modules/access_control/output.tf create mode 100644 tf_modules/access_control/provider.tf create mode 100644 tf_modules/access_control/vars.tf diff --git a/codefresh/provider.go b/codefresh/provider.go index 5a59c74a..5b90a959 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -22,8 +22,7 @@ func Provider() *schema.Provider { }, "token": { Type: schema.TypeString, - Required: true, - DefaultFunc: schema.EnvDefaultFunc("CODEFRESH_API_KEY", ""), + Optional: true, }, }, DataSourcesMap: map[string]*schema.Resource{ @@ -49,6 +48,8 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) { apiURL := d.Get("api_url").(string) token := d.Get("token").(string) - + if token == "" { + token = os.Getenv("CODEFRESH_API_KEY") + } return cfClient.NewClient(apiURL, token), nil } diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index db66a807..e2520fa0 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -53,6 +53,7 @@ func resourceAccount() *schema.Resource { "data_retention_weeks": { Type: schema.TypeInt, Optional: true, + Default: 5, }, }, }, @@ -68,6 +69,7 @@ func resourceAccount() *schema.Resource { }, "nodes": { Type: schema.TypeInt, + Default: 1, Optional: true, }, }, diff --git a/docs/resources/account.md b/docs/resources/account.md index 69b1d3a4..6da85eb0 100644 --- a/docs/resources/account.md +++ b/docs/resources/account.md @@ -18,6 +18,14 @@ resource "codefresh_account" "test" { parallel = 27 } + features = { + OfflineLogging = true, + ssoManagement = true, + teamsManagement = true, + abac = true, + customKubernetesCluster = true, + launchDarklyManagement = false, + } } ``` @@ -26,7 +34,7 @@ resource "codefresh_account" "test" { - `name` - (Required) The display name for the account. - `limits` - (Optional) A collection of `limits` blocks as documented below. - `build` - (Optional) A collection of `build` blocks as documented below. - +- `features` - (Optional) map of supported features toggles --- `limits` supports the following: diff --git a/tf_modules/access_control/main.tf b/tf_modules/access_control/main.tf new file mode 100644 index 00000000..e350db54 --- /dev/null +++ b/tf_modules/access_control/main.tf @@ -0,0 +1,69 @@ +data "codefresh_idps" "idps" { + for_each = var.default_idps + _id = lookup(each.value, "_id", "") + display_name = lookup(each.value, "display_name", "") + client_name = lookup(each.value, "client_name", "") + client_type = lookup(each.value, "client_type", "") +} + +resource "codefresh_account" "acc" { + for_each = var.accounts + name = each.key + + features = var.default_account_features + + limits { + collaborators = lookup(var.default_acccount_limits, "collaborators", 10) + } + + build { + parallel = lookup(var.default_acccount_limits, "parallel_builds", 1) + } + +} + +resource "codefresh_idp_accounts" "acc_idp" { + for_each = var.default_idps + idp_id = data.codefresh_idps.idps[each.key].id + account_ids = values(codefresh_account.acc)[*].id +} + +resource "codefresh_user" "users" { + for_each = var.users + user_name = each.key + email = each.value.email + + accounts = [ + for acc_name in each.value.accounts: codefresh_account.acc[acc_name].id + ] + + activate = true + + roles = each.value.global_admin ? ["Admin","User"] : ["User"] + + dynamic "login" { + for_each = var.default_idps + content { + idp_id = data.codefresh_idps.idps[login.key].id + sso = login.value.sso + } + } + + personal { + first_name = each.value.personal.first_name + last_name = each.value.personal.last_name + } +} + +resource "codefresh_account_admins" "acc_admins" { + for_each = toset(flatten([ + for u in var.users: + u.admin_of_accounts if length(u.admin_of_accounts) > 0 + ])) + + account_id = codefresh_account.acc[each.value].id + users = [ + for k, u in var.users: + codefresh_user.users[k].id if contains(u.admin_of_accounts, each.key) + ] +} diff --git a/tf_modules/access_control/output.tf b/tf_modules/access_control/output.tf new file mode 100644 index 00000000..ec8a006d --- /dev/null +++ b/tf_modules/access_control/output.tf @@ -0,0 +1,14 @@ +output "idps" { + value = { + for idp in data.codefresh_idps.idps: + idp.id => { client_name = idp.client_name, + display_name = idp.display_name + } + } +} +output "accounts" { + value = { + for acc in codefresh_account.acc: + acc.id => acc.name + } +} diff --git a/tf_modules/access_control/provider.tf b/tf_modules/access_control/provider.tf new file mode 100644 index 00000000..615d72a3 --- /dev/null +++ b/tf_modules/access_control/provider.tf @@ -0,0 +1,4 @@ +provider "codefresh" { + api_url = var.api_url + token = var.token +} \ No newline at end of file diff --git a/tf_modules/access_control/vars.tf b/tf_modules/access_control/vars.tf new file mode 100644 index 00000000..647ba4ca --- /dev/null +++ b/tf_modules/access_control/vars.tf @@ -0,0 +1,81 @@ +variable api_url { + type = string +} + +# +variable token { + type = string + default = "" +} + +variable default_account_features { + type = map(any) + default = { + OfflineLogging = true, + ssoManagement = true, + teamsManagement = true, + abac = true, + customKubernetesCluster = true, + launchDarklyManagement = false, + } +} + +variable default_acccount_limits { + type = map(any) + default = { + collaborators = 100 + parallel_builds = 10 + } +} + +variable default_idps { + type = map(any) + default = { + local = { + display_name = "local" + sso = false + } + } +} + +# map of accounts indexed by unique account name +# accounts = { +# acc1 = { +# } +# acc2 = { +# limits = { +# collaborators = 50 +# parallel_builds = 5 +# } +# } +# } +variable accounts { + type = map(any) +} + +# map of users: +# users = { +# user1 = { +# email = "ddd@gmail.com" +# personal = { +# first_name = "Q" +# last_name = "D" +# } +# accounts = ["acc1", "acc2"] +# global_admin = false +# } +# user2 = { + +# email = "ddd@gmail.com" +# personal = { +# first_name = "Q" +# last_name = "D" +# } +# accounts = ["acc1", "acc2"] +# global_admin = true +# } +# } +variable users { + //type = map(any) +} + From d9f6a13fbfcf50ca5247a36917c144b7c911492f Mon Sep 17 00:00:00 2001 From: kosta709 Date: Sun, 26 Jul 2020 20:14:31 +0300 Subject: [PATCH 22/32] tf_module access_control and examples --- examples/access_control/main.tf | 9 ++++ examples/access_control/terraform.tfvars | 55 ++++++++++++++++++++++++ examples/access_control/vars.tf | 22 ++++++++++ 3 files changed, 86 insertions(+) create mode 100644 examples/access_control/main.tf create mode 100644 examples/access_control/terraform.tfvars create mode 100644 examples/access_control/vars.tf diff --git a/examples/access_control/main.tf b/examples/access_control/main.tf new file mode 100644 index 00000000..68372d95 --- /dev/null +++ b/examples/access_control/main.tf @@ -0,0 +1,9 @@ +module "codefresh_access_control" { + source = "../../tf_modules/access_control" + api_url = var.api_url + default_idps = var.default_idps + accounts = var.accounts + users = var.users + + default_acccount_limits = var.default_acccount_limits +} \ No newline at end of file diff --git a/examples/access_control/terraform.tfvars b/examples/access_control/terraform.tfvars new file mode 100644 index 00000000..5136b8ae --- /dev/null +++ b/examples/access_control/terraform.tfvars @@ -0,0 +1,55 @@ +api_url = "https://onprem-tst-1.cf-cd.com/api" + +default_idps = { + local = { + display_name = "local" + sso = false + } + azure_sso = { + display_name = "codefresh-azure-sso-1" + sso = true + } +} + +accounts = { + acc1 = {} + acc2 = { + limits = { + collaborators = 50 + parallel_builds = 5 + } + } +} + +users = { + user1 = { + email = "kosta@codefresh.io" + personal = { + first_name = "Kosta" + last_name = "A" + } + accounts = ["acc1", "acc2"] + admin_of_accounts = ["acc1"] + global_admin = true + } + user2 = { + email = "live.com#kosta777@gmail.com" + personal = { + first_name = "Q" + last_name = "D" + } + accounts = ["acc2"] + admin_of_accounts = [] + global_admin = false + } + user3 = { + email = "kosta@sysadmiral.io" + personal = { + first_name = "Kosta" + last_name = "sysadmiral-io" + } + accounts = ["acc1", "acc2"] + admin_of_accounts = ["acc1", "acc2"] + global_admin = true + } +} \ No newline at end of file diff --git a/examples/access_control/vars.tf b/examples/access_control/vars.tf new file mode 100644 index 00000000..1d0b2844 --- /dev/null +++ b/examples/access_control/vars.tf @@ -0,0 +1,22 @@ +variable api_url {} + +variable default_acccount_limits { + type = map(any) + default = { + collaborators = 100 + parallel_builds = 10 + } +} + +variable default_idps { + type = map(any) +} + +variable accounts { + type = map(any) +} + +variable users { + //type = map(any) +} + From 80321de4adacb69abc6e275bacccc9a80e784ceb Mon Sep 17 00:00:00 2001 From: kosta709 Date: Sun, 26 Jul 2020 22:05:59 +0300 Subject: [PATCH 23/32] tf_module access_control and examples --- client/account.go | 49 +++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/client/account.go b/client/account.go index d5c547cb..0ecc0722 100644 --- a/client/account.go +++ b/client/account.go @@ -239,6 +239,10 @@ func (client *Client) CreateAccount(account *Account) (*Account, error) { return nil, err } + err = client.setAccountFeatures(account.Features, &respAccount) + if err != nil { + return nil, err + } return &respAccount, nil } @@ -284,24 +288,10 @@ func (client *Client) UpdateAccount(account *Account) (*Account, error) { return nil, err } - // Update Features - requestOptions := &RequestOptions{} - for k, v := range account.Features{ - requestOptions.Body = []byte(fmt.Sprintf("{\"feature\": \"%s\"}", k)) - if v { - requestOptions.Path = fmt.Sprintf("/features/%s", id) - requestOptions.Method = "POST" - } else { - requestOptions.Path = fmt.Sprintf("/features/switchOff/%s", id) - requestOptions.Method = "PUT" - } - _, err = client.RequestAPI(requestOptions) - if err != nil { - return nil, err - } - respAccount.Features[k] = v - } - + err = client.setAccountFeatures(account.Features, &respAccount) + if err != nil { + return nil, err + } return &respAccount, nil } @@ -335,7 +325,6 @@ func GetAccountAdminsDiff(desiredAdmins []string, existingAdmins []string) (admi } for _, id := range desiredAdmins { - if ok := FindInSlice(existingAdmins, id); !ok { adminsToAdd = append(adminsToAdd, id) } @@ -343,3 +332,25 @@ func GetAccountAdminsDiff(desiredAdmins []string, existingAdmins []string) (admi return adminsToAdd, adminsToDelete } + +// Update Features +func(client *Client) setAccountFeatures(features map[string]bool, account *Account) error { + id := account.GetID() + requestOptions := &RequestOptions{} + for k, v := range features{ + requestOptions.Body = []byte(fmt.Sprintf("{\"feature\": \"%s\"}", k)) + if v { + requestOptions.Path = fmt.Sprintf("/features/%s", id) + requestOptions.Method = "POST" + } else { + requestOptions.Path = fmt.Sprintf("/features/switchOff/%s", id) + requestOptions.Method = "PUT" + } + _, err := client.RequestAPI(requestOptions) + if err != nil { + return err + } + account.Features[k] = v + } + return nil +} \ No newline at end of file From b2a7e54c5309dcf21d1523bc2e94a5aaa2d4bff3 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Mon, 27 Jul 2020 15:28:14 +0300 Subject: [PATCH 24/32] api-ket no extra-user --- client/account.go | 37 ++++++++++++ client/api_key.go | 103 ++++++++++++++++++++++++---------- codefresh/provider.go | 1 + codefresh/resource_api_key.go | 7 ++- 4 files changed, 117 insertions(+), 31 deletions(-) diff --git a/client/account.go b/client/account.go index 0ecc0722..8ae41c1f 100644 --- a/client/account.go +++ b/client/account.go @@ -174,6 +174,43 @@ func (client *Client) GetAccountByID(id string) (*Account, error) { return &account, nil } +// GetAccountByName - returns account +func (client *Client) GetAccountByName(name string) (*Account, error) { + + if name == "" { + return nil, fmt.Errorf("GetAccountByName - must specify name param") + } + opts := RequestOptions{ + Path: "/admin/accounts", + Method: "GET", + QS: map[string]string{"filter[name]": name}, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var accounts []Account + + err = DecodeResponseInto(resp, &accounts) + if err != nil { + return nil, err + } + + var account *Account + for _, acc := range(accounts) { + if acc.Name == name { + account = &acc + } + } + if account == nil { + return nil, fmt.Errorf("GetAccountByName - cannot find account by name %s", name) + } + return account, nil +} + func (client *Client) GetAllAccounts() (*[]Account, error) { opts := RequestOptions{ diff --git a/client/api_key.go b/client/api_key.go index 97ba4f98..fc55a652 100644 --- a/client/api_key.go +++ b/client/api_key.go @@ -97,7 +97,8 @@ func (client *Client) UpdateAPIKey(key *ApiKey) error { return nil } -func (client *Client) CreateApiKey(accountId string, apiKey *ApiKey) (string, error) { +// CreateApiKey - creates api key for account by switch to the user and call /api/auth/keys +func (client *Client) CreateApiKey(userID string, accountId string, apiKey *ApiKey) (string, error) { // Check collaborataros account, err := client.GetAccountByID(accountId) @@ -108,34 +109,18 @@ func (client *Client) CreateApiKey(accountId string, apiKey *ApiKey) (string, er log.Fatal("[ERROR] Collaborators are not set") } - // add user - userPrefix := acctest.RandString(10) - userName := "tfuser" + userPrefix - userEmail := userName + "@codefresh.io" - - user, err := client.AddNewUserToAccount(accountId, userName, userEmail) - if err != nil { - return "", err - } - userID := user.ID - - // activate - _, err = client.ActivateUser(userID) - if err != nil { - return "", err - } - - // set user as account admin - err = client.SetUserAsAccountAdmin(accountId, userID) - if err != nil { - return "", nil - } - + var xAccessToken string + if userID == "" { + userID, err = client.createRandomUser(accountId) + if err != nil { + return "", err + } + } // login as user - xAccessToken, err := client.GetXAccessToken(userID) + xAccessToken, err = client.GetXAccessToken(userID, accountId) if err != nil { return "", err - } + } // generate token apiToken, err := client.GenerateToken(xAccessToken, apiKey) @@ -144,10 +129,10 @@ func (client *Client) CreateApiKey(accountId string, apiKey *ApiKey) (string, er } return apiToken, nil - } -func (client *Client) GetXAccessToken(userID string) (string, error) { +// GetXAccessToken +func (client *Client) GetXAccessToken(userID string, accountId string) (string, error) { url := fmt.Sprintf("%s/admin/user/loginAsUser?userId=%s", client.Host, userID) request, err := http.NewRequest("GET", url, nil) @@ -165,13 +150,44 @@ func (client *Client) GetXAccessToken(userID string) (string, error) { defer resp.Body.Close() + var userCfAccessToken string for _, cookie := range resp.Cookies() { if cookie.Name == "cf-access-token" { - return cookie.Value, nil + userCfAccessToken = cookie.Value + break + } + } + if userCfAccessToken == "" { + return "", fmt.Errorf("Failed to GetXAccessToken for userId = %s", userID) + } + + // change account + changeAccURL := fmt.Sprintf("%s/user/changeaccount/%s", client.Host, accountId) + changeAccRequest, err := http.NewRequest("POST", changeAccURL, nil) + if err != nil { + return "", err + } + + changeAccRequest.Header.Set("x-access-token", userCfAccessToken) + changeAccRequest.Header.Set("Content-Type", "application/json; charset=utf-8") + + changeAccResp, err := client.Client.Do(changeAccRequest) + if err != nil { + return "", err + } + + var accCfAccessToken string + for _, cookie := range changeAccResp.Cookies() { + if cookie.Name == "cf-access-token" { + accCfAccessToken = cookie.Value + break } } + if accCfAccessToken == "" { + return "", fmt.Errorf("Failed to GetXAccessToken for userId = %s after ChangeAcocunt to %s", userID, accountId) + } - return "", nil + return accCfAccessToken, nil } func (client *Client) GenerateToken(xToken string, apiKey *ApiKey) (string, error) { @@ -219,3 +235,30 @@ func (client *Client) GetApiKeysList() ([]ApiKey, error) { return apiKeys, nil } + +func (client *Client) createRandomUser(accountId string) (string, error) { + // add user + userPrefix := acctest.RandString(10) + userName := "tfuser" + userPrefix + userEmail := userName + "@codefresh.io" + + user, err := client.AddNewUserToAccount(accountId, userName, userEmail) + if err != nil { + return "", err + } + userID := user.ID + + // activate + _, err = client.ActivateUser(userID) + if err != nil { + return "", err + } + + // set user as account admin + err = client.SetUserAsAccountAdmin(accountId, userID) + if err != nil { + return "", nil + } + return userID, nil + +} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index 5b90a959..f44f792b 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -29,6 +29,7 @@ func Provider() *schema.Provider { "codefresh_users": dataSourceUsers(), "codefresh_user": dataSourceUser(), "codefresh_idps": dataSourceIdps(), + "codefresh_account": dataSourceAccount(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), diff --git a/codefresh/resource_api_key.go b/codefresh/resource_api_key.go index af49c189..432f4387 100644 --- a/codefresh/resource_api_key.go +++ b/codefresh/resource_api_key.go @@ -25,6 +25,10 @@ func resourceApiKey() *schema.Resource { Type: schema.TypeString, Required: true, }, + "user_id": { + Type: schema.TypeString, + Required: true, + }, "token": { Type: schema.TypeString, Computed: true, @@ -45,8 +49,9 @@ func resourceApiKeyCreate(d *schema.ResourceData, meta interface{}) error { apiKey := *mapResourceToApiKey(d) accountID := d.Get("account_id").(string) + userID := d.Get("user_id").(string) - resp, err := client.CreateApiKey(accountID, &apiKey) + resp, err := client.CreateApiKey(userID, accountID, &apiKey) if err != nil { fmt.Println(string(resp)) return err From c294d7695bbf9d934ff5ebebe3d803594d4f41c0 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Mon, 27 Jul 2020 16:49:50 +0300 Subject: [PATCH 25/32] team-data --- codefresh/data_account.go | 72 ++++++++++++++++++++++++++++++ codefresh/data_team.go | 94 +++++++++++++++++++++++++++++++++++++++ codefresh/provider.go | 1 + 3 files changed, 167 insertions(+) create mode 100644 codefresh/data_account.go create mode 100644 codefresh/data_team.go diff --git a/codefresh/data_account.go b/codefresh/data_account.go new file mode 100644 index 00000000..97d17366 --- /dev/null +++ b/codefresh/data_account.go @@ -0,0 +1,72 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceAccount() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAccountRead, + Schema: map[string]*schema.Schema{ + "_id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "admins": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + + +func dataSourceAccountRead(d *schema.ResourceData, meta interface{}) error { + + + client := meta.(*cfClient.Client) + var account *cfClient.Account + var err error + + if _id, _idOk := d.GetOk("_id"); _idOk { + account, err = client.GetAccountByID(_id.(string)) + } else if name, nameOk := d.GetOk("name"); nameOk { + account, err = client.GetAccountByName(name.(string)) + } else { + return fmt.Errorf("data.codefresh_account - must specify _id or name") + } + if err != nil { + return err + } + + if account == nil { + return fmt.Errorf("data.codefresh_account - cannot find account") + } + + return mapDataAccountToResource(account, d) + +} + +func mapDataAccountToResource(account *cfClient.Account, d *schema.ResourceData) error { + + if account == nil || account.ID == "" { + return fmt.Errorf("data.codefresh_account - failed to mapDataAccountToResource") + } + d.SetId(account.ID) + + d.Set("_id", account.ID) + d.Set("name", account.Name) + d.Set("admins", account.Admins) + + return nil +} + diff --git a/codefresh/data_team.go b/codefresh/data_team.go new file mode 100644 index 00000000..acf5e247 --- /dev/null +++ b/codefresh/data_team.go @@ -0,0 +1,94 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceTeam() *schema.Resource { + return &schema.Resource{ + Read: dataSourceTeamRead, + Schema: map[string]*schema.Schema{ + "_id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "account_id": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + }, + "users": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + + +func dataSourceTeamRead(d *schema.ResourceData, meta interface{}) error { + + + client := meta.(*cfClient.Client) + var team *cfClient.Team + var err error + + if _id, _idOk := d.GetOk("_id"); _idOk { + team, err = client.GetTeamByID(_id.(string)) + } else if name, nameOk := d.GetOk("name"); nameOk { + // accountID, accountOk := d.GetOk("account_id"); + team, err = client.GetTeamByName(name.(string)) + } + + if err != nil { + return err + } + + if team == nil { + return fmt.Errorf("data.codefresh_team - cannot find team") + } + + return mapDataTeamToResource(team, d) + +} + +func mapDataTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { + + if team == nil || team.ID == "" { + return fmt.Errorf("data.codefresh_team - failed to mapDataTeamToResource") + } + d.SetId(team.ID) + + d.Set("_id", team.ID) + d.Set("account_id", team.Account) + d.Set("type", team.Type) + + var users []string + for _, user := range team.Users { + users = append(users, user.ID) + } + d.Set("users", users) + d.Set("tags", team.Tags) + + return nil +} + diff --git a/codefresh/provider.go b/codefresh/provider.go index f44f792b..741feb43 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -30,6 +30,7 @@ func Provider() *schema.Provider { "codefresh_user": dataSourceUser(), "codefresh_idps": dataSourceIdps(), "codefresh_account": dataSourceAccount(), + "codefresh_team": dataSourceTeam(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), From 612aa5e3ee62c4a181c1fac9dcb3584f1e631711 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Mon, 27 Jul 2020 19:42:45 +0300 Subject: [PATCH 26/32] resource_permission draft --- client/permission.go | 120 ++++++++++++++++++++ codefresh/provider.go | 1 + codefresh/resource_permission.go | 185 +++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 client/permission.go create mode 100644 codefresh/resource_permission.go diff --git a/client/permission.go b/client/permission.go new file mode 100644 index 00000000..ab90c0eb --- /dev/null +++ b/client/permission.go @@ -0,0 +1,120 @@ +package client + +import ( + "fmt" +) + +// Permission spec +type Permission struct { + ID string `json:"_id,omitempty"` + Team string `json:"role,omitempty"` + Resource string `json:"resource,omitempty"` + Action string `json:"action,omitempty"` + Account string `json:"account,omitempty"` + Tags []string `json:"tags,omitempty"` +} + +// GetPermissionList - +func (client *Client) GetPermissionList(teamID, action, resource string) ([]Permission, error) { + fullPath := "/abac" + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var permissions, permissionsFiltered []Permission + + err = DecodeResponseInto(resp, &permissions) + if err != nil { + return nil, err + } + + for _, p := range permissions { + if teamID != "" && p.Team != teamID { + continue + } + if action != "" && p.Action != action { + continue + } + if resource != "" && p.Resource != resource { + continue + } + permissionsFiltered = append(permissionsFiltered, p) + } + + return permissionsFiltered, nil +} + +// GetPermissionByID - +func (client *Client) GetPermissionByID(id string) (*Permission, error) { + fullPath := fmt.Sprintf("/abac/%s", id) + opts := RequestOptions{ + Path: fullPath, + Method: "GET", + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var permission Permission + err = DecodeResponseInto(resp, &permission) + if err != nil { + return nil, err + } + + return &permission, nil +} + +// CreatePermision - +func (client *Client) CreatePermission(permission *Permission) (*Permission, error) { + + body, err := EncodeToJSON(permission) + + if err != nil { + return nil, err + } + opts := RequestOptions{ + Path: "/abac", + Method: "POST", + Body: body, + } + + resp, err := client.RequestAPI(&opts) + + if err != nil { + return nil, err + } + + var newPermission Permission + err = DecodeResponseInto(resp, &newPermission) + if err != nil { + return nil, err + } + + return &newPermission, nil +} + +// DeletePermission - +func (client *Client) DeletePermission(id string) error { + fullPath := fmt.Sprintf("/abac/%s", id) + opts := RequestOptions{ + Path: fullPath, + Method: "DELETE", + } + + _, err := client.RequestAPI(&opts) + + if err != nil { + return err + } + + return nil +} \ No newline at end of file diff --git a/codefresh/provider.go b/codefresh/provider.go index 741feb43..ca3ef43d 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -41,6 +41,7 @@ func Provider() *schema.Provider { "codefresh_idp_accounts": resourceIDPAccounts(), "codefresh_account_admins": resourceAccountAdmins(), "codefresh_user": resourceUser(), + "codefresh_permission": resourcePermission(), }, ConfigureFunc: configureProvider, } diff --git a/codefresh/resource_permission.go b/codefresh/resource_permission.go new file mode 100644 index 00000000..93079363 --- /dev/null +++ b/codefresh/resource_permission.go @@ -0,0 +1,185 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + +) + +func resourcePermission() *schema.Resource { + return &schema.Resource{ + Create: resourcePermissionCreate, + Read: resourcePermissionRead, + Update: resourcePermissionUpdate, + Delete: resourcePermissionDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "team": { + Type: schema.TypeString, + Required: true, + }, + "account": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "resource": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + if v != "cluster" || v != "pipeline" { + errs = append(errs, fmt.Errorf("%q must be between \"pipeline\" or \"cluster\", got: %s", key, v)) + } + return + }, + }, + "action": { + Type: schema.TypeString, + Required: true, + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + if v != "create" || v != "read" || v != "update" || v != "delete" || v != "approve" { + errs = append(errs, fmt.Errorf("%q must be between one of create,read,update,delete,approve, got: %s", key, v)) + } + return + }, + }, + "tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Default: []string{"*", "untagged"}, + }, + }, + } +} + +func resourcePermissionCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + permission := *mapResourceToPermission(d) + + resp, err := client.CreatePermission(&permission) + if err != nil { + return err + } + + d.SetId(resp.ID) + + return resourcePermissionRead(d, meta) +} + +func resourcePermissionRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + + permissionID := d.Id() + if permissionID == "" { + d.SetId("") + return nil + } + + permission, err := client.GetPermissionByID(permissionID) + if err != nil { + return err + } + + err = mapPermissionToResource(permission, d) + if err != nil { + return err + } + + return nil +} + +func resourcePermissionUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + permission := *mapResourceToPermission(d) + + + // existingPermission, err := client.GetPermissionByID(permission.ID) + // if err != nil { + // return nil + // } + + resp, err := client.CreatePermission(&permission) + if err != nil { + return err + } + d.SetId(resp.ID) + + return resourcePermissionRead(d, meta) +} + +func resourcePermissionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + + err := client.DeletePermission(d.Id()) + if err != nil { + return err + } + + return nil +} + +func mapPermissionToResource(permission *cfClient.Permission, d *schema.ResourceData) error { + + err := d.Set("_id", permission.ID) + if err != nil { + return err + } + + err = d.Set("team", permission.Team) + if err != nil { + return err + } + + err = d.Set("account", permission.Account) + if err != nil { + return err + } + + err = d.Set("action", permission.Action) + if err != nil { + return err + } + + err = d.Set("resource", permission.Resource) + if err != nil { + return err + } + + err = d.Set("tags", permission.Tags) + if err != nil { + return err + } + + return nil +} + +func mapResourceToPermission(d *schema.ResourceData) *cfClient.Permission { + + tags := d.Get("tags").(*schema.Set).List() + permission := &cfClient.Permission{ + ID: d.Id(), + Team: d.Get("team").(string), + Action: d.Get("action").(string), + Resource: d.Get("string").(string), + //Account: d.Get("account_id").(string), + Tags: convertStringArr(tags), + } + + return permission +} From db2d3976493e5a2c2df8e11eae67c2d09ed21ff3 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Mon, 27 Jul 2020 23:40:19 +0300 Subject: [PATCH 27/32] resource_permission - done --- client/permission.go | 37 +++++++++++++++++++--- codefresh/resource_permission.go | 53 +++++++++++++++----------------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/client/permission.go b/client/permission.go index ab90c0eb..905f7563 100644 --- a/client/permission.go +++ b/client/permission.go @@ -2,15 +2,26 @@ package client import ( "fmt" + //"log" ) // Permission spec type Permission struct { - ID string `json:"_id,omitempty"` + ID string `json:"id,omitempty"` Team string `json:"role,omitempty"` Resource string `json:"resource,omitempty"` Action string `json:"action,omitempty"` Account string `json:"account,omitempty"` + Tags []string `json:"attributes,omitempty"` +} + +// NewPermission spec, diffs from Permission is `json:"team,omitempty"` vs `json:"role,omitempty"` +type NewPermission struct { + ID string `json:"_id,omitempty"` + Team string `json:"team,omitempty"` + Resource string `json:"resource,omitempty"` + Action string `json:"action,omitempty"` + Account string `json:"account,omitempty"` Tags []string `json:"tags,omitempty"` } @@ -76,7 +87,16 @@ func (client *Client) GetPermissionByID(id string) (*Permission, error) { // CreatePermision - func (client *Client) CreatePermission(permission *Permission) (*Permission, error) { - body, err := EncodeToJSON(permission) + newPermission := &NewPermission{ + ID: permission.ID, + Team: permission.Team, + Resource: permission.Resource, + Action: permission.Action, + Account: permission.Account, + Tags: permission.Tags, + } + + body, err := EncodeToJSON(newPermission) if err != nil { return nil, err @@ -93,13 +113,20 @@ func (client *Client) CreatePermission(permission *Permission) (*Permission, er return nil, err } - var newPermission Permission - err = DecodeResponseInto(resp, &newPermission) + // respStr := string(resp) + // log.Printf("[DEBUG] createPermission responce body = %s", respStr) + var permissionResp []Permission + err = DecodeResponseInto(resp, &permissionResp) if err != nil { return nil, err } + if len(permissionResp) != 1 { + return nil, fmt.Errorf("createPermission - unknown response lenght!=1: %v", permissionResp) + } - return &newPermission, nil + newPermissionID := permissionResp[0].ID + + return client.GetPermissionByID(newPermissionID) } // DeletePermission - diff --git a/codefresh/resource_permission.go b/codefresh/resource_permission.go index 93079363..b51de0ee 100644 --- a/codefresh/resource_permission.go +++ b/codefresh/resource_permission.go @@ -1,7 +1,8 @@ package codefresh import ( - "fmt" + "fmt" + "log" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -26,17 +27,12 @@ func resourcePermission() *schema.Resource { Type: schema.TypeString, Required: true, }, - "account": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, "resource": { Type: schema.TypeString, Required: true, ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) - if v != "cluster" || v != "pipeline" { + if v != "cluster" && v != "pipeline" { errs = append(errs, fmt.Errorf("%q must be between \"pipeline\" or \"cluster\", got: %s", key, v)) } return @@ -47,7 +43,7 @@ func resourcePermission() *schema.Resource { Required: true, ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) - if v != "create" || v != "read" || v != "update" || v != "delete" || v != "approve" { + if v != "create" && v != "read" && v != "update" && v != "delete" && v != "run" && v != "approve" { errs = append(errs, fmt.Errorf("%q must be between one of create,read,update,delete,approve, got: %s", key, v)) } return @@ -59,7 +55,6 @@ func resourcePermission() *schema.Resource { Elem: &schema.Schema{ Type: schema.TypeString, }, - Default: []string{"*", "untagged"}, }, }, } @@ -70,12 +65,15 @@ func resourcePermissionCreate(d *schema.ResourceData, meta interface{}) error { permission := *mapResourceToPermission(d) - resp, err := client.CreatePermission(&permission) + newPermission, err := client.CreatePermission(&permission) if err != nil { return err } + if newPermission == nil { + return fmt.Errorf("resourcePermissionCreate - failed to create permission, empty responce") + } - d.SetId(resp.ID) + d.SetId(newPermission.ID) return resourcePermissionRead(d, meta) } @@ -107,17 +105,16 @@ func resourcePermissionUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*cfClient.Client) permission := *mapResourceToPermission(d) - - - // existingPermission, err := client.GetPermissionByID(permission.ID) - // if err != nil { - // return nil - // } - + permission.ID = "" resp, err := client.CreatePermission(&permission) if err != nil { return err - } + } + + deleteErr := resourcePermissionDelete(d, meta) + if deleteErr != nil { + log.Printf("[WARN] failed to delete permission %v: %v",permission, deleteErr) + } d.SetId(resp.ID) return resourcePermissionRead(d, meta) @@ -146,11 +143,6 @@ func mapPermissionToResource(permission *cfClient.Permission, d *schema.Resource return err } - err = d.Set("account", permission.Account) - if err != nil { - return err - } - err = d.Set("action", permission.Action) if err != nil { return err @@ -171,14 +163,19 @@ func mapPermissionToResource(permission *cfClient.Permission, d *schema.Resource func mapResourceToPermission(d *schema.ResourceData) *cfClient.Permission { - tags := d.Get("tags").(*schema.Set).List() + tagsI := d.Get("tags").(*schema.Set).List() + var tags []string + if len(tagsI) > 0 { + tags = convertStringArr(tagsI) + } else { + tags = []string{"*", "untagged"} + } permission := &cfClient.Permission{ ID: d.Id(), Team: d.Get("team").(string), Action: d.Get("action").(string), - Resource: d.Get("string").(string), - //Account: d.Get("account_id").(string), - Tags: convertStringArr(tags), + Resource: d.Get("resource").(string), + Tags: tags, } return permission From c6bc1cc500374adf2e3d5aaabdc522187271550f Mon Sep 17 00:00:00 2001 From: kosta709 Date: Mon, 27 Jul 2020 23:52:37 +0300 Subject: [PATCH 28/32] doc refactoring --- .../main.tf | 2 +- .../terraform.tfvars | 19 ++++++++++--------- .../vars.tf | 0 .../main.tf | 0 .../output.tf | 0 .../provider.tf | 0 .../vars.tf | 0 7 files changed, 11 insertions(+), 10 deletions(-) rename examples/{access_control => accounts_users}/main.tf (81%) rename examples/{access_control => accounts_users}/terraform.tfvars (69%) rename examples/{access_control => accounts_users}/vars.tf (100%) rename tf_modules/{access_control => accounts_users}/main.tf (100%) rename tf_modules/{access_control => accounts_users}/output.tf (100%) rename tf_modules/{access_control => accounts_users}/provider.tf (100%) rename tf_modules/{access_control => accounts_users}/vars.tf (100%) diff --git a/examples/access_control/main.tf b/examples/accounts_users/main.tf similarity index 81% rename from examples/access_control/main.tf rename to examples/accounts_users/main.tf index 68372d95..574f5a8d 100644 --- a/examples/access_control/main.tf +++ b/examples/accounts_users/main.tf @@ -1,5 +1,5 @@ module "codefresh_access_control" { - source = "../../tf_modules/access_control" + source = "../../tf_modules/accounts_users" api_url = var.api_url default_idps = var.default_idps accounts = var.accounts diff --git a/examples/access_control/terraform.tfvars b/examples/accounts_users/terraform.tfvars similarity index 69% rename from examples/access_control/terraform.tfvars rename to examples/accounts_users/terraform.tfvars index 5136b8ae..abffe62f 100644 --- a/examples/access_control/terraform.tfvars +++ b/examples/accounts_users/terraform.tfvars @@ -1,4 +1,5 @@ -api_url = "https://onprem-tst-1.cf-cd.com/api" +api_url = "https://my-codefresh.example.com/api" +token = "cfAdmin-token" default_idps = { local = { @@ -6,7 +7,7 @@ default_idps = { sso = false } azure_sso = { - display_name = "codefresh-azure-sso-1" + display_name = "azure-sso-1" sso = true } } @@ -23,17 +24,17 @@ accounts = { users = { user1 = { - email = "kosta@codefresh.io" + email = "user1@example.com" personal = { - first_name = "Kosta" - last_name = "A" + first_name = "John" + last_name = "Smith" } accounts = ["acc1", "acc2"] admin_of_accounts = ["acc1"] global_admin = true } user2 = { - email = "live.com#kosta777@gmail.com" + email = "live.com#user2@gmail.com" personal = { first_name = "Q" last_name = "D" @@ -43,10 +44,10 @@ users = { global_admin = false } user3 = { - email = "kosta@sysadmiral.io" + email = "user3@example.com" personal = { - first_name = "Kosta" - last_name = "sysadmiral-io" + first_name = "Sam" + last_name = "Johnson" } accounts = ["acc1", "acc2"] admin_of_accounts = ["acc1", "acc2"] diff --git a/examples/access_control/vars.tf b/examples/accounts_users/vars.tf similarity index 100% rename from examples/access_control/vars.tf rename to examples/accounts_users/vars.tf diff --git a/tf_modules/access_control/main.tf b/tf_modules/accounts_users/main.tf similarity index 100% rename from tf_modules/access_control/main.tf rename to tf_modules/accounts_users/main.tf diff --git a/tf_modules/access_control/output.tf b/tf_modules/accounts_users/output.tf similarity index 100% rename from tf_modules/access_control/output.tf rename to tf_modules/accounts_users/output.tf diff --git a/tf_modules/access_control/provider.tf b/tf_modules/accounts_users/provider.tf similarity index 100% rename from tf_modules/access_control/provider.tf rename to tf_modules/accounts_users/provider.tf diff --git a/tf_modules/access_control/vars.tf b/tf_modules/accounts_users/vars.tf similarity index 100% rename from tf_modules/access_control/vars.tf rename to tf_modules/accounts_users/vars.tf From 16485e940a0786c157f2da676838f7c3e982a30d Mon Sep 17 00:00:00 2001 From: kosta709 Date: Tue, 28 Jul 2020 00:44:06 +0300 Subject: [PATCH 29/32] change_account module --- README.md | 11 ++++- docs/data/account.md | 39 ++++++++++++++++ docs/data/idps.md | 66 +++++++++++++++++++++++++++ docs/data/team.md | 20 ++++++++ docs/resources/permissions.md | 6 +++ tf_modules/change_account/main.tf | 39 ++++++++++++++++ tf_modules/change_account/provider.tf | 4 ++ tf_modules/change_account/vars.tf | 13 ++++++ 8 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 docs/data/account.md create mode 100644 docs/data/idps.md create mode 100644 docs/data/team.md create mode 100644 docs/resources/permissions.md create mode 100644 tf_modules/change_account/main.tf create mode 100644 tf_modules/change_account/provider.tf create mode 100644 tf_modules/change_account/vars.tf diff --git a/README.md b/README.md index 0c8f0e19..37051279 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,12 @@ The provider is still under development, and can be used as a terraform [third-p ## Requirements -- [Terraform](https://www.terraform.io/downloads.html) 0.11+ ; +- [Terraform](https://www.terraform.io/downloads.html) 0.12+ ; - [Go](https://golang.org/doc/install) 1.12+ (to build the provider plugin). +## Download Provider +Download and extract terraform-provider-codefresh from [releases](https://github.com/codefresh-io/terraform-provider-codefresh/releases) + ## Building the Provider ```sh @@ -24,7 +27,11 @@ For Linux OS it can be: - _~/.terraform.d/plugins/linux\_amd64_ - _./terraform.d/plugins/linux\_amd64_. The relative path in your Terraform project. -To configure codefresh provider: +## [Documentations](./docs) + +## [Examples](./examples) + +## To configure codefresh provider: ```hcl provider "codefresh" { diff --git a/docs/data/account.md b/docs/data/account.md new file mode 100644 index 00000000..6945569e --- /dev/null +++ b/docs/data/account.md @@ -0,0 +1,39 @@ +# account data module + +``` +data "codefresh_account" "acc" { + name = "acc1" +} + +resource "codefresh_user" "user1" { + email = "user1@example.com" + user_name = "user1" + + accounts = [ + data.codefresh_account.acc.id + ] + + activate = true + + roles = [ + "Admin", + "User" + ] + + login { + idp_id = data.codefresh_idps.idp_azure.id + sso = true + } + + login { + idp_id = data.codefresh_idps.local.id + //sso = false + } + + + personal { + first_name = "John" + last_name = "Smith" + } +} +``` \ No newline at end of file diff --git a/docs/data/idps.md b/docs/data/idps.md new file mode 100644 index 00000000..828ba029 --- /dev/null +++ b/docs/data/idps.md @@ -0,0 +1,66 @@ +# data codefresh_idps +``` +data "codefresh_idps" "idp_azure" { + display_name = "codefresh-onprem-tst-2" + # client_name = "2222" + # _id = "5df234543" + client_type = "azure" +} + +data "codefresh_idps" "local" { + display_name = "local" +} + +resource "codefresh_account" "acc" { + name = "acc1" + + features = var.accountFeatures + + limits { + collaborators = 25 + data_retention_weeks = 5 + } + + build { + parallel = 25 + nodes = 7 + } + +} + +resource "codefresh_user" "user1" { + email = "user1@example.com" + user_name = "user1" + + activate = true + + roles = [ + "Admin", + "User" + ] + + login { + idp_id = data.codefresh_idps.idp_azure.id + sso = true + } + + login { + idp_id = data.codefresh_idps.local.id + //sso = false + } + + personal { + first_name = "John" + last_name = "Smith" + } + + accounts = [ + codefresh_account.acc.id + ] +} + +resource "codefresh_idp_accounts" "acc_idp" { + idp_id = data.codefresh_idps.idp_azure.id + account_ids = [codefresh_account.acc.id] +} +``` \ No newline at end of file diff --git a/docs/data/team.md b/docs/data/team.md new file mode 100644 index 00000000..b1c3f7de --- /dev/null +++ b/docs/data/team.md @@ -0,0 +1,20 @@ +# data codefresh_team + +*Note*: Teams resources should be called with account specific access token + +``` +data "codefresh_team" "admin" { + provider = codefresh.acc1 + name = "users" +} + +resource "codefresh_permission" "permission2" { + provider = codefresh.acc1 + team = data.codefresh_team.admin.id + action = "create" + resource = "pipeline" + tags = ["frontend"] +} + +``` + diff --git a/docs/resources/permissions.md b/docs/resources/permissions.md new file mode 100644 index 00000000..3395ae81 --- /dev/null +++ b/docs/resources/permissions.md @@ -0,0 +1,6 @@ +# resource codefresh_permission + +``` + + +``` \ No newline at end of file diff --git a/tf_modules/change_account/main.tf b/tf_modules/change_account/main.tf new file mode 100644 index 00000000..9267ff8b --- /dev/null +++ b/tf_modules/change_account/main.tf @@ -0,0 +1,39 @@ +data "codefresh_account" "acc" { + name = var.account_id +} + +resource "random_string" "random" { + length = 16 + special = false +} + +resource "codefresh_api_key" "new" { + account_id = data.codefresh_account.acc.id + user_id = data.codefresh_account.acc.admins[0] + name = "tfkey_${random_string.random.result}" + + scopes = [ + "agent", + "agents", + "audit", + "build", + "cluster", + "clusters", + "environments-v2", + "github-action", + "helm", + "kubernetes", + "pipeline", + "project", + "repos", + "runner-installation", + "step-type", + "step-types", + "view", + "workflow", + ] +} + +output "token" { + value = codefresh_api_key.new.token +} \ No newline at end of file diff --git a/tf_modules/change_account/provider.tf b/tf_modules/change_account/provider.tf new file mode 100644 index 00000000..615d72a3 --- /dev/null +++ b/tf_modules/change_account/provider.tf @@ -0,0 +1,4 @@ +provider "codefresh" { + api_url = var.api_url + token = var.token +} \ No newline at end of file diff --git a/tf_modules/change_account/vars.tf b/tf_modules/change_account/vars.tf new file mode 100644 index 00000000..699159ab --- /dev/null +++ b/tf_modules/change_account/vars.tf @@ -0,0 +1,13 @@ +variable api_url { + type = string +} + +# +variable token { + type = string + default = "" +} + +variable account_id { + type = string +} From e2627f144d7b974ed932c5037d631c9d9035cf41 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Tue, 28 Jul 2020 16:53:07 +0300 Subject: [PATCH 30/32] current account --- .gitignore | 5 ++ client/current_account.go | 87 +++++++++++++++++++ codefresh/data_current_account.go | 76 ++++++++++++++++ codefresh/resource_team.go | 4 + docs/modules/account_token.md | 44 ++++++++++ docs/modules/accounts_users.md | 4 + docs/modules/permissions.md | 2 + docs/modules/teams.md | 1 + examples/account_tokens/main.tf | 24 +++++ examples/account_tokens/terraform.tfvars | 5 ++ go.mod | 1 + .../{change_account => account_token}/main.tf | 12 ++- .../provider.tf | 0 .../{change_account => account_token}/vars.tf | 6 ++ tf_modules/account_tokens/main.tf | 45 ++++++++++ tf_modules/account_tokens/provider.tf | 4 + tf_modules/account_tokens/vars.tf | 15 ++++ tf_modules/accounts_users/output.tf | 2 +- 18 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 client/current_account.go create mode 100644 codefresh/data_current_account.go create mode 100644 docs/modules/account_token.md create mode 100644 docs/modules/accounts_users.md create mode 100644 docs/modules/permissions.md create mode 100644 docs/modules/teams.md create mode 100644 examples/account_tokens/main.tf create mode 100644 examples/account_tokens/terraform.tfvars rename tf_modules/{change_account => account_token}/main.tf (73%) rename tf_modules/{change_account => account_token}/provider.tf (100%) rename tf_modules/{change_account => account_token}/vars.tf (64%) create mode 100644 tf_modules/account_tokens/main.tf create mode 100644 tf_modules/account_tokens/provider.tf create mode 100644 tf_modules/account_tokens/vars.tf diff --git a/.gitignore b/.gitignore index ca574e9f..b0f7e1e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ terraform-provider-codefresh dist/ + +**/.terraform +**/terraform.tfstate +**/terraform.tfstate.backup +tests/ \ No newline at end of file diff --git a/client/current_account.go b/client/current_account.go new file mode 100644 index 00000000..9fd12560 --- /dev/null +++ b/client/current_account.go @@ -0,0 +1,87 @@ +package client + +import ( + "fmt" + "encoding/json" + "github.com/stretchr/objx" +) + +// CurrentAccountUser spec +type CurrentAccountUser struct { + ID string + UserName string + Email string +} + +// CurrentAccount spec +type CurrentAccount struct { + ID string + Name string + Users map[string]CurrentAccountUser +} + +// GetCurrentAccount - +func (client *Client) GetCurrentAccount() (*CurrentAccount, error) { + + // get and parse current account + userResp, err := client.RequestAPI(&RequestOptions{ + Path: "/user", + Method: "GET", + }) + if err != nil { + return nil, err + } + + currentAccountX, err := objx.FromJSON(string(userResp)) + if err != nil { + return nil, err + } + + activeAccountName := currentAccountX.Get("activeAccountName").String() + if activeAccountName == "" { + return nil, fmt.Errorf("GetCurrentAccount - cannot get activeAccountName") + } + currentAccount := &CurrentAccount{ + Name: activeAccountName, + Users: make(map[string]CurrentAccountUser), + } + + allAccountsI := currentAccountX.Get("account").MSISlice() + for _, accI := range(allAccountsI) { + accX := objx.New(accI) + if accX.Get("name").String() == activeAccountName { + currentAccount.ID = accX.Get("id").String() + break + } + } + if currentAccount.ID == "" { + return nil, fmt.Errorf("GetCurrentAccount - cannot get activeAccountName") + } + + // get and parse account users + accountUsersResp, err := client.RequestAPI(&RequestOptions{ + Path: fmt.Sprintf("/accounts/%s/users", currentAccount.ID), + Method: "GET", + }) + if err != nil { + return nil, err + } + + accountUsersI := make([]interface{}, 0) + if e := json.Unmarshal(accountUsersResp, &accountUsersI); e != nil { + return nil, fmt.Errorf("Cannot unmarshal accountUsers responce for accountId=%s: %v", currentAccount.ID, e) + } + for _, userI := range(accountUsersI) { + userX := objx.New(userI) + userName := userX.Get("userX").String() + email := userX.Get("email").String() + userID := userX.Get("_id").String() + currentAccount.Users[userName] = CurrentAccountUser{ + ID: userID, + UserName: userName, + Email: email, + } + } + + return currentAccount, nil +} diff --git a/codefresh/data_current_account.go b/codefresh/data_current_account.go new file mode 100644 index 00000000..0a076716 --- /dev/null +++ b/codefresh/data_current_account.go @@ -0,0 +1,76 @@ +package codefresh + +import ( + "fmt" + cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceCurrentAccount() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCurrentAccountRead, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + }, + "id": { + Type: schema.TypeString, + Optional: true, + }, + "users": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "email": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + } + }, + } +} + + +func dataSourceCurrentAccountRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*cfClient.Client) + var currentAccount *cfClient.CurrentAccount + var err error + + currentAccount, err = client.GetCurrentAccount + if err != nil { + return err + } + + if currentAccount == nil { + return fmt.Errorf("data.codefresh_current_account - failed to get current_account") + } + + return mapDataCurrentAccountToResource(team, d) + +} + +func mapDataCurrentAccountToResource(currentAccount *cfClient.CurrentAccount, d *schema.ResourceData) error { + + if currentAccount == nil || currentAccount.ID == "" { + return fmt.Errorf("data.codefresh_current_account - failed to mapDataCurrentAccountToResource") + } + d.SetId(currentAccount.ID) + + d.Set("id", currentAccount.ID) + d.Set("name", currentAccount.Name) + d.Set("users", currentAccount.Users) + + return nil +} diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 2e9d2934..d5eff329 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -1,6 +1,7 @@ package codefresh import ( + "fmt" cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -136,6 +137,9 @@ func resourceTeamDelete(d *schema.ResourceData, meta interface{}) error { func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { + if team == nil { + return fmt.Errorf("mapTeamToResource - cannot find team") + } err := d.Set("name", team.Name) if err != nil { return err diff --git a/docs/modules/account_token.md b/docs/modules/account_token.md new file mode 100644 index 00000000..2e214b6e --- /dev/null +++ b/docs/modules/account_token.md @@ -0,0 +1,44 @@ +# modules account_token and account_tokens + +To operate with Teams and Permission we should use token generated for Codefresh Account user (not adminCF token) + + +[account_token](../../tf_modules/account_token) - creates and outputs token of single account, for usage in aliased providers + +[account_tokens](../../tf_modules/account_tokens) - creates and outputs token for multiple accounts, for usage in other per-account configurations + +### Example - account_token +```hcl +module "account_token" "acc1_token" { + source = "../../tf_modules/account_token" + account_name = "acc1" +} + +provider "codefresh" { + alias = "acc1" + api_url = var.api_url + token = module.change_account.acc1_token.token +} + +resource "codefresh_team" "developers" { + provider = codefresh.acc1 + name = "developers" + account_id = data.codefresh_account.acc.id + + users = [ + data.codefresh_user.user.id + ] +} + +resource "codefresh_permission" "permission" { + for_each = toset(["run", "create", "update", "delete", "read", "approve"]) + provider = codefresh.acc1 + team = codefresh_team.developers.id + action = each.value + resource = "pipeline" + tags = [ "*", "untagged"] +} + +``` + +### [Example account-tokens](../../examples/account_tokens) \ No newline at end of file diff --git a/docs/modules/accounts_users.md b/docs/modules/accounts_users.md new file mode 100644 index 00000000..e1968e3d --- /dev/null +++ b/docs/modules/accounts_users.md @@ -0,0 +1,4 @@ +# module account_users + +[accounts_users source](../../tf_modules/accounts_users) +[accounts_users example](../../examples/accounts_users) diff --git a/docs/modules/permissions.md b/docs/modules/permissions.md new file mode 100644 index 00000000..6e5ca366 --- /dev/null +++ b/docs/modules/permissions.md @@ -0,0 +1,2 @@ +# module permissions + diff --git a/docs/modules/teams.md b/docs/modules/teams.md new file mode 100644 index 00000000..063732a8 --- /dev/null +++ b/docs/modules/teams.md @@ -0,0 +1 @@ +# module teams \ No newline at end of file diff --git a/examples/account_tokens/main.tf b/examples/account_tokens/main.tf new file mode 100644 index 00000000..4fe05a59 --- /dev/null +++ b/examples/account_tokens/main.tf @@ -0,0 +1,24 @@ +variable api_url { + type = string +} + +# +variable token { + type = string + default = "" +} + +## Set of account names +variable accounts { + type = set(string) +} + +module "account_tokens" { + source = "../../tf_modules/account_tokens" + api_url = var.api_url + accounts = var.accounts +} + +output "account_tokens" { + value = module.account_tokens.tokens +} \ No newline at end of file diff --git a/examples/account_tokens/terraform.tfvars b/examples/account_tokens/terraform.tfvars new file mode 100644 index 00000000..6c09f30f --- /dev/null +++ b/examples/account_tokens/terraform.tfvars @@ -0,0 +1,5 @@ +api_url = "https://my-codefresh-example.com/api" + +accounts = [ +"acc1", "acc2" +] \ No newline at end of file diff --git a/go.mod b/go.mod index db39b88e..ee3cbb8c 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.0-rc.2.0.20200717132200-7435e2abc9d1 github.com/imdario/mergo v0.3.9 + github.com/stretchr/objx v0.1.1 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect ) diff --git a/tf_modules/change_account/main.tf b/tf_modules/account_token/main.tf similarity index 73% rename from tf_modules/change_account/main.tf rename to tf_modules/account_token/main.tf index 9267ff8b..d7715815 100644 --- a/tf_modules/change_account/main.tf +++ b/tf_modules/account_token/main.tf @@ -1,5 +1,7 @@ data "codefresh_account" "acc" { - name = var.account_id + name = var.account_name != ""? var.account_name : "" + _id = var.account_id != ""? var.account_id : "" + } resource "random_string" "random" { @@ -36,4 +38,12 @@ resource "codefresh_api_key" "new" { output "token" { value = codefresh_api_key.new.token +} + +output "account_name" { + value = data.codefresh_account.acc.name +} + +output "account_id" { + value = data.codefresh_account.acc.id } \ No newline at end of file diff --git a/tf_modules/change_account/provider.tf b/tf_modules/account_token/provider.tf similarity index 100% rename from tf_modules/change_account/provider.tf rename to tf_modules/account_token/provider.tf diff --git a/tf_modules/change_account/vars.tf b/tf_modules/account_token/vars.tf similarity index 64% rename from tf_modules/change_account/vars.tf rename to tf_modules/account_token/vars.tf index 699159ab..94f55e9b 100644 --- a/tf_modules/change_account/vars.tf +++ b/tf_modules/account_token/vars.tf @@ -10,4 +10,10 @@ variable token { variable account_id { type = string + default = "" } + +variable account_name { + type = string + default = "" +} \ No newline at end of file diff --git a/tf_modules/account_tokens/main.tf b/tf_modules/account_tokens/main.tf new file mode 100644 index 00000000..482419ca --- /dev/null +++ b/tf_modules/account_tokens/main.tf @@ -0,0 +1,45 @@ +data "codefresh_account" "acc" { + for_each = var.accounts + name = each.value +} + +resource "random_string" "random" { + for_each = var.accounts + length = 5 + special = false +} + +resource "codefresh_api_key" "new" { + for_each = var.accounts + account_id = data.codefresh_account.acc[each.value].id + user_id = data.codefresh_account.acc[each.value].admins[0] + name = "tfkey_${random_string.random[each.value].result}" + + scopes = [ + "agent", + "agents", + "audit", + "build", + "cluster", + "clusters", + "environments-v2", + "github-action", + "helm", + "kubernetes", + "pipeline", + "project", + "repos", + "runner-installation", + "step-type", + "step-types", + "view", + "workflow", + ] +} + +output "tokens" { + value = { + for acc, token in codefresh_api_key.new: + acc => token.token + } +} \ No newline at end of file diff --git a/tf_modules/account_tokens/provider.tf b/tf_modules/account_tokens/provider.tf new file mode 100644 index 00000000..45289179 --- /dev/null +++ b/tf_modules/account_tokens/provider.tf @@ -0,0 +1,4 @@ +provider "codefresh" { + api_url = var.api_url + token = var.admin_token +} \ No newline at end of file diff --git a/tf_modules/account_tokens/vars.tf b/tf_modules/account_tokens/vars.tf new file mode 100644 index 00000000..a2370424 --- /dev/null +++ b/tf_modules/account_tokens/vars.tf @@ -0,0 +1,15 @@ +variable api_url { + type = string +} + +# +variable admin_token { + type = string + default = "" +} + + +## Set of account names +variable accounts { + type = set(string) +} \ No newline at end of file diff --git a/tf_modules/accounts_users/output.tf b/tf_modules/accounts_users/output.tf index ec8a006d..f874b114 100644 --- a/tf_modules/accounts_users/output.tf +++ b/tf_modules/accounts_users/output.tf @@ -9,6 +9,6 @@ output "idps" { output "accounts" { value = { for acc in codefresh_account.acc: - acc.id => acc.name + acc.id => acc.name } } From df0aeef0e0ab26f5ceefea4e3c00a54a029cf8f0 Mon Sep 17 00:00:00 2001 From: kosta709 Date: Tue, 28 Jul 2020 20:10:03 +0300 Subject: [PATCH 31/32] data.current_account --- client/current_account.go | 22 +++++++-------- codefresh/data_account.go | 3 -- codefresh/data_current_account.go | 33 ++++++++++++++++------ codefresh/provider.go | 1 + docs/data/current_accont.md | 41 ++++++++++++++++++++++++++++ examples/{README.md => pipelines.md} | 0 6 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 docs/data/current_accont.md rename examples/{README.md => pipelines.md} (100%) diff --git a/client/current_account.go b/client/current_account.go index 9fd12560..0cae745e 100644 --- a/client/current_account.go +++ b/client/current_account.go @@ -8,16 +8,16 @@ import ( // CurrentAccountUser spec type CurrentAccountUser struct { - ID string - UserName string - Email string + ID string `json:"id,omitempty"` + UserName string `json:"name,omitempty"` + Email string `json:"email,omitempty"` } // CurrentAccount spec type CurrentAccount struct { ID string Name string - Users map[string]CurrentAccountUser + Users []CurrentAccountUser } // GetCurrentAccount - @@ -31,8 +31,8 @@ func (client *Client) GetCurrentAccount() (*CurrentAccount, error) { if err != nil { return nil, err } - - currentAccountX, err := objx.FromJSON(string(userResp)) + userRespStr := string(userResp) + currentAccountX, err := objx.FromJSON(userRespStr) if err != nil { return nil, err } @@ -43,10 +43,10 @@ func (client *Client) GetCurrentAccount() (*CurrentAccount, error) { } currentAccount := &CurrentAccount{ Name: activeAccountName, - Users: make(map[string]CurrentAccountUser), + Users: make([]CurrentAccountUser, 0), } - allAccountsI := currentAccountX.Get("account").MSISlice() + allAccountsI := currentAccountX.Get("account").InterSlice() for _, accI := range(allAccountsI) { accX := objx.New(accI) if accX.Get("name").String() == activeAccountName { @@ -73,14 +73,14 @@ func (client *Client) GetCurrentAccount() (*CurrentAccount, error) { } for _, userI := range(accountUsersI) { userX := objx.New(userI) - userName := userX.Get("userX").String() + userName := userX.Get("userName").String() email := userX.Get("email").String() userID := userX.Get("_id").String() - currentAccount.Users[userName] = CurrentAccountUser{ + currentAccount.Users= append(currentAccount.Users, CurrentAccountUser{ ID: userID, UserName: userName, Email: email, - } + }) } return currentAccount, nil diff --git a/codefresh/data_account.go b/codefresh/data_account.go index 97d17366..0b461dee 100644 --- a/codefresh/data_account.go +++ b/codefresh/data_account.go @@ -29,10 +29,8 @@ func dataSourceAccount() *schema.Resource { } } - func dataSourceAccountRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) var account *cfClient.Account var err error @@ -53,7 +51,6 @@ func dataSourceAccountRead(d *schema.ResourceData, meta interface{}) error { } return mapDataAccountToResource(account, d) - } func mapDataAccountToResource(account *cfClient.Account, d *schema.ResourceData) error { diff --git a/codefresh/data_current_account.go b/codefresh/data_current_account.go index 0a076716..ce29b4f2 100644 --- a/codefresh/data_current_account.go +++ b/codefresh/data_current_account.go @@ -14,12 +14,12 @@ func dataSourceCurrentAccount() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "id": { + "_id": { Type: schema.TypeString, Optional: true, }, "users": { - Type: schema.TypeMap, + Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -37,7 +37,7 @@ func dataSourceCurrentAccount() *schema.Resource { }, }, }, - } + }, }, } } @@ -48,7 +48,7 @@ func dataSourceCurrentAccountRead(d *schema.ResourceData, meta interface{}) erro var currentAccount *cfClient.CurrentAccount var err error - currentAccount, err = client.GetCurrentAccount + currentAccount, err = client.GetCurrentAccount() if err != nil { return err } @@ -57,7 +57,7 @@ func dataSourceCurrentAccountRead(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("data.codefresh_current_account - failed to get current_account") } - return mapDataCurrentAccountToResource(team, d) + return mapDataCurrentAccountToResource(currentAccount, d) } @@ -68,9 +68,26 @@ func mapDataCurrentAccountToResource(currentAccount *cfClient.CurrentAccount, d } d.SetId(currentAccount.ID) - d.Set("id", currentAccount.ID) - d.Set("name", currentAccount.Name) - d.Set("users", currentAccount.Users) + d.Set("_id", currentAccount.ID) + d.Set("name", currentAccount.Name) + + // users := make(map[string](map[string]interface{})) + // for n, user := range currentAccount.Users { + // users[n] = make(map[string]interface{}) + // users[n]["name"] = user.UserName + // users[n]["email"] = user.Email + // users[n]["id"] = user.ID + // } + // d.Set("users", []map[string](map[string]interface{}){users}) + users := make([](map[string]interface{}), len(currentAccount.Users)) + for n, user := range currentAccount.Users { + users[n] = make(map[string]interface{}) + users[n]["name"] = user.UserName + users[n]["email"] = user.Email + users[n]["id"] = user.ID + } + + d.Set("users", users) return nil } diff --git a/codefresh/provider.go b/codefresh/provider.go index ca3ef43d..2ece1068 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -31,6 +31,7 @@ func Provider() *schema.Provider { "codefresh_idps": dataSourceIdps(), "codefresh_account": dataSourceAccount(), "codefresh_team": dataSourceTeam(), + "codefresh_current_account": dataSourceCurrentAccount(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_project": resourceProject(), diff --git a/docs/data/current_accont.md b/docs/data/current_accont.md new file mode 100644 index 00000000..d213d169 --- /dev/null +++ b/docs/data/current_accont.md @@ -0,0 +1,41 @@ +# current_account data module + +Return current account (owner of the token) and its users +```hcl +provider "codefresh" { + api_url = var.api_url + token = var.token +} + +data "codefresh_current_account" "acc" { + +} + + +output "current_ac" { + value = data.codefresh_current_account.acc +} +``` + +The output example: +``` +Outputs: + +current_ac = { + "_id" = "5f1fd9044d0fc94ddff0d745" + "id" = "5f1fd9044d0fc94ddff0d745" + "name" = "acc1" + "users" = [ + { + "email" = "kosta@codefresh.io" + "id" = "5f1fd9094d0fc9c656f0d75a" + "name" = "user1" + }, + { + "email" = "kosta@sysadmiral.io" + "id" = "5f1fd9094d0fc93b52f0d75c" + "name" = "user3" + }, + ] +} +``` \ No newline at end of file diff --git a/examples/README.md b/examples/pipelines.md similarity index 100% rename from examples/README.md rename to examples/pipelines.md From f3b89ad581d862c42354077e3ee98d7f00a112ad Mon Sep 17 00:00:00 2001 From: kosta709 Date: Tue, 28 Jul 2020 22:20:31 +0300 Subject: [PATCH 32/32] teams modules + examples --- docs/{index.md => README.md} | 55 ++++----------------------- docs/modules/account_token.md | 9 ++++- docs/modules/permissions.md | 2 - docs/modules/teams.md | 5 ++- examples/permissions/main.tf | 23 +++++++++++ examples/permissions/provider.tf | 4 ++ examples/permissions/terraform.tfvars | 1 + examples/permissions/vars.tf | 8 ++++ examples/teams/main.tf | 21 ++++++++++ examples/teams/terraform.tfvars | 7 ++++ tf_modules/teams/main.tf | 18 +++++++++ tf_modules/teams/output.tf | 6 +++ tf_modules/teams/vars.tf | 17 +++++++++ 13 files changed, 125 insertions(+), 51 deletions(-) rename docs/{index.md => README.md} (55%) delete mode 100644 docs/modules/permissions.md create mode 100644 examples/permissions/main.tf create mode 100644 examples/permissions/provider.tf create mode 100644 examples/permissions/terraform.tfvars create mode 100644 examples/permissions/vars.tf create mode 100644 examples/teams/main.tf create mode 100644 examples/teams/terraform.tfvars create mode 100644 tf_modules/teams/main.tf create mode 100644 tf_modules/teams/output.tf create mode 100644 tf_modules/teams/vars.tf diff --git a/docs/index.md b/docs/README.md similarity index 55% rename from docs/index.md rename to docs/README.md index e2aa6c2a..68124123 100644 --- a/docs/index.md +++ b/docs/README.md @@ -15,55 +15,16 @@ The Codefresh Provider can be used to configure [Codefresh](https://codefresh.io The Codefresh API requires the [authentication key](https://codefresh.io/docs/docs/integrations/codefresh-api/#authentication-instructions) to authenticate. The key can be passed either as provider's attribute or as environment variable - `CODEFRESH_API_KEY`. -## Example Usage - -```hcl -provider "codefresh" { - token = "xxxxxxxxx.xxxxxxxxxx" -} - -resource "codefresh_project" "project" { - name = "myproject" - - tags = [ - "production", - "docker", - ] - - variables = { - myProjectVar = "value" - } -} - -resource "codefresh_pipeline" "pipeline" { - lifecycle { - ignore_changes = [ - revision - ] - } - - name = "${codefresh_project.project.name}/mypipeline" - - spec { - - spec_template { - repo = "my-github-account/my-repository" - path = "./codefresh.yml" - revision = "master" - context = "github" - } - - variables = { - goVersion = "1.13" - release = "true" - } - } -} -``` - ## Argument Reference The following arguments are supported: - `token` - (Optional) The client API token. This can also be sourced from the `CODEFRESH_API_KEY` environment variable. -- `api_url` -(Optional) Default value - https://g.codefresh.io/api. \ No newline at end of file +- `api_url` -(Optional) Default value - https://g.codefresh.io/api. + +## Recommendation for creation Accounts, Users, Teams, Permissions +* create users and accounts using [accounts_users module](modules/accounts_users.md) and Codefresh Admin token +* Create and save in tf state api_keys using [accounts_token module](modules/accounts_token.md) +* Create teams using [teams module](modules/teams.md) +* Create permissions - (see example)[../examplea/permisssions) + diff --git a/docs/modules/account_token.md b/docs/modules/account_token.md index 2e214b6e..332de346 100644 --- a/docs/modules/account_token.md +++ b/docs/modules/account_token.md @@ -41,4 +41,11 @@ resource "codefresh_permission" "permission" { ``` -### [Example account-tokens](../../examples/account_tokens) \ No newline at end of file +### [Example account-tokens](../../examples/account_tokens) +Output example: +``` + "account_tokens": { + "acc1": "1xxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1", + "acc2": "2xxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2" + } +``` \ No newline at end of file diff --git a/docs/modules/permissions.md b/docs/modules/permissions.md deleted file mode 100644 index 6e5ca366..00000000 --- a/docs/modules/permissions.md +++ /dev/null @@ -1,2 +0,0 @@ -# module permissions - diff --git a/docs/modules/teams.md b/docs/modules/teams.md index 063732a8..6f515693 100644 --- a/docs/modules/teams.md +++ b/docs/modules/teams.md @@ -1 +1,4 @@ -# module teams \ No newline at end of file +# module teams + +[teams source](../../tf_modules/teams) +[teams example](../../examples/teams) \ No newline at end of file diff --git a/examples/permissions/main.tf b/examples/permissions/main.tf new file mode 100644 index 00000000..9fc059af --- /dev/null +++ b/examples/permissions/main.tf @@ -0,0 +1,23 @@ +data "codefresh_team" "admins" { + name = "admins" +} + +data "codefresh_team" "developers" { + name = "developers" +} + +resource "codefresh_permission" "dev_pipeline" { + for_each = toset(["run", "create", "update", "delete", "read"]) + team = data.codefresh_team.developers.id + action = each.value + resource = "pipeline" + tags = [ "dev", "untagged"] +} + +resource "codefresh_permission" "admin_pipeline" { + for_each = toset(["run", "create", "update", "delete", "read", "approve"]) + team = data.codefresh_team.admins.id + action = each.value + resource = "pipeline" + tags = [ "production", "*"] +} diff --git a/examples/permissions/provider.tf b/examples/permissions/provider.tf new file mode 100644 index 00000000..42717d46 --- /dev/null +++ b/examples/permissions/provider.tf @@ -0,0 +1,4 @@ +provider "codefresh" { + api_url = var.api_url + token = var.token # If token isn't set the provider expects the $CODEFRESH_API_KEY env variable +} \ No newline at end of file diff --git a/examples/permissions/terraform.tfvars b/examples/permissions/terraform.tfvars new file mode 100644 index 00000000..f1be2951 --- /dev/null +++ b/examples/permissions/terraform.tfvars @@ -0,0 +1 @@ +api_url = "https://my-codefresh.example.com/api" \ No newline at end of file diff --git a/examples/permissions/vars.tf b/examples/permissions/vars.tf new file mode 100644 index 00000000..90f2b988 --- /dev/null +++ b/examples/permissions/vars.tf @@ -0,0 +1,8 @@ +variable api_url { + type = string +} + +variable token { + type = string + default = "" +} \ No newline at end of file diff --git a/examples/teams/main.tf b/examples/teams/main.tf new file mode 100644 index 00000000..887e1c08 --- /dev/null +++ b/examples/teams/main.tf @@ -0,0 +1,21 @@ +variable api_url { + type = string +} + +variable token { + type = string + default = "" +} +provider "codefresh" { + api_url = var.api_url + token = var.token +} + +variable teams { + type = map(any) +} + +module "teams" { + source = "../../tf_modules/teams" + teams = var.teams +} diff --git a/examples/teams/terraform.tfvars b/examples/teams/terraform.tfvars new file mode 100644 index 00000000..126a560c --- /dev/null +++ b/examples/teams/terraform.tfvars @@ -0,0 +1,7 @@ +api_url = "https://my-codefresh.example.com/api" +token = "" + +teams = { + developers = ["user1", "user3"] + managers = ["user3", "user2"] +} \ No newline at end of file diff --git a/tf_modules/teams/main.tf b/tf_modules/teams/main.tf new file mode 100644 index 00000000..b32f5b93 --- /dev/null +++ b/tf_modules/teams/main.tf @@ -0,0 +1,18 @@ +data "codefresh_current_account" "acc" { + +} + +locals { + user_ids = tomap({ + for u in data.codefresh_current_account.acc.users: + u.name => u.id + }) + +} + +resource "codefresh_team" "teams" { + for_each = var.teams + name = each.key + + users = [for u in each.value: lookup(local.user_ids, u)] +} diff --git a/tf_modules/teams/output.tf b/tf_modules/teams/output.tf new file mode 100644 index 00000000..6d1f6782 --- /dev/null +++ b/tf_modules/teams/output.tf @@ -0,0 +1,6 @@ +output "users" { + value = local.user_ids +} +output "teams" { + value = codefresh_team.teams +} diff --git a/tf_modules/teams/vars.tf b/tf_modules/teams/vars.tf new file mode 100644 index 00000000..a69a9807 --- /dev/null +++ b/tf_modules/teams/vars.tf @@ -0,0 +1,17 @@ +# variable api_url { +# type = string +# } + +# variable token { +# type = string +# default = "" +# } + +# teams map[team_name]usersList +# { +# developers = ["user1", "user3"] +# managers = ["user3", "user2"] +# } +variable teams { + type = map(any) +}