diff --git a/bitbucket/provider.go b/bitbucket/provider.go index 87ac800..825859e 100644 --- a/bitbucket/provider.go +++ b/bitbucket/provider.go @@ -18,24 +18,31 @@ func Provider() *schema.Provider { return &schema.Provider{ Schema: map[string]*schema.Schema{ "server": { - Required: true, + Optional: true, Type: schema.TypeString, DefaultFunc: schema.EnvDefaultFunc("BITBUCKET_SERVER", nil), Description: "The url of your bitbucket instance. For the docker compose instance this is http://localhost:7990", }, "username": { - Required: true, + Optional: true, Type: schema.TypeString, DefaultFunc: schema.EnvDefaultFunc("BITBUCKET_USERNAME", nil), Description: "The username for authentication. If you're using a personal access token use your normal username.", }, "password": { Type: schema.TypeString, - Required: true, + Optional: true, Sensitive: true, DefaultFunc: schema.EnvDefaultFunc("BITBUCKET_PASSWORD", nil), Description: "the password for authentication. Personal access tokens are allowed, but http access token aren't yet", }, + "token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + DefaultFunc: schema.EnvDefaultFunc("BITBUCKET_TOKEN", nil), + Description: "Token as alternative to the Password. Only use for repository access tokens. Personal access tokens can use the normal basic authentication", + }, }, ConfigureContextFunc: providerConfigure, DataSourcesMap: map[string]*schema.Resource{ @@ -91,6 +98,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} username := d.Get("username").(string) password := d.Get("password").(string) + token := d.Get("token").(string) configErrors := diag.Diagnostics{} @@ -102,7 +110,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} Detail: "server is required and must be provided in the provider config or the BITBUCKET_SERVER environment variable", }) } - if username == "" { + if username == "" && token == "" { configErrors = append(configErrors, diag.Diagnostic{ @@ -111,7 +119,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} Detail: "username is required and must be provided in the provider config or the BITBUCKET_USERNAME environment variable", }) } - if password == "" { + if password == "" && token == "" { configErrors = append(configErrors, diag.Diagnostic{ Severity: diag.Error, @@ -128,6 +136,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{} Server: serverSanitized, Username: username, Password: password, + Token: token, HTTPClient: &http.Client{}, } diff --git a/bitbucket/provider_framework.go b/bitbucket/provider_framework.go index 72b0aa0..1c5d10d 100644 --- a/bitbucket/provider_framework.go +++ b/bitbucket/provider_framework.go @@ -34,6 +34,7 @@ type BitbucketServerProviderModel struct { Server types.String `tfsdk:"server"` Username types.String `tfsdk:"username"` Password types.String `tfsdk:"password"` + Token types.String `tfsdk:"token"` } func (p *BitbucketServerProviderFramework) Resources(_ context.Context) []func() resource.Resource { @@ -71,6 +72,11 @@ func (p *BitbucketServerProviderFramework) Schema(_ context.Context, _ provider. Description: "the password for authentication. Personal access tokens are allowed, but http access token aren't yet", Sensitive: true, }, + "token": schema.StringAttribute{ + Optional: true, + Description: "Token as alternative to the Password. Only use for repository access tokens. Personal access tokens can use the normal basic authentication", + Sensitive: true, + }, }, } } @@ -101,11 +107,16 @@ func (p *BitbucketServerProviderFramework) Configure(ctx context.Context, req pr ) } + token := os.Getenv("BITBUCKET_TOKEN") + if data.Token.ValueString() != "" { + token = data.Token.ValueString() + } + username := os.Getenv("BITBUCKET_USERNAME") if data.Username.ValueString() != "" { username = data.Username.ValueString() } - if username == "" { + if username == "" && token == "" { resp.Diagnostics.AddError( "username is required", "username is required and must be provided in the provider config or the BITBUCKET_USERNAME environment variable", @@ -116,7 +127,7 @@ func (p *BitbucketServerProviderFramework) Configure(ctx context.Context, req pr if data.Password.ValueString() != "" { password = data.Password.ValueString() } - if password == "" { + if password == "" && token == "" { resp.Diagnostics.AddError( "password is required", "password is required and must be provided in the provider config or the BITBUCKET_PASSWORD environment variable", @@ -127,6 +138,7 @@ func (p *BitbucketServerProviderFramework) Configure(ctx context.Context, req pr Server: server, Username: username, Password: password, + Token: token, HTTPClient: &http.Client{}, } diff --git a/bitbucket/util/client/client.go b/bitbucket/util/client/client.go index 3d649dd..2dc5a81 100644 --- a/bitbucket/util/client/client.go +++ b/bitbucket/util/client/client.go @@ -40,6 +40,7 @@ type BitbucketClient struct { Server string Username string Password string + Token string HTTPClient *http.Client } @@ -60,7 +61,11 @@ func (c *BitbucketClient) Do(method, endpoint string, payload *bytes.Buffer, con return nil, err } - req.SetBasicAuth(c.Username, c.Password) + if c.Password != "" { + req.SetBasicAuth(c.Username, c.Password) + } else { + req.Header.Add("Authorization", "Bearer "+c.Token) + } req.Header.Add("X-Atlassian-Token", "no-check") if payload != nil { diff --git a/docs/index.md b/docs/index.md index 966109a..d6dd548 100755 --- a/docs/index.md +++ b/docs/index.md @@ -6,14 +6,12 @@ unlocks the power of terraform to manage your self-hosted Bitbucket Server insta ## Installation -### Terraform 0.13+ +### Terraform 1.0+ The provider can be installed and managed automatically by Terraform. Sample `versions.tf` file : ```hcl terraform { - required_version = ">= 0.13" - required_providers { bitbucketserver = { source = "xvlcwk-terraform/bitbucketserver" @@ -22,26 +20,6 @@ terraform { } ``` -### Terraform 0.12 - -#### Install latest version - -The following one-liner script will fetch the latest provider version and download it to your `~/.terraform.d/plugins` directory. - -```bash -$ mkdir -p ~/.terraform.d/plugins && \ - curl -Ls https://api.github.com/repos/xvlcwk-terraform/terraform-provider-bitbucketserver/releases/latest \ - | jq -r ".assets[] | select(.browser_download_url | contains(\"$(uname -s | tr A-Z a-z)\")) | select(.browser_download_url | contains(\"amd64\")) | .browser_download_url" \ - | xargs -n 1 curl -Lo ~/.terraform.d/plugins/terraform-provider-bitbucketserver.zip && \ - pushd ~/.terraform.d/plugins/ && \ - unzip ~/.terraform.d/plugins/terraform-provider-bitbucketserver.zip -d terraform-provider-bitbucketserver-tmp && \ - mv terraform-provider-bitbucketserver-tmp/terraform-provider-bitbucketserver* . && \ - chmod +x terraform-provider-bitbucketserver* && \ - rm -rf terraform-provider-bitbucketserver-tmp && \ - rm -rf terraform-provider-bitbucketserver.zip && \ - popd -``` - #### Install manually If you don't want to use the one-liner above, you can download a binary for your system from the [release page](https://github.com/xvlcwk-terraform/terraform-provider-bitbucketserver/releases), @@ -60,10 +38,20 @@ provider "bitbucketserver" { } ``` +Alternatively you can specify a http-access-token, but please be aware that those aren't able to create other access tokens and are overall limited in their scope. + + +```hcl +provider "bitbucketserver" { + server = "https://mybitbucket.example.com" + token = "BBDC-ODc4NTMyODU1MTI3OnSOs8sHd7EZneuWx2ZiYyF/Xmuj" +} +``` + ### Authentication The `username` and `password` specified should be of a user with sufficient privileges to perform the operations you are after. -Typically this is a user with `SYS_ADMIN` global permissions. +Typically, this is a user with `SYS_ADMIN` global permissions. ### Environment Variables @@ -72,6 +60,7 @@ You can also specify the provider configuration using the following env vars: * `BITBUCKET_SERVER` * `BITBUCKER_USERNAME` * `BITBUCKET_PASSWORD` +* `BITBUCKET_TOKEN` > Note: The hcl provider configuration takes precedence over the environment variables.