From 4b46eb8b405aae6c4948dda485becb60c9651a65 Mon Sep 17 00:00:00 2001 From: Christian Bongiorno Date: Sat, 4 Sep 2021 08:32:40 -0700 Subject: [PATCH] PTRENG-2827 - all references to atlassian are removed (not just for access tokens). We took the extra step of simplifying client access too --- LICENSE | 1 - README.md | 1 - .../artifactory_permission_target.md | 18 +- go.mod | 2 +- go.sum | 3 - .../datasource_artifactory_file.go | 7 +- .../datasource_artifactory_fileinfo.go | 5 +- pkg/artifactory/provider.go | 91 +++++----- .../resource_artifactory_access_token.go | 163 ++++++++++++------ .../resource_artifactory_access_token_test.go | 93 +++++----- .../resource_artifactory_api_key.go | 9 +- .../resource_artifactory_api_key_test.go | 4 +- .../resource_artifactory_certificate.go | 10 +- .../resource_artifactory_certificate_test.go | 2 +- pkg/artifactory/resource_artifactory_group.go | 52 +++--- .../resource_artifactory_group_test.go | 4 +- .../resource_artifactory_local_repository.go | 21 +-- .../resource_artifactory_permission_target.go | 16 +- .../resource_artifactory_remote_repository.go | 27 ++- ...resource_artifactory_replication_config.go | 15 +- ...e_artifactory_single_replication_config.go | 21 ++- ...ifactory_single_replication_config_test.go | 7 +- pkg/artifactory/resource_artifactory_user.go | 41 ++--- .../resource_artifactory_user_test.go | 3 +- ...resource_artifactory_virtual_repository.go | 17 +- ...rce_artifactory_virtual_repository_test.go | 10 +- pkg/artifactory/util.go | 15 +- 27 files changed, 331 insertions(+), 327 deletions(-) diff --git a/LICENSE b/LICENSE index 2277fcf0..8821a5f1 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,6 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 Atlassian Pty Ltd Copyright 2020 JFrog Ltd Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/README.md b/README.md index 24e62681..e5a21939 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,6 @@ and is willing to have it used in distributions and derivative works [Sign the CLA](https://cla-assistant.io/jfrog/terraform-provider-artifactory) ## License -Copyright (c) 2019 Atlassian and others. Copyright (c) 2020 JFrog. Apache 2.0 licensed, see [LICENSE][LICENSE] file. diff --git a/docs/resources/artifactory_permission_target.md b/docs/resources/artifactory_permission_target.md index 09556ac4..14249b0d 100644 --- a/docs/resources/artifactory_permission_target.md +++ b/docs/resources/artifactory_permission_target.md @@ -1,8 +1,6 @@ # Artifactory Permission Target Resource -**Requires Artifactory >= 6.6.0.** - -***permissions target V1 is no longer supported*** +**Requires Artifactory >= 6.6.0. If using a lower version see [here](./artifactory_permission_target_v1.md)** Provides an Artifactory permission target resource. This can be used to create and manage Artifactory permission targets. @@ -42,18 +40,6 @@ resource "artifactory_permission_target" "test-perm" { } } } - - release_bundle { - includes_pattern = ["**"] - repositories = ["example-repo-local"] - - actions { - users { - name = "anonymous" - permissions = ["read", "write"] - } - } - } } ``` @@ -70,9 +56,7 @@ The following arguments are supported: * `users` - (Optional) Users this permission target applies for. * `groups` - (Optional) Groups this permission applies for. * `build` - (Optional) As for repo but for artifactory-build-info permssions. -* `release_bundle` - (Optional) -Please see the docs [here](https://www.jfrog.com/confluence/display/JFROG/Security+Configuration+JSON#SecurityConfigurationJSON-application/vnd.org.jfrog.artifactory.security.PermissionTarget+json) ## Import Permission targets can be imported using their name, e.g. diff --git a/go.mod b/go.mod index 0310a02e..799dbbba 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/jfrog/terraform-provider-artifactory require ( - github.com/atlassian/go-artifactory/v2 v2.5.0 github.com/go-resty/resty/v2 v2.4.0 + github.com/google/go-querystring v1.0.0 github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/terraform-plugin-sdk v1.7.0 diff --git a/go.sum b/go.sum index 58a78f85..b16e4797 100644 --- a/go.sum +++ b/go.sum @@ -30,9 +30,6 @@ github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/ 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= -github.com/atlassian/go-artifactory/v2 v2.3.0/go.mod h1:mMEbxu89yTyKev4mysL03aSioTEdZ8+08KuMGG7myUY= -github.com/atlassian/go-artifactory/v2 v2.5.0 h1:NKs9kuGgb2Gj+pU+Y7BzFlx6D/e6P82zP3m/FJZpy40= -github.com/atlassian/go-artifactory/v2 v2.5.0/go.mod h1:mMEbxu89yTyKev4mysL03aSioTEdZ8+08KuMGG7myUY= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= 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= diff --git a/pkg/artifactory/datasource_artifactory_file.go b/pkg/artifactory/datasource_artifactory_file.go index 8867e9e2..4a49928d 100644 --- a/pkg/artifactory/datasource_artifactory_file.go +++ b/pkg/artifactory/datasource_artifactory_file.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/go-resty/resty/v2" "io" "os" @@ -102,14 +103,12 @@ func dataSourceArtifactoryFile() *schema.Resource { } func dataSourceFileRead(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - repository := d.Get("repository").(string) path := d.Get("path").(string) outputPath := d.Get("output_path").(string) forceOverwrite := d.Get("force_overwrite").(bool) fileInfo := FileInfo{} - _,err := client.R().SetResult(&fileInfo).Get(fmt.Sprintf("artifactory/api/storage/%s/%s", repository, path)) + _,err := m.(*resty.Client).R().SetResult(&fileInfo).Get(fmt.Sprintf("artifactory/api/storage/%s/%s", repository, path)) if err != nil { return err } @@ -129,7 +128,7 @@ func dataSourceFileRead(d *schema.ResourceData, m interface{}) error { _ = outFile.Close() }(outFile) - _, err = client.R().SetOutput(outputPath).Get(fileInfo.DownloadUri) + _, err = m.(*resty.Client).R().SetOutput(outputPath).Get(fileInfo.DownloadUri) if err != nil { return err } diff --git a/pkg/artifactory/datasource_artifactory_fileinfo.go b/pkg/artifactory/datasource_artifactory_fileinfo.go index 14dcff27..de1ce23d 100644 --- a/pkg/artifactory/datasource_artifactory_fileinfo.go +++ b/pkg/artifactory/datasource_artifactory_fileinfo.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -67,13 +68,11 @@ func dataSourceArtifactoryFileInfo() *schema.Resource { } func dataSourceFileInfoRead(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - repository := d.Get("repository").(string) path := d.Get("path").(string) fileInfo := FileInfo{} - _, err := c.R().SetResult(&fileInfo).Get(fmt.Sprintf("artifactory/api/storage/%s/%s", repository, path)) + _, err := m.(*resty.Client).R().SetResult(&fileInfo).Get(fmt.Sprintf("artifactory/api/storage/%s/%s", repository, path)) if err != nil { return err } diff --git a/pkg/artifactory/provider.go b/pkg/artifactory/provider.go index 42a5c39f..634c0260 100644 --- a/pkg/artifactory/provider.go +++ b/pkg/artifactory/provider.go @@ -2,25 +2,22 @@ package artifactory import ( "fmt" - artifactoryold "github.com/atlassian/go-artifactory/v2/artifactory" "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/jasonwbarnett/go-xray/xray" "github.com/jfrog/jfrog-client-go/http/jfroghttpclient" - "github.com/jfrog/jfrog-client-go/utils/log" "net/http" "net/url" ) - - var Version = "2.2.16" + const repositoriesEndpoint = "artifactory/api/repositories/" type ArtClient struct { - ArtOld *artifactoryold.Artifactory + ArtNew *jfroghttpclient.JfrogHttpClient Xray *xray.Xray Resty *resty.Client @@ -32,28 +29,28 @@ func Provider() terraform.ResourceProvider { p := &schema.Provider{ Schema: map[string]*schema.Schema{ "url": { - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_URL", func() (interface{}, error) { - return "http://localhost:8082",nil + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_URL", func() (interface{}, error) { + return "http://localhost:8082", nil }), ValidateFunc: validation.IsURLWithHTTPorHTTPS, }, "username": { - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_USERNAME", func() (interface{}, error) { - return "admin",nil + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_USERNAME", func() (interface{}, error) { + return "admin", nil }), ConflictsWith: []string{"access_token", "api_key"}, ValidateFunc: validation.StringIsNotEmpty, }, "password": { - Type: schema.TypeString, - Optional: true, - Sensitive: true, - DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_PASSWORD", func() (interface{}, error) { - return "password",nil + Type: schema.TypeString, + Optional: true, + Sensitive: true, + DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_PASSWORD", func() (interface{}, error) { + return "password", nil }), ConflictsWith: []string{"access_token", "api_key"}, ValidateFunc: validation.StringIsNotEmpty, @@ -111,15 +108,9 @@ func Provider() terraform.ResourceProvider { return p } -func buildResty(d *schema.ResourceData, terraformVersion string) (*resty.Client, error) { +func buildResty(URL string) (*resty.Client, error) { - if key, ok := d.GetOk("url"); key == nil || key == "" || !ok { - return nil, fmt.Errorf("you must supply a URL") - } - - log.SetLogger(log.NewLogger(log.INFO, nil)) - - u, err := url.ParseRequestURI(d.Get("url").(string)) + u, err := url.ParseRequestURI(URL) if err != nil { return nil, err @@ -134,48 +125,56 @@ func buildResty(d *schema.ResourceData, terraformVersion string) (*resty.Client, } return nil }). - SetHeader("content-type", "application/json"). - SetHeader("accept", "*/*"). - SetHeader("user-agent", "jfrog/terraform-provider-artifactory:"+Version) + SetHeader("content-type", "application/json"). + SetHeader("accept", "*/*"). + SetHeader("user-agent", "jfrog/terraform-provider-artifactory:"+Version) + restyBase.DisableWarn = true + return restyBase, nil - username := d.Get("username").(string) - password := d.Get("password").(string) - apiKey := d.Get("api_key").(string) - accessToken := d.Get("access_token").(string) +} + +func addAuthToResty(client *resty.Client, username, password, apiKey, accessToken string) (*resty.Client, error) { if username != "" && password != "" { - restyBase = restyBase.SetBasicAuth(username, password) + return client.SetBasicAuth(username, password), nil } if apiKey != "" { - restyBase = restyBase.SetHeader("X-JFrog-Art-Api", apiKey) + return client.SetHeader("X-JFrog-Art-Api", apiKey), nil } if accessToken != "" { - restyBase = restyBase.SetAuthToken(accessToken) + return client.SetAuthToken(accessToken), nil } - restyBase.DisableWarn = true - return restyBase, nil + return nil, fmt.Errorf("no authentication details supplied") } // Creates the client for artifactory, will prefer token auth over basic auth if both set func providerConfigure(d *schema.ResourceData, terraformVersion string) (interface{}, error) { - restyBase, err := buildResty(d, terraformVersion) + URL, ok := d.GetOk("url") + if URL == nil || URL == "" || !ok { + return nil, fmt.Errorf("you must supply a URL") + } + + restyBase, err := buildResty(URL.(string)) if err != nil { return nil, err } - _, err = sendUsageRepo(restyBase, terraformVersion) + username := d.Get("username").(string) + password := d.Get("password").(string) + apiKey := d.Get("api_key").(string) + accessToken := d.Get("access_token").(string) + restyBase, err = addAuthToResty(restyBase, username, password, apiKey, accessToken) if err != nil { return nil, err } + _, err = sendUsageRepo(restyBase, terraformVersion) - rt := &ArtClient{ - ArtOld: nil, - ArtNew: nil, - Xray: nil, - Resty: restyBase, + if err != nil { + return nil, err } - return rt, nil + + return restyBase, nil } diff --git a/pkg/artifactory/resource_artifactory_access_token.go b/pkg/artifactory/resource_artifactory_access_token.go index 31731dd2..bcedcdfb 100644 --- a/pkg/artifactory/resource_artifactory_access_token.go +++ b/pkg/artifactory/resource_artifactory_access_token.go @@ -1,22 +1,56 @@ package artifactory import ( - "context" "errors" "fmt" + "github.com/go-resty/resty/v2" + "github.com/google/go-querystring/query" "log" "net/http" + "regexp" "strconv" "strings" "time" - "github.com/atlassian/go-artifactory/v2/artifactory" - artifactoryold "github.com/atlassian/go-artifactory/v2/artifactory" - v1 "github.com/atlassian/go-artifactory/v2/artifactory/v1" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) +// AccessTokenRevokeOptions jfrog client go has no v1 code and moving to v2 would be a lot of work. +// To remove the dependency, we copy and past it here +type AccessTokenRevokeOptions struct { + Token string `url:"token,omitempty"` +} +type AccessTokenOptions struct { + // The grant type used to authenticate the request. In this case, the only value supported is "client_credentials" which is also the default value if this parameter is not specified. + GrantType string `url:"grant_type,omitempty"` // [Optional, default: "client_credentials"] + // The user name for which this token is created. If the user does not exist, a transient user is created. Non-admin users can only create tokens for themselves so they must specify their own username. + // If the user does not exist, the member-of-groups scope token must be provided (e.g. member-of-groups: g1, g2, g3...) + Username string `url:"username,omitempty"` + // The scope to assign to the token provided as a space-separated list of scope tokens. Currently there are three possible scope tokens: + // - "api:*" - indicates that the token grants access to REST API calls. This is always granted by default whether specified in the call or not. + // - member-of-groups:[] - indicates the groups that the token is associated with (e.g. member-of-groups: g1, g2, g3...). The token grants access according to the permission targets specified for the groups listed. + // Specify "*" for group-name to indicate that the token should provide the same access privileges that are given to the group of which the logged in user is a member. + // A non-admin user can only provide a scope that is a subset of the groups to which he belongs + // - "jfrt@:admin" - provides admin privileges on the specified Artifactory instance. This is only available for administrators. + // If omitted and the username specified exists, the token is granted the scope of that user. + Scope string `url:"scope,omitempty"` // [Optional if the user specified in username exists] + // The time in seconds for which the token will be valid. To specify a token that never expires, set to zero. Non-admin can only set a value that is equal to or less than the default 3600. + ExpiresIn int `url:"expires_in,omitempty"` // [Optional, default: 3600] + // If true, this token is refreshable and the refresh token can be used to replace it with a new token once it expires. + Refreshable string `url:"refreshable,omitempty"` // [Optional, default: false] + // A space-separate list of the other Artifactory instances or services that should accept this token identified by their Artifactory Service IDs as obtained from the Get Service ID endpoint. + // In case you want the token to be accepted by all Artifactory instances you may use the following audience parameter "audience=jfrt@*". + Audience string `url:"audience,omitempty"` // [Optional, default: Only the Service ID of the Artifactory instance that created the token] +} +type AccessToken struct { + AccessToken string `json:"access_token,omitempty"` + ExpiresIn int `json:"expires_in,omitempty"` + Scope string `json:"scope,omitempty"` + TokenType string `json:"token_type,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` +} + func resourceArtifactoryAccessToken() *schema.Resource { return &schema.Resource{ Create: resourceAccessTokenCreate, @@ -63,6 +97,7 @@ func resourceArtifactoryAccessToken() *schema.Resource { return nil, nil }, + AtLeastOneOf: []string{"end_date", "end_date_relative"}, }, "end_date": { Type: schema.TypeString, @@ -83,6 +118,7 @@ func resourceArtifactoryAccessToken() *schema.Resource { return warnings, errors }, + AtLeastOneOf: []string{"end_date", "end_date_relative"}, }, "refreshable": { Type: schema.TypeBool, @@ -122,10 +158,10 @@ func resourceArtifactoryAccessToken() *schema.Resource { } func resourceAccessTokenCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).ArtOld + client := m.(*resty.Client) grantType := "client_credentials" // client_credentials is the only supported type - tokenOptions := v1.AccessTokenOptions{} + tokenOptions := AccessTokenOptions{} resourceData := &ResourceData{d} date, expiresIn, err := getDate(d) @@ -142,10 +178,10 @@ func resourceAccessTokenCreate(d *schema.ResourceData, m interface{}) error { refreshable := resourceData.Get("refreshable").(bool) audience := d.Get("audience").(string) - tokenOptions.Audience = artifactory.String(audience) - tokenOptions.GrantType = &grantType - tokenOptions.Refreshable = artifactory.String(strconv.FormatBool(refreshable)) - tokenOptions.Username = resourceData.getStringRef("username", false) + tokenOptions.Audience = audience + tokenOptions.GrantType = grantType + tokenOptions.Refreshable = strconv.FormatBool(refreshable) + tokenOptions.Username = resourceData.getString("username", false) username := resourceData.Get("username").(string) userExists, _ := checkUserExists(client, username) @@ -164,21 +200,30 @@ func resourceAccessTokenCreate(d *schema.ResourceData, m interface{}) error { return err } - accessToken, _, err := client.V1.Security.CreateToken(context.Background(), &tokenOptions) + accessToken := AccessToken{} + values, err := query.Values(tokenOptions) if err != nil { return err } + _, err = m.(*resty.Client).R(). + SetHeader("Content-Type", "application/x-www-form-urlencoded"). + SetResult(&accessToken). + SetFormDataFromValues(values).Post("artifactory/api/security/token") - d.SetId(strconv.Itoa(hashcode.String(*accessToken.AccessToken))) + if err != nil { + return err + } - err = d.Set("access_token", *accessToken.AccessToken) + d.SetId(strconv.Itoa(hashcode.String(accessToken.AccessToken))) + + err = d.Set("access_token", accessToken.AccessToken) if err != nil { return err } refreshToken := "" if refreshable { - refreshToken = *accessToken.RefreshToken + refreshToken = accessToken.RefreshToken } err = d.Set("refresh_token", refreshToken) @@ -195,8 +240,6 @@ func resourceAccessTokenRead(_ *schema.ResourceData, _ interface{}) error { } func resourceAccessTokenDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).ArtOld - // Artifactory only allows you to revoke a token if the there is no expiry. // Otherwise, Artifactory will ensure the token is revoked at the expiry time. // https://www.jfrog.com/confluence/display/JFROG/Access+Tokens#AccessTokens-ViewingandRevokingTokens @@ -220,20 +263,28 @@ func resourceAccessTokenDelete(d *schema.ResourceData, m interface{}) error { // Therefore revoke the token. if duration.Seconds() == 0 { log.Printf("[DEBUG] Revoking token") - revokeOptions := v1.AccessTokenRevokeOptions{} + revokeOptions := AccessTokenRevokeOptions{} revokeOptions.Token = d.Get("access_token").(string) - - _, resp, err := client.V1.Security.RevokeToken(context.Background(), revokeOptions) + values, err := query.Values(revokeOptions) + resp, err := m.(*resty.Client).R(). + SetHeader("Content-Type", "application/x-www-form-urlencoded"). + SetFormDataFromValues(values).Post("artifactory/api/security/token/revoke") if err != nil { + if resp != nil { + if resp.StatusCode() == http.StatusNotFound { + log.Printf("[DEBUG] Token Revoked") + return nil + } + // the original atlassian code considered any error code fine. However, expiring tokens can't be revoked + regex := regexp.MustCompile(`.*Token not revocable.*`) + if regex.MatchString(string(resp.Body()[:])) { + return nil + } + } return err } - - if resp.StatusCode == http.StatusNotFound { - log.Printf("[DEBUG] Token Revoked") - return nil - } - return err + return nil } // If the duration is set, Artifactory will automatically revoke the token. @@ -242,7 +293,7 @@ func resourceAccessTokenDelete(d *schema.ResourceData, m interface{}) error { return nil } -func unpackGroups(d *schema.ResourceData, client *artifactoryold.Artifactory, tokenOptions *v1.AccessTokenOptions) error { +func unpackGroups(d *schema.ResourceData, client *resty.Client, tokenOptions *AccessTokenOptions) error { if srcGroups, ok := d.GetOk("groups"); ok { groups := make([]string, len(srcGroups.([]interface{}))) for i, group := range srcGroups.([]interface{}) { @@ -255,13 +306,13 @@ func unpackGroups(d *schema.ResourceData, client *artifactoryold.Artifactory, to scopedGroupString := strings.Join(groups[:], ",") scope := "member-of-groups:\"" + scopedGroupString + "\"" - tokenOptions.Scope = &scope + tokenOptions.Scope = scope } return nil } -func unpackAdminToken(d *schema.ResourceData, tokenOptions *v1.AccessTokenOptions) error { +func unpackAdminToken(d *schema.ResourceData, tokenOptions *AccessTokenOptions) error { if adminToken, ok := d.GetOk("admin_token"); ok { set := adminToken.(*schema.Set) val := set.List()[0].(map[string]interface{}) @@ -269,47 +320,49 @@ func unpackAdminToken(d *schema.ResourceData, tokenOptions *v1.AccessTokenOption instanceID := val["instance_id"].(string) scope := "jfrt@" + instanceID + ":admin" - tokenOptions.Scope = &scope + tokenOptions.Scope = scope } return nil } -func checkUserExists(client *artifactoryold.Artifactory, name string) (bool, error) { - _, resp, err := client.V1.Security.GetUser(context.Background(), name) +func checkUserExists(client *resty.Client, name string) (bool, error) { + resp, err := client.R().Head("artifactory/api/security/users/" + name) + if err != nil { - return false, err - } - // If there is an error, it possible the user does not exist. - if resp != nil { - // Check if the user does not exist in artifactory - if resp.StatusCode == http.StatusNotFound { - return false, errors.New("user must exist in artifactory") - } + // If there is an error, it possible the user does not exist. + if resp != nil { + // Check if the user does not exist in artifactory + if resp.StatusCode() == http.StatusNotFound { + return false, errors.New("user must exist in artifactory") + } - // If we cannot search for Users, the current user is not an admin - // So, we'll let this through and let the CreateToken function error if there is a misconfiguration. - if resp.StatusCode == http.StatusForbidden { - return true, nil + // If we cannot search for Users, the current user is not an admin + // So, we'll let this through and let the CreateToken function error if there is a misconfiguration. + if resp.StatusCode() == http.StatusForbidden { + return true, nil + } } + return false, err } - return false, err + + return true, nil } -func checkGroupExists(client *artifactoryold.Artifactory, name string) (bool, error) { - _, resp, err := client.V1.Security.GetGroup(context.Background(), name) +func checkGroupExists(client *resty.Client, name string) (bool, error) { + resp, err := client.R().Head(groupsEndpoint + name) // If there is an error, it possible the group does not exist. if err != nil { if resp != nil { // Check if the group does not exist in artifactory - if resp.StatusCode == http.StatusNotFound { + if resp.StatusCode() == http.StatusNotFound { return false, errors.New("group must exist in artifactory") } // If we cannot search for groups, the current user is not an admin and they can only specify groups they belong to. // Therefore, we return true and rely on Artifactory to error if the user has specified a wrong group. - if resp.StatusCode == http.StatusForbidden { + if resp.StatusCode() == http.StatusForbidden { return true, nil } } @@ -321,7 +374,7 @@ func checkGroupExists(client *artifactoryold.Artifactory, name string) (bool, er } // Inspired by azure ad implementation -func getDate(d *schema.ResourceData) (*time.Time, *int, error) { +func getDate(d *schema.ResourceData) (time.Time, int, error) { var endDate time.Time now := time.Now() @@ -329,28 +382,28 @@ func getDate(d *schema.ResourceData) (*time.Time, *int, error) { var err error endDate, err = time.Parse(time.RFC3339, v) if err != nil { - return nil, nil, fmt.Errorf("unable to parse the provided end date %q: %+v", v, err) + return endDate, -1, fmt.Errorf("unable to parse the provided end date %q: %+v", v, err) } } else if v := d.Get("end_date_relative").(string); v != "" { d, err := time.ParseDuration(v) if err != nil { - return nil, nil, fmt.Errorf("unable to parse `end_date_relative` %s as a duration", v) + return endDate, -1, fmt.Errorf("unable to parse `end_date_relative` %s as a duration", v) } // Artifactory's minimum duration is in seconds. // The consumer should either specify 0 for a non-expiring token, or >= 1 seconds // If the consumer passes in configuration that is between 0 and 1 seconds, they have used a smaller time unit that seconds. if d.Nanoseconds() > 0 && d.Seconds() < 1 { - return nil, nil, fmt.Errorf("minimum duration is 1 second, but `end_date_relative` is %s", v) + return endDate, -1, fmt.Errorf("minimum duration is 1 second, but `end_date_relative` is %s", v) } endDate = time.Now().Add(d) } else { - return nil, nil, fmt.Errorf("one of `end_date` or `end_date_relative` must be specified") + return endDate, -1, fmt.Errorf("one of `end_date` or `end_date_relative` must be specified") } differenceInSeconds := int(endDate.Sub(now).Seconds()) if differenceInSeconds < 0 { - return nil, nil, fmt.Errorf("end date must be in the future, but is %s", endDate.String()) + return endDate, -1, fmt.Errorf("end date must be in the future, but is %s", endDate.String()) } - return &endDate, &differenceInSeconds, nil + return endDate, differenceInSeconds, nil } diff --git a/pkg/artifactory/resource_artifactory_access_token_test.go b/pkg/artifactory/resource_artifactory_access_token_test.go index 750dab0a..7685fd71 100644 --- a/pkg/artifactory/resource_artifactory_access_token_test.go +++ b/pkg/artifactory/resource_artifactory_access_token_test.go @@ -1,7 +1,6 @@ package artifactory import ( - "context" "fmt" "net/http" "os" @@ -9,30 +8,29 @@ import ( "testing" "time" - artifactoryold "github.com/atlassian/go-artifactory/v2/artifactory" - "github.com/atlassian/go-artifactory/v2/artifactory/transport" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" - "github.com/jfrog/jfrog-client-go/artifactory/auth" ) -const audienceBad = ` -resource "artifactory_user" "existinguser" { - name = "existinguser" - email = "existinguser@a.com" - admin = false - groups = ["readers"] -} -resource "artifactory_access_token" "foobar" { - end_date_relative = "1s" - username = artifactory_user.existinguser.name - audience = "bad" - refreshable = true -} -` func TestAccAccessTokenAudienceBad(t *testing.T) { + const audienceBad = ` + resource "artifactory_user" "existinguser" { + name = "existinguser" + email = "existinguser@a.com" + admin = false + groups = ["readers"] + password = "Passsword1" + } + + resource "artifactory_access_token" "foobar" { + end_date_relative = "1s" + username = artifactory_user.existinguser.name + audience = "bad" + refreshable = true + } + ` resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, CheckDestroy: testAccCheckAccessTokenNotCreated("artifactory_access_token.foobar"), @@ -46,23 +44,25 @@ func TestAccAccessTokenAudienceBad(t *testing.T) { }) } -const audienceGood = ` -resource "artifactory_user" "existinguser" { - name = "existinguser" - email = "existinguser@a.com" - admin = false - groups = ["readers"] -} -resource "artifactory_access_token" "foobar" { - end_date_relative = "1s" - username = artifactory_user.existinguser.name - audience = "jfrt@*" - refreshable = true -} -` func TestAccAccessTokenAudienceGood(t *testing.T) { + const audienceGood = ` + resource "artifactory_user" "existinguser" { + name = "existinguser" + email = "existinguser@a.com" + admin = false + groups = ["readers"] + password = "Passsword1" + } + + resource "artifactory_access_token" "foobar" { + end_date_relative = "1s" + username = artifactory_user.existinguser.name + audience = "jfrt@*" + refreshable = true + } + ` resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, CheckDestroy: testAccCheckAccessTokenDestroy("artifactory_access_token.foobar"), @@ -90,6 +90,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -130,6 +131,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -166,6 +168,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -196,6 +199,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -228,6 +232,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -321,6 +326,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -352,6 +358,7 @@ resource "artifactory_user" "existinguser" { email = "existinguser@a.com" admin = false groups = ["readers"] + password = "Passsword1" } resource "artifactory_access_token" "foobar" { @@ -400,29 +407,21 @@ func testAccCheckAccessTokenDestroy(id string) func(*terraform.State) error { // Create a new client to auth to Artifactory // We want to check that the token cannot authenticate url := os.Getenv("ARTIFACTORY_URL") - var client *http.Client - details := auth.NewArtifactoryDetails() - - details.SetUrl(url) - accessToken := rs.Primary.Attributes["access_token"] - details.SetAccessToken(accessToken) - tp := &transport.AccessTokenAuth{ - AccessToken: accessToken, + resty, err := buildResty(url) + if err != nil { + return err } - client = tp.Client() - - rtold, err := artifactoryold.NewClient(url, client) - + accessToken := rs.Primary.Attributes["access_token"] + resty, err = addAuthToResty(resty, "", "", accessToken, "") if err != nil { return err } - - if _, resp, err := rtold.V1.System.Ping(context.Background()); err != nil { + if resp, err := resty.R().Get("artifactory/api/system/ping"); err != nil { if resp == nil { return fmt.Errorf("no response returned for testAccCheckAccessTokenDestroy") } - if resp.StatusCode == http.StatusUnauthorized { + if resp.StatusCode() == http.StatusForbidden { return nil } return fmt.Errorf("failed to ping server. Got %s", err) diff --git a/pkg/artifactory/resource_artifactory_api_key.go b/pkg/artifactory/resource_artifactory_api_key.go index eb480281..f3593515 100644 --- a/pkg/artifactory/resource_artifactory_api_key.go +++ b/pkg/artifactory/resource_artifactory_api_key.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "strconv" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" @@ -48,10 +49,9 @@ func packApiKey(apiKey string, d *schema.ResourceData) error { } func resourceApiKeyCreate(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty data := make(map[string]string) - _, err := c.R().SetResult(&data).Post(apiKeyEndpoint) + _, err := m.(*resty.Client).R().SetResult(&data).Post(apiKeyEndpoint) if err != nil { return err } @@ -64,9 +64,8 @@ func resourceApiKeyCreate(d *schema.ResourceData, m interface{}) error { } func resourceApiKeyRead(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty data := make(map[string]string) - _, err := client.R().SetResult(&data).Get(apiKeyEndpoint) + _, err := m.(*resty.Client).R().SetResult(&data).Get(apiKeyEndpoint) if err != nil { return err } @@ -79,6 +78,6 @@ func resourceApiKeyRead(d *schema.ResourceData, m interface{}) error { } func apiKeyRevoke(_ *schema.ResourceData, m interface{}) error { - _, err := m.(*ArtClient).Resty.R().Delete(apiKeyEndpoint) + _, err := m.(*resty.Client).R().Delete(apiKeyEndpoint) return err } diff --git a/pkg/artifactory/resource_artifactory_api_key_test.go b/pkg/artifactory/resource_artifactory_api_key_test.go index b70e3058..64042857 100644 --- a/pkg/artifactory/resource_artifactory_api_key_test.go +++ b/pkg/artifactory/resource_artifactory_api_key_test.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -32,8 +33,7 @@ func TestAccApiKey(t *testing.T) { func testAccCheckApiKeyDestroy(id string) func(*terraform.State) error { return func(s *terraform.State) error { - apis := testAccProvider.Meta().(*ArtClient) - client := apis.Resty + client := testAccProvider.Meta().(*resty.Client) rs, ok := s.RootModule().Resources[id] if !ok { diff --git a/pkg/artifactory/resource_artifactory_certificate.go b/pkg/artifactory/resource_artifactory_certificate.go index 3c39441f..4089765f 100644 --- a/pkg/artifactory/resource_artifactory_certificate.go +++ b/pkg/artifactory/resource_artifactory_certificate.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "encoding/pem" "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "io/ioutil" "os" @@ -160,7 +161,7 @@ func calculateFingerPrint(pemData string) (string, error) { } func findCertificate(alias string, m interface{}) (*CertificateDetails, error) { - c := m.(*ArtClient).Resty + c := m.(*resty.Client) certificates := new([]CertificateDetails) _, err := c.R().SetResult(certificates).Get(endpoint) @@ -249,14 +250,12 @@ func getContentFromData(d *schema.ResourceData) (string, error) { } func resourceCertificateUpdate(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - content, err := getContentFromData(d) if err != nil { return err } - _, err = c.R().SetBody(content).SetHeader("content-type", "text/plain").Post(endpoint + d.Id()) + _, err = m.(*resty.Client).R().SetBody(content).SetHeader("content-type", "text/plain").Post(endpoint + d.Id()) if err != nil { return err @@ -266,8 +265,7 @@ func resourceCertificateUpdate(d *schema.ResourceData, m interface{}) error { } func resourceCertificateDelete(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - _, err := c.R().Delete(endpoint + d.Id()) + _, err := m.(*resty.Client).R().Delete(endpoint + d.Id()) if err != nil { return err } diff --git a/pkg/artifactory/resource_artifactory_certificate_test.go b/pkg/artifactory/resource_artifactory_certificate_test.go index a6d2d412..0c350aaa 100644 --- a/pkg/artifactory/resource_artifactory_certificate_test.go +++ b/pkg/artifactory/resource_artifactory_certificate_test.go @@ -52,7 +52,7 @@ func TestAccCertWithFile(t *testing.T){ const certWithFile = ` resource "artifactory_certificate" "%s" { alias = "%s" - file = "${path.cwd}/samples/cert.pem" // for this to work the CWD must be the repo root + file = "${path.cwd}/../../samples/cert.pem" } ` id := randomInt() diff --git a/pkg/artifactory/resource_artifactory_group.go b/pkg/artifactory/resource_artifactory_group.go index d903db5d..4a763232 100644 --- a/pkg/artifactory/resource_artifactory_group.go +++ b/pkg/artifactory/resource_artifactory_group.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -12,24 +13,25 @@ import ( const groupsEndpoint = "artifactory/api/security/groups/" -var autoJoinAdminValidate = func() func(i interface{}, k string) ([]string, []error) { - autoJoin, admin := false, false - return func(value interface{}, key string) ([]string, []error) { - switch key { - case "auto_join": - autoJoin = value.(bool) - case "admin_privileges": - admin = value.(bool) - } - if autoJoin && admin { - return nil, []error{fmt.Errorf("admin privs on auto_join groups is not allowed")} - } - return nil, nil - } -}() func resourceArtifactoryGroup() *schema.Resource { + var autoJoinAdminValidate = func() func(i interface{}, k string) ([]string, []error) { + autoJoin, admin := false, false + + return func(value interface{}, key string) ([]string, []error) { + switch key { + case "auto_join": + autoJoin = value.(bool) + case "admin_privileges": + admin = value.(bool) + } + if autoJoin && admin { + return nil, []error{fmt.Errorf("admin privs on auto_join groups is not allowed")} + } + return nil, nil + } + }() return &schema.Resource{ Create: resourceGroupCreate, Read: resourceGroupRead, @@ -112,13 +114,11 @@ func groupParams(s *schema.ResourceData) (services.GroupParams, error) { } func resourceGroupCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - groupParams, err := groupParams(d) if err != nil { return err } - _, err = client.R().SetBody(&(groupParams.GroupDetails)).Put(groupsEndpoint + groupParams.GroupDetails.Name) + _, err = m.(*resty.Client).R().SetBody(&(groupParams.GroupDetails)).Put(groupsEndpoint + groupParams.GroupDetails.Name) if err != nil { return err @@ -140,15 +140,13 @@ func resourceGroupCreate(d *schema.ResourceData, m interface{}) error { } func resourceGroupGet(d *schema.ResourceData, m interface{}) (*services.Group, error) { - client := m.(*ArtClient).Resty - params := services.GroupParams{} params.GroupDetails.Name = d.Id() params.IncludeUsers = true group := services.Group{} url := fmt.Sprintf("%s%s?includeUsers=%t", groupsEndpoint, params.GroupDetails.Name, params.IncludeUsers) - _, err := client.R().SetResult(&group).Get(url) + _, err := m.(*resty.Client).R().SetResult(&group).Get(url) return &group, err } @@ -186,7 +184,7 @@ func resourceGroupUpdate(d *schema.ResourceData, m interface{}) error { // Create and Update uses same endpoint, create checks for ReplaceIfExists and then uses put // Update instead uses POST which prevents removing users. This recreates the group with the same permissions and updated users - _, err = m.(*ArtClient).Resty.R().SetBody(&(groupParams.GroupDetails)).Put(groupsEndpoint + d.Id()) + _, err = m.(*resty.Client).R().SetBody(&(groupParams.GroupDetails)).Put(groupsEndpoint + d.Id()) if err != nil { return err } @@ -196,11 +194,15 @@ func resourceGroupUpdate(d *schema.ResourceData, m interface{}) error { } func resourceGroupDelete(d *schema.ResourceData, m interface{}) error { - _, err := m.(*ArtClient).Resty.R().Delete(groupsEndpoint + d.Id()) + _, err := m.(*resty.Client).R().Delete(groupsEndpoint + d.Id()) return err } func resourceGroupExists(d *schema.ResourceData, m interface{}) (bool, error) { - _, err := m.(*ArtClient).Resty.R().Head(groupsEndpoint + d.Id()) - return err == nil, err + return groupExists(m.(*resty.Client),d.Id()) } + +func groupExists(client *resty.Client, groupName string) (bool, error) { + _, err := client.R().Head(groupsEndpoint + groupName) + return err == nil, err +} \ No newline at end of file diff --git a/pkg/artifactory/resource_artifactory_group_test.go b/pkg/artifactory/resource_artifactory_group_test.go index e77b9fc5..b2c6243d 100644 --- a/pkg/artifactory/resource_artifactory_group_test.go +++ b/pkg/artifactory/resource_artifactory_group_test.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "net/http" "regexp" "testing" @@ -143,7 +144,8 @@ func TestAccGroup_full(t *testing.T) { func testAccCheckGroupDestroy(id string) func(*terraform.State) error { return func(s *terraform.State) error { - client := testAccProvider.Meta().(*ArtClient).Resty + client := testAccProvider.Meta().(*resty.Client) + rs, ok := s.RootModule().Resources[id] if !ok { return fmt.Errorf("err: Resource id[%s] not found", id) diff --git a/pkg/artifactory/resource_artifactory_local_repository.go b/pkg/artifactory/resource_artifactory_local_repository.go index 7704fef2..54f77251 100644 --- a/pkg/artifactory/resource_artifactory_local_repository.go +++ b/pkg/artifactory/resource_artifactory_local_repository.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/jfrog/jfrog-client-go/artifactory/services" "net/http" @@ -23,6 +24,7 @@ func resourceArtifactoryLocalRepository() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + ValidateFunc: repoKeyValidator, }, "package_type": { Type: schema.TypeString, @@ -184,11 +186,9 @@ func unmarshalLocalRepository(data *schema.ResourceData) MessyRepo { func resourceLocalRepositoryCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - repo := unmarshalLocalRepository(d) - _, err := client.R().SetBody(repo).Put(repositoriesEndpoint + repo.Key) + _, err := m.(*resty.Client).R().SetBody(repo).Put(repositoriesEndpoint + repo.Key) if err != nil { return err @@ -198,14 +198,13 @@ func resourceLocalRepositoryCreate(d *schema.ResourceData, m interface{}) error } func resourceLocalRepositoryRead(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty repo := MessyRepo{} if d.Id() == "" { return fmt.Errorf("no id given") } - resp, err := client.R().SetResult(&repo).Get(repositoriesEndpoint + d.Id()) + resp, err := m.(*resty.Client).R().SetResult(&repo).Get(repositoriesEndpoint + d.Id()) if err != nil { if resp != nil { if resp.StatusCode() == http.StatusNotFound{ @@ -254,11 +253,9 @@ func resourceLocalRepositoryRead(d *schema.ResourceData, m interface{}) error { } func resourceLocalRepositoryUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - repo := unmarshalLocalRepository(d) - _, err := client.R().SetBody(repo).SetHeader("accept", "text/plain"). + _, err := m.(*resty.Client).R().SetBody(repo).SetHeader("accept", "text/plain"). Post(repositoriesEndpoint + d.Id()) if err != nil { @@ -269,16 +266,12 @@ func resourceLocalRepositoryUpdate(d *schema.ResourceData, m interface{}) error } func resourceLocalRepositoryDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - - _, err := client.R().SetHeader("accept", "*/*").Delete(repositoriesEndpoint + d.Id()) + _, err := m.(*resty.Client).R().SetHeader("Accept", "*/*").Delete(repositoriesEndpoint + d.Id()) return err } func resourceLocalRepositoryExists(d *schema.ResourceData, m interface{}) (bool, error) { - client := m.(*ArtClient).Resty - - _, err := client.R().Head(repositoriesEndpoint + d.Id()) + _, err := m.(*resty.Client).R().Head(repositoriesEndpoint + d.Id()) // artifactory returns 400 instead of 404. but regardless, it's an error return err == nil, err } diff --git a/pkg/artifactory/resource_artifactory_permission_target.go b/pkg/artifactory/resource_artifactory_permission_target.go index 7907cff3..9b9ea2b7 100644 --- a/pkg/artifactory/resource_artifactory_permission_target.go +++ b/pkg/artifactory/resource_artifactory_permission_target.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/jfrog/jfrog-client-go/artifactory/services" @@ -288,11 +289,9 @@ func packPermissionTarget(permissionTarget *services.PermissionTargetParams, d * } func resourcePermissionTargetCreate(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - permissionTarget := unpackPermissionTarget(d) - if _, err := c.R().SetBody(permissionTarget).Post(permissionsEndPoint + permissionTarget.Name); err != nil { + if _, err := m.(*resty.Client).R().SetBody(permissionTarget).Post(permissionsEndPoint + permissionTarget.Name); err != nil { return err } @@ -313,9 +312,8 @@ func resourcePermissionTargetCreate(d *schema.ResourceData, m interface{}) error } func resourcePermissionTargetRead(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty permissionTarget := new(services.PermissionTargetParams) - resp, err := c.R().SetResult(permissionTarget).Get(permissionsEndPoint + d.Id()) + resp, err := m.(*resty.Client).R().SetResult(permissionTarget).Get(permissionsEndPoint + d.Id()) if err != nil { if resp != nil && resp.StatusCode() == http.StatusNotFound { d.SetId("") @@ -328,11 +326,9 @@ func resourcePermissionTargetRead(d *schema.ResourceData, m interface{}) error { } func resourcePermissionTargetUpdate(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - permissionTarget := unpackPermissionTarget(d) - if _, err := c.R().SetBody(permissionTarget).Put(permissionsEndPoint + d.Id()); err != nil { + if _, err := m.(*resty.Client).R().SetBody(permissionTarget).Put(permissionsEndPoint + d.Id()); err != nil { return err } @@ -341,7 +337,7 @@ func resourcePermissionTargetUpdate(d *schema.ResourceData, m interface{}) error } func resourcePermissionTargetDelete(d *schema.ResourceData, m interface{}) error { - _, err := m.(*ArtClient).Resty.R().Delete(permissionsEndPoint + d.Id()) + _, err := m.(*resty.Client).R().Delete(permissionsEndPoint + d.Id()) return err } @@ -351,7 +347,7 @@ func resourcePermissionTargetExists(d *schema.ResourceData, m interface{}) (bool } func permTargetExists(id string, m interface{}) (bool, error) { - _, err := m.(*ArtClient).Resty.R().Head(permissionsEndPoint + id) + _, err := m.(*resty.Client).R().Head(permissionsEndPoint + id) return err == nil, err } diff --git a/pkg/artifactory/resource_artifactory_remote_repository.go b/pkg/artifactory/resource_artifactory_remote_repository.go index 0c82cf0c..c8053d72 100644 --- a/pkg/artifactory/resource_artifactory_remote_repository.go +++ b/pkg/artifactory/resource_artifactory_remote_repository.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/jfrog/jfrog-client-go/artifactory/services" "net/http" @@ -34,9 +35,10 @@ func resourceArtifactoryRemoteRepository() *schema.Resource { Schema: map[string]*schema.Schema{ "key": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: repoKeyValidator, }, "package_type": { Type: schema.TypeString, @@ -448,14 +450,12 @@ func packRemoteRepo(repo MessyRemoteRepo, d *schema.ResourceData) error { } func resourceRemoteRepositoryCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - repo, err := unpackRemoteRepo(d) if err != nil { return err } - _, err = client.R().SetBody(repo).Put(repositoriesEndpoint+ repo.Key) + _, err = m.(*resty.Client).R().SetBody(repo).Put(repositoriesEndpoint + repo.Key) if err != nil { return err } @@ -465,9 +465,8 @@ func resourceRemoteRepositoryCreate(d *schema.ResourceData, m interface{}) error } func resourceRemoteRepositoryRead(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty repo := MessyRemoteRepo{} - resp, err := client.R().SetResult(&repo).Get(repositoriesEndpoint+ d.Id()) + resp, err := m.(*resty.Client).R().SetResult(&repo).Get(repositoriesEndpoint + d.Id()) if err != nil { if resp != nil && resp.StatusCode() == http.StatusNotFound { d.SetId("") @@ -483,13 +482,11 @@ func resourceRemoteRepositoryRead(d *schema.ResourceData, m interface{}) error { } func resourceRemoteRepositoryUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - repo, err := unpackRemoteRepo(d) if err != nil { return err } - _, err = client.R().SetBody(repo).Post(repositoriesEndpoint+ repo.Key) + _, err = m.(*resty.Client).R().SetBody(repo).Post(repositoriesEndpoint + repo.Key) if err != nil { return err } @@ -499,9 +496,7 @@ func resourceRemoteRepositoryUpdate(d *schema.ResourceData, m interface{}) error } func resourceRemoteRepositoryDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - - resp, err := client.R().Delete(repositoriesEndpoint+ d.Id()) + resp, err := m.(*resty.Client).R().Delete(repositoriesEndpoint + d.Id()) if err != nil { if resp != nil && resp.StatusCode() == http.StatusNotFound { @@ -515,9 +510,7 @@ func resourceRemoteRepositoryDelete(d *schema.ResourceData, m interface{}) error } func resourceRemoteRepositoryExists(d *schema.ResourceData, m interface{}) (bool, error) { - client := m.(*ArtClient).Resty - - _, err := client.R().Head(repositoriesEndpoint+ d.Id()) + _, err := m.(*resty.Client).R().Head(repositoriesEndpoint + d.Id()) // as long as we don't have an error, it's good return err == nil, err diff --git a/pkg/artifactory/resource_artifactory_replication_config.go b/pkg/artifactory/resource_artifactory_replication_config.go index e9d51545..c8f99891 100644 --- a/pkg/artifactory/resource_artifactory_replication_config.go +++ b/pkg/artifactory/resource_artifactory_replication_config.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/jfrog/jfrog-client-go/artifactory/services/utils" @@ -210,11 +211,9 @@ func packReplicationConfig(replicationConfig *ReplicationConfig, d *schema.Resou } func resourceReplicationConfigCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - replicationConfig := unpackReplicationConfig(d) - _, err := client.R().SetBody(replicationConfig).Put("artifactory/api/replications/multiple/" + replicationConfig.RepoKey) + _, err := m.(*resty.Client).R().SetBody(replicationConfig).Put("artifactory/api/replications/multiple/" + replicationConfig.RepoKey) if err != nil { return err } @@ -224,7 +223,7 @@ func resourceReplicationConfigCreate(d *schema.ResourceData, m interface{}) erro } func resourceReplicationConfigRead(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty + c := m.(*resty.Client) var replications []utils.ReplicationBody _, err := c.R().SetResult(&replications).Get("artifactory/api/replications/" + d.Id()) @@ -244,11 +243,9 @@ func resourceReplicationConfigRead(d *schema.ResourceData, m interface{}) error } func resourceReplicationConfigUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - replicationConfig := unpackReplicationConfig(d) - _, err := client.R().SetBody(replicationConfig).Post("/api/replications/" + d.Id()) + _, err := m.(*resty.Client).R().SetBody(replicationConfig).Post("/api/replications/" + d.Id()) if err != nil { return err } @@ -259,11 +256,11 @@ func resourceReplicationConfigUpdate(d *schema.ResourceData, m interface{}) erro } func resourceReplicationConfigDelete(d *schema.ResourceData, m interface{}) error { - _, err := m.(*ArtClient).Resty.R().Delete("artifactory/api/replications/" + d.Id()) + _, err := m.(*resty.Client).R().Delete("artifactory/api/replications/" + d.Id()) return err } func repConfigExists(id string, m interface{}) (bool, error) { - _, err := m.(*ArtClient).Resty.R().Head("artifactory/api/replications/" + id) + _, err := m.(*resty.Client).R().Head("artifactory/api/replications/" + id) return err == nil, err } diff --git a/pkg/artifactory/resource_artifactory_single_replication_config.go b/pkg/artifactory/resource_artifactory_single_replication_config.go index 2ca59686..3d2c874f 100644 --- a/pkg/artifactory/resource_artifactory_single_replication_config.go +++ b/pkg/artifactory/resource_artifactory_single_replication_config.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/jfrog/jfrog-client-go/artifactory/services/utils" ) @@ -54,7 +55,10 @@ func packSingleReplicationConfig(config *utils.ReplicationBody, d *schema.Resour setValue("url", config.URL) setValue("socket_timeout_millis", config.SocketTimeoutMillis) setValue("username", config.Username) - setValue("password", getMD5Hash(config.Password)) + // the password coming back from artifactory is already scrambled, and I don't know in what form. + // password -> JE2fNsEThvb1buiH7h7S2RDsGWSdp2EcuG9Pky5AFyRMwE4UzG + // Because it comes back scrambled, we can't/shouldn't touch it. + setValue("password", config.Password) setValue("enabled", config.Enabled) setValue("sync_deletes", config.SyncDeletes) setValue("sync_properties", config.SyncProperties) @@ -70,11 +74,9 @@ func packSingleReplicationConfig(config *utils.ReplicationBody, d *schema.Resour } func resourceSingleReplicationConfigCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - replicationConfig := unpackSingleReplicationConfig(d) - - _,err := client.R().SetBody(replicationConfig).Put(replicationEndpoint + replicationConfig.RepoKey) + // The password is sent clear + _,err := m.(*resty.Client).R().SetBody(replicationConfig).Put(replicationEndpoint + replicationConfig.RepoKey) if err != nil { return err } @@ -84,10 +86,9 @@ func resourceSingleReplicationConfigCreate(d *schema.ResourceData, m interface{} } func resourceSingleReplicationConfigRead(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty replications := new([]utils.ReplicationBody) - _, err := client.R().SetResult(replications).Get(replicationEndpoint + d.Id()) - + _, err := m.(*resty.Client).R().SetResult(replications).Get(replicationEndpoint + d.Id()) + // password comes back scrambled if err != nil { return err } @@ -98,10 +99,8 @@ func resourceSingleReplicationConfigRead(d *schema.ResourceData, m interface{}) } func resourceSingleReplicationConfigUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - replicationConfig := unpackSingleReplicationConfig(d) - _, err := client.R().SetBody(replicationConfig).Post(replicationEndpoint + replicationConfig.RepoKey) + _, err := m.(*resty.Client).R().SetBody(replicationConfig).Post(replicationEndpoint + replicationConfig.RepoKey) if err != nil { return err } diff --git a/pkg/artifactory/resource_artifactory_single_replication_config_test.go b/pkg/artifactory/resource_artifactory_single_replication_config_test.go index be83413f..b217fce1 100644 --- a/pkg/artifactory/resource_artifactory_single_replication_config_test.go +++ b/pkg/artifactory/resource_artifactory_single_replication_config_test.go @@ -88,7 +88,12 @@ func TestAccSingleReplication_full(t *testing.T) { resource.TestCheckResourceAttr(fqrn, "enable_event_replication", "true"), resource.TestCheckResourceAttr(fqrn, "url", os.Getenv("ARTIFACTORY_URL")), resource.TestCheckResourceAttr(fqrn, "username", os.Getenv("ARTIFACTORY_USERNAME")), - resource.TestCheckResourceAttr(fqrn, "password", getMD5Hash(os.Getenv("ARTIFACTORY_PASSWORD"))), + // artifactory is sending us back a scrambled password and because we can't compute it, we can't + // store it's state. I am going to leave this test broken specifically to draw attention to this + // because local state will never match remote state and TF will have issues + // we send: password + // we get back: JE2fNsEThvb1buiH7h7S2RDsGWSdp2EcuG9Pky5AFyRMwE4UzG + resource.TestCheckResourceAttr(fqrn, "password", os.Getenv("ARTIFACTORY_PASSWORD")), ), }, }, diff --git a/pkg/artifactory/resource_artifactory_user.go b/pkg/artifactory/resource_artifactory_user.go index e1cf6ddc..45bd55a8 100644 --- a/pkg/artifactory/resource_artifactory_user.go +++ b/pkg/artifactory/resource_artifactory_user.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/base64" "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" @@ -13,14 +14,13 @@ import ( "strconv" ) - func resourceArtifactoryUser() *schema.Resource { return &schema.Resource{ Create: resourceUserCreate, Read: resourceUserRead, Update: resourceUserUpdate, Delete: resourceUserDelete, - Exists: userExists, + Exists: resourceUserExists, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -69,12 +69,12 @@ func resourceArtifactoryUser() *schema.Resource { Sensitive: true, Required: true, ValidateFunc: func(tfValue interface{}, key string) ([]string, []error) { - validationOn, _ := strconv.ParseBool( os.Getenv("JFROG_PASSWD_VALIDATION_ON")) - if validationOn { + validationOn, _ := strconv.ParseBool(os.Getenv("JFROG_PASSWD_VALIDATION_ON")) + if validationOn { ses, err := defaultPassValidation(tfValue, key) if err != nil { - return append(ses,"if your organization has custom password rules, you may override " + - "password validation by setting env var JFROG_PASSWD_VALIDATION_ON=false"),append(err) + return append(ses, "if your organization has custom password rules, you may override "+ + "password validation by setting env var JFROG_PASSWD_VALIDATION_ON=false"), append(err) } } return nil, nil @@ -93,18 +93,19 @@ func resourceArtifactoryUser() *schema.Resource { } } -func userExists(data *schema.ResourceData, config interface{}) (bool, error) { - client := config.(*ArtClient).Resty +func resourceUserExists(data *schema.ResourceData, m interface{}) (bool, error) { + d := &ResourceData{data} userName := d.getString("name", false) if userName == "" { return false, fmt.Errorf("no usersname supplied") } + return userExists(m.(*resty.Client), userName) +} + +func userExists(client *resty.Client, userName string) (bool, error) { _, err := client.R().Head("artifactory/api/security/users/" + userName) - if err != nil { - return false, err - } - return true, nil + return err == nil, err } func unpackUser(s *schema.ResourceData) services.User { @@ -144,8 +145,6 @@ func packUser(user services.User, d *schema.ResourceData) error { } func resourceUserCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - user := unpackUser(d) if user.Name == "" { @@ -155,7 +154,7 @@ func resourceUserCreate(d *schema.ResourceData, m interface{}) error { if user.Password == "" { return fmt.Errorf("no password supplied. Please use any of the terraform random password generators") } - _, err := client.R().SetBody(user).Put("artifactory/api/security/users/" + user.Name) + _, err := m.(*resty.Client).R().SetBody(user).Put("artifactory/api/security/users/" + user.Name) if err != nil { return err } @@ -163,7 +162,7 @@ func resourceUserCreate(d *schema.ResourceData, m interface{}) error { d.SetId(user.Name) return resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { result := &services.User{} - resp, e := client.R().SetResult(result).Get("artifactory/api/security/users/" + user.Name) + resp, e := m.(*resty.Client).R().SetResult(result).Get("artifactory/api/security/users/" + user.Name) if e != nil { if resp != nil && resp.StatusCode() == http.StatusNotFound { @@ -176,12 +175,11 @@ func resourceUserCreate(d *schema.ResourceData, m interface{}) error { } func resourceUserRead(rd *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty d := &ResourceData{rd} userName := d.getString("name", false) user := &services.User{} - resp, err := client.R().SetResult(user).Get("artifactory/api/security/users/"+ userName) + resp, err := m.(*resty.Client).R().SetResult(user).Get("artifactory/api/security/users/" + userName) if err != nil { if resp != nil && resp.StatusCode() == http.StatusNotFound { @@ -194,10 +192,8 @@ func resourceUserRead(rd *schema.ResourceData, m interface{}) error { } func resourceUserUpdate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - user := unpackUser(d) - _, err := client.R().SetBody(user).Post("artifactory/api/security/users/" + user.Name) + _, err := m.(*resty.Client).R().SetBody(user).Post("artifactory/api/security/users/" + user.Name) if err != nil { return err @@ -208,11 +204,10 @@ func resourceUserUpdate(d *schema.ResourceData, m interface{}) error { } func resourceUserDelete(rd *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty d := &ResourceData{rd} userName := d.getString("name", false) - _, err := client.R().Delete("artifactory/api/security/users/" + userName) + _, err := m.(*resty.Client).R().Delete("artifactory/api/security/users/" + userName) if err != nil { return fmt.Errorf("user %s not deleted. %s", userName, err) } diff --git a/pkg/artifactory/resource_artifactory_user_test.go b/pkg/artifactory/resource_artifactory_user_test.go index ec177cc0..5364c5f5 100644 --- a/pkg/artifactory/resource_artifactory_user_test.go +++ b/pkg/artifactory/resource_artifactory_user_test.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "net/http" "testing" @@ -73,7 +74,7 @@ func TestAccUser_full(t *testing.T) { func testAccCheckUserDestroy(id string) func(*terraform.State) error { return func(s *terraform.State) error { - client := testAccProvider.Meta().(*ArtClient).Resty + client := testAccProvider.Meta().(*resty.Client) rs, ok := s.RootModule().Resources[id] diff --git a/pkg/artifactory/resource_artifactory_virtual_repository.go b/pkg/artifactory/resource_artifactory_virtual_repository.go index fe97dc4d..163c82d9 100644 --- a/pkg/artifactory/resource_artifactory_virtual_repository.go +++ b/pkg/artifactory/resource_artifactory_virtual_repository.go @@ -2,6 +2,7 @@ package artifactory import ( "fmt" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/jfrog/jfrog-client-go/artifactory/services" "net/http" @@ -148,10 +149,9 @@ func packVirtualRepository(repo MessyVirtualRepo, d *schema.ResourceData) error } func resourceVirtualRepositoryCreate(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty repo := unpackVirtualRepository(d) - _, err := client.R().SetBody(repo).Put(repositoriesEndpoint + repo.Key) + _, err := m.(*resty.Client).R().SetBody(repo).Put(repositoriesEndpoint + repo.Key) if err != nil { return err @@ -161,9 +161,8 @@ func resourceVirtualRepositoryCreate(d *schema.ResourceData, m interface{}) erro } func resourceVirtualRepositoryRead(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty repo := MessyVirtualRepo{} - resp, err := c.R().SetResult(&repo).Get(repositoriesEndpoint+ d.Id()) + resp, err := m.(*resty.Client).R().SetResult(&repo).Get(repositoriesEndpoint+ d.Id()) if err != nil { if resp != nil && (resp.StatusCode() == http.StatusNotFound) { @@ -176,11 +175,9 @@ func resourceVirtualRepositoryRead(d *schema.ResourceData, m interface{}) error } func resourceVirtualRepositoryUpdate(d *schema.ResourceData, m interface{}) error { - c := m.(*ArtClient).Resty - repo := unpackVirtualRepository(d) - _, err := c.R().SetBody(repo).Post(repositoriesEndpoint+ d.Id()) + _, err := m.(*resty.Client).R().SetBody(repo).Post(repositoriesEndpoint+ d.Id()) if err != nil { return err } @@ -190,9 +187,7 @@ func resourceVirtualRepositoryUpdate(d *schema.ResourceData, m interface{}) erro } func resourceVirtualRepositoryDelete(d *schema.ResourceData, m interface{}) error { - client := m.(*ArtClient).Resty - - resp, err := client.R().Delete(repositoriesEndpoint+ d.Id()) + resp, err := m.(*resty.Client).R().Delete(repositoriesEndpoint+ d.Id()) if err != nil && (resp != nil && resp.StatusCode() == http.StatusNotFound) { d.SetId("") @@ -202,7 +197,7 @@ func resourceVirtualRepositoryDelete(d *schema.ResourceData, m interface{}) erro } func resourceVirtualRepositoryExists(d *schema.ResourceData, m interface{}) (bool, error) { - _, err := m.(*ArtClient).Resty.R().Head(repositoriesEndpoint+ d.Id()) + _, err := m.(*resty.Client).R().Head(repositoriesEndpoint+ d.Id()) return err == nil, err } diff --git a/pkg/artifactory/resource_artifactory_virtual_repository_test.go b/pkg/artifactory/resource_artifactory_virtual_repository_test.go index e9778d29..0e270917 100644 --- a/pkg/artifactory/resource_artifactory_virtual_repository_test.go +++ b/pkg/artifactory/resource_artifactory_virtual_repository_test.go @@ -108,7 +108,7 @@ func mkVirtualTestCase(repo string, t *testing.T) (resource.TestT, resource.Test repositories = [] description = "A test virtual repo" notes = "Internal description" - includes_pattern = "com/atlassian/**,cloud/atlassian/**" + includes_pattern = "com/jfrog/**,cloud/jfrog/**" excludes_pattern = "com/google/**" artifactory_requests_can_retrieve_remote_artifacts = true pom_repository_references_cleanup_policy = "discard_active_reference" @@ -129,7 +129,7 @@ func mkVirtualTestCase(repo string, t *testing.T) (resource.TestT, resource.Test resource.TestCheckResourceAttr(fqrn, "repositories.#", "0"), resource.TestCheckResourceAttr(fqrn, "description", "A test virtual repo"), resource.TestCheckResourceAttr(fqrn, "notes", "Internal description"), - resource.TestCheckResourceAttr(fqrn, "includes_pattern", "com/atlassian/**,cloud/atlassian/**"), + resource.TestCheckResourceAttr(fqrn, "includes_pattern", "com/jfrog/**,cloud/jfrog/**"), resource.TestCheckResourceAttr(fqrn, "excludes_pattern", "com/google/**"), resource.TestCheckResourceAttr(fqrn, "pom_repository_references_cleanup_policy", "discard_active_reference"), ), @@ -150,7 +150,7 @@ func TestNugetPackageCreationFull(t *testing.T) { repositories = [] description = "A test virtual repo" notes = "Internal description" - includes_pattern = "com/atlassian/**,cloud/atlassian/**" + includes_pattern = "com/jfrog/**,cloud/jfrog/**" excludes_pattern = "com/google/**" artifactory_requests_can_retrieve_remote_artifacts = true pom_repository_references_cleanup_policy = "discard_active_reference" @@ -188,7 +188,7 @@ func TestAccVirtualRepository_full(t *testing.T) { repositories = [] description = "A test virtual repo" notes = "Internal description" - includes_pattern = "com/atlassian/**,cloud/atlassian/**" + includes_pattern = "com/jfrog/**,cloud/jfrog/**" excludes_pattern = "com/google/**" artifactory_requests_can_retrieve_remote_artifacts = true pom_repository_references_cleanup_policy = "discard_active_reference" @@ -209,7 +209,7 @@ func TestAccVirtualRepository_full(t *testing.T) { resource.TestCheckResourceAttr(fqrn, "repositories.#", "0"), resource.TestCheckResourceAttr(fqrn, "description", "A test virtual repo"), resource.TestCheckResourceAttr(fqrn, "notes", "Internal description"), - resource.TestCheckResourceAttr(fqrn, "includes_pattern", "com/atlassian/**,cloud/atlassian/**"), + resource.TestCheckResourceAttr(fqrn, "includes_pattern", "com/jfrog/**,cloud/jfrog/**"), resource.TestCheckResourceAttr(fqrn, "excludes_pattern", "com/google/**"), resource.TestCheckResourceAttr(fqrn, "pom_repository_references_cleanup_policy", "discard_active_reference"), ), diff --git a/pkg/artifactory/util.go b/pkg/artifactory/util.go index 7d9bc210..d72c750f 100644 --- a/pkg/artifactory/util.go +++ b/pkg/artifactory/util.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/atlassian/go-artifactory/v2/artifactory" + "github.com/go-resty/resty/v2" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "math/rand" "text/template" @@ -16,7 +16,8 @@ type ResourceData struct{ *schema.ResourceData } func (d *ResourceData) getStringRef(key string, onlyIfChanged bool) *string { if v, ok := d.GetOk(key); ok && (!onlyIfChanged || d.HasChange(key)) { - return artifactory.String(v.(string)) + thing := v.(string) + return &thing } return nil } @@ -29,7 +30,8 @@ func (d *ResourceData) getString(key string, onlyIfChanged bool) string { func (d *ResourceData) getBoolRef(key string, onlyIfChanged bool) *bool { if v, ok := d.GetOkExists(key); ok && (!onlyIfChanged || d.HasChange(key)) { - return artifactory.Bool(v.(bool)) + thing := v.(bool) + return &thing } return nil } @@ -43,7 +45,8 @@ func (d *ResourceData) getBool(key string, onlyIfChanged bool) bool { func (d *ResourceData) getIntRef(key string, onlyIfChanged bool) *int { if v, ok := d.GetOkExists(key); ok && (!onlyIfChanged || d.HasChange(key)) { - return artifactory.Int(v.(int)) + thing := v.(int) + return &thing } return nil } @@ -130,9 +133,7 @@ func mergeSchema(schemata ...map[string]*schema.Schema) map[string]*schema.Schem } func repoExists(id string, m interface{}) (bool, error) { - client := m.(*ArtClient).Resty - - _, err := client.R().Head(repositoriesEndpoint+ id) + _, err := m.(*resty.Client).R().Head(repositoriesEndpoint+ id) return err == nil, err }