diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6c141c6..48ab08d 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,22 +8,23 @@ USER root COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/swagger /usr/local/bin/swagger COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/terraform /usr/local/bin/terraform COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/terraform-doc /usr/local/bin/terraform-doc +COPY --from=docker.pkg.github.com/nolte/vscode-devcontainers/devops:latest /usr/local/bin/shellcheck /usr/local/bin/shellcheck RUN curl -sSL -k https://github.com/bats-core/bats-core/archive/v${BATS_VERSION}.tar.gz -o /tmp/bats.tgz \ - && tar -zxf /tmp/bats.tgz -C /tmp \ - && /bin/bash /tmp/bats-core-${BATS_VERSION}/install.sh /usr/local + && tar -zxf /tmp/bats.tgz -C /tmp \ + && /bin/bash /tmp/bats-core-${BATS_VERSION}/install.sh /usr/local RUN curl -sSL -k https://github.com/bflad/tfproviderdocs/releases/download/v0.6.0/tfproviderdocs_0.6.0_linux_amd64.tar.gz -o /tmp/tfproviderdocs.tgz \ - && tar -zxf /tmp/tfproviderdocs.tgz -C /tmp \ - && mv /tmp/tfproviderdocs /usr/local/bin/ + && tar -zxf /tmp/tfproviderdocs.tgz -C /tmp \ + && mv /tmp/tfproviderdocs /usr/local/bin/ RUN apk add --update-cache \ - nodejs npm \ - && rm -rf /var/cache/apk/* + nodejs npm \ + && rm -rf /var/cache/apk/* RUN mkdir -p /go/src && chown -R ${USER_UID}:${USER_GID} /go/src \ - && mkdir -p /go/pkg && chown -R ${USER_UID}:${USER_GID} /go/pkg + && mkdir -p /go/pkg && chown -R ${USER_UID}:${USER_GID} /go/pkg USER ${USERNAME} @@ -40,4 +41,4 @@ RUN npm config set prefix "/home/${USERNAME}/.npm-packages" RUN npm install swagger-merger --user -g RUN helm repo add harbor https://helm.goharbor.io -RUN npm install swagger-merger -g \ No newline at end of file +RUN npm install swagger-merger -g diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0a41dc4..f18ccc6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -50,6 +50,7 @@ "ms-kubernetes-tools.vscode-kubernetes-tools", "jetmartin.bats", "EditorConfig.EditorConfig", + "lonefy.vscode-js-css-html-formatter", ], "settings": { // General settings @@ -67,4 +68,4 @@ "editor.detectIndentation": false } } -} \ No newline at end of file +} diff --git a/.editorconfig b/.editorconfig index 2a1b767..9a418a5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,13 +2,20 @@ root = true [*] -indent_style = tab +indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +[docs/**.md] +# allow line break https://3os.org/markdownCheatSheet/lineBreaks/#line_break_with_2_spaces +trim_trailing_whitespace = false + +[makefile] +indent_style = tabs + [{*.yml,*.yaml, *.tf}] indent_style = space indent_size = 2 diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..c818a84 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,2 @@ +linters: + enable-all: true \ No newline at end of file diff --git a/Makefile b/Makefile index 1226ee0..76b75fe 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,10 @@ fmtcheck: vet: go vet ./... +check-scripts: + shellcheck scripts/*.sh + shellcheck scripts/test/bats/build/*.bats + e2e_prepare: scripts/tst-00-prepare-kind.sh scripts/tst-01-prepare-harbor.sh diff --git a/README.md b/README.md index 4e3914c..25a6e76 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This is original based on the Work from [BESTSELLER/terraform-harbor-provider](h **Planed Branking Changes:** -- [ ] Rename provier attributes, like url etc. +- [x] [Rename provider](https://github.com/nolte/terraform-provider-harbor/issues/3) attributes, like url etc. - [x] Planed Git Rebase for remove the Ugly CI/CD Test Commit - [x] Finazilize the frist version of common ci workflow - [x] Finazilize the frist version of release workflow diff --git a/client/client.go b/client/client.go index 1d6366f..6eeb530 100644 --- a/client/client.go +++ b/client/client.go @@ -10,35 +10,20 @@ import ( apiclient "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" ) -type Client struct { - url string - username string - password string - insecure bool - Client *apiclient.Harbor -} - // NewClient creates common settings -func NewClient(url string, username string, password string, insecure bool, basepath string) *Client { +func NewClient(host string, username string, password string, insecure bool, basepath string, schema string) *apiclient.Harbor { basicAuth := httptransport.BasicAuth(username, password) // create the transport - //proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true} - if insecure { http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} } - transport := httptransport.New(url, basepath, apiclient.DefaultSchemes) + apiSchemes := []string{schema} + transport := httptransport.New(host, basepath, apiSchemes) // add default auth transport.DefaultAuthentication = basicAuth // create the API client, with the transport client := apiclient.New(transport, strfmt.Default) - return &Client{ - url: url, - username: username, - password: password, - insecure: insecure, - Client: client, - } + return client } diff --git a/docs/css/table.css b/docs/css/table.css new file mode 100644 index 0000000..37ca127 --- /dev/null +++ b/docs/css/table.css @@ -0,0 +1,6 @@ +.wy-nav-content { + background: white; + max-width: 100%; + height: 100vh; + margin: 0; +} diff --git a/docs/data_sources/harbor_label.md b/docs/data_sources/harbor_label.md new file mode 100644 index 0000000..06e9f70 --- /dev/null +++ b/docs/data_sources/harbor_label.md @@ -0,0 +1,30 @@ +# Data Source: harbor_label + +## Example Usage + +```hcl +data "harbor_label" "label_1" { + name = "main" + scope = "g" +} + +data "harbor_label" "label_2" { + id = 4 +} + +``` + +## Argument Reference + +- `id` - (Optional, int) ID of the label. +- `name` - (Optional, string) Name of the label. +- `scope` - (Optional, string) Scope of the label. + +## Attributes Reference + +- `id` - (int) Unique ID of the label. +- `name` - (string) Name of the label. +- `description` - (Optional) The description of the label account will be displayed in harbor. +- `color` - (Optional) The color the label. +- `scope` - (Optional) The scope the label, `p` for project and `g` for global. +- `project_id` - (Optional) The ID of project that the label belongs to. diff --git a/docs/data_sources/harbor_project.md b/docs/data_sources/harbor_project.md index 6907226..0b0a36a 100644 --- a/docs/data_sources/harbor_project.md +++ b/docs/data_sources/harbor_project.md @@ -1,51 +1,24 @@ ---- -subcategory: "project" -page_title: "Harbor: harbor_project" -description: |- - Get information on a Harbor Project ---- - # Data Source: harbor_project -Use this data source to get the ARN of a certificate in AWS Certificate -Manager (ACM), you can reference -it by domain without having to hard code the ARNs as input. - ## Example Usage ```hcl -# Find a certificate that is issued -data "aws_acm_certificate" "example" { - domain = "tf.example.com" - statuses = ["ISSUED"] +data "harbor_project" "project_1" { + name = "main" } -# Find a certificate issued by (not imported into) ACM -data "aws_acm_certificate" "example" { - domain = "tf.example.com" - types = ["AMAZON_ISSUED"] - most_recent = true +data "harbor_project" "project_2" { + id = 4 } -# Find a RSA 4096 bit certificate -data "aws_acm_certificate" "example" { - domain = "tf.example.com" - key_types = ["RSA_4096"] -} ``` ## Argument Reference - * `domain` - (Required) The domain of the certificate to look up. If no certificate is found with this name, an error will be returned. - * `key_types` - (Optional) A list of key algorithms to filter certificates. By default, ACM does not return all certificate types when searching. Valid values are `RSA_1024`, `RSA_2048`, `RSA_4096`, `EC_prime256v1`, `EC_secp384r1`, and `EC_secp521r1`. - * `statuses` - (Optional) A list of statuses on which to filter the returned list. Valid values are `PENDING_VALIDATION`, `ISSUED`, - `INACTIVE`, `EXPIRED`, `VALIDATION_TIMED_OUT`, `REVOKED` and `FAILED`. If no value is specified, only certificates in the `ISSUED` state - are returned. - * `types` - (Optional) A list of types on which to filter the returned list. Valid values are `AMAZON_ISSUED` and `IMPORTED`. - * `most_recent` - (Optional) If set to true, it sorts the certificates matched by previous criteria by the NotBefore field, returning only the most recent one. If set to false, it returns an error if more than one certificate is found. Defaults to false. +- `id` - (Optional, int) ID of the project. +- `name` - (Optional, string) Name of the project. ## Attributes Reference - * `arn` - Set to the ARN of the found certificate, suitable for referencing in other resources that support ACM certificates. - * `tags` - A mapping of tags for the resource. - +- `id` - (int) Unique ID of the project. +- `name` - (string) Name of the project. diff --git a/docs/data_sources/harbor_registry.md b/docs/data_sources/harbor_registry.md new file mode 100644 index 0000000..80f8329 --- /dev/null +++ b/docs/data_sources/harbor_registry.md @@ -0,0 +1,24 @@ +# Data Source: harbor_registry + +## Example Usage + +```hcl +data "harbor_registry" "registry_1" { + name = "main" +} + +data "harbor_registry" "registry_2" { + id = 4 +} + +``` + +## Argument Reference + +- `id` - (Optional, string) ID of the registry. +- `name` - (Optional, string) Name of the registry. + +## Attributes Reference + +- `id` - (int) Unique ID of the registry. +- `name` - (string) Name of the registry. diff --git a/docs/guides/development.md b/docs/guides/development.md index 0bbb3b7..c16cbac 100644 --- a/docs/guides/development.md +++ b/docs/guides/development.md @@ -40,10 +40,8 @@ Please use the ```develop``` branch for new features and fixes. ### Releasing The [Github Release](https://github.com/nolte/terraform-provider-harbor/releases) Assets will be automatical attatch from the build job see ```.github/workflows/go.yml```. -![Go](https://github.com/nolte/terraform-provider-harbor/workflows/Go/badge.svg?branch=master) - -For a Easy Relase process we use the GitHub Commandline Interface [cli.github.com](https://cli.github.com/manual/). - +![Go](https://github.com/nolte/terraform-provider-harbor/workflows/Go/badge.svg?branch=master) +For a Easy Relase process we use the GitHub Commandline Interface [cli.github.com](https://cli.github.com/manual/). Each Release will be start from the ```develop``` branch. ```sh @@ -58,6 +56,19 @@ mkdocs serve ``` and open [127.0.0.1:8000](http://127.0.0.1:8000/) +## Development Shortcuts + +**build and test in one command** + +```sh +make compile \ + && make install \ + && bats scripts/test/bats/build +``` + +``` +terraform import -var harbor_endpoint=${HARBOR_ENDPOINT} -var harbor_base_path='/api' harbor_project.main 24 +``` ## Links diff --git a/docs/index.css b/docs/index.css deleted file mode 100644 index 4cbf726..0000000 --- a/docs/index.css +++ /dev/null @@ -1,7 +0,0 @@ - -.wy-nav-content { - background: white; - max-width: 100%; - height: 100vh; - margin: 0; - } \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index e43ac22..e8bb6f0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,9 +15,22 @@ app/service documentation. ## Example Usage ```hcl -provider "harbor" { - url = "demo.goharbor.io" - basepath = "/api/v2.0" +# example for harbor v2 api usage +provider "harborv2" { + host = "demo.goharbor.io" + schema = "https" + insecure = true + basepath = "/api/v2" + username = "admin" + password = "Harbor12345" +} + +# example for harbor v1 api usage +provider "harborv1" { + host = var.harbor_endpoint + schema = "https" + insecure = true + basepath = var.harbor_base_path username = "admin" password = "Harbor12345" } @@ -29,21 +42,17 @@ In addition to [generic `provider` arguments](https://www.terraform.io/docs/conf (e.g. `alias` and `version`), the following arguments are supported in the Harbor `provider` block: -* `url` - (Required) ddd - -* `basepath` - (Optional) - -* `basepath` - (Optional) +* `host` - (Required) Hostname from the [Harbor](https://goharbor.io) Service. like _demo.goharbor.io_ -* `basepath` - (Optional) +* `username` - (Required) Username for authorize at the harbor. -* `basepath` - (Optional) +* `password` - (Required) Password from given user. -* `basepath` - (Optional) +* `schema` - (Optional) Set Used http Schema, possible values are: ```https,http```. Default: ```https``` -* `basepath` - (Optional) +* `insecure` - (Optional) Verify Https Certificates. Default: ```false``` -* `basepath` - (Optional) +* `basepath` - (Optional) The Harbor Api basepath, for example use ```/api``` for default HarborV1 and ```/api/v2``` for Harbor V2 Deployments. Default: ```/api``` ## Install the Custom Provider diff --git a/docs/js/extra.js b/docs/js/extra.js deleted file mode 100644 index 5987ef1..0000000 --- a/docs/js/extra.js +++ /dev/null @@ -1,6 +0,0 @@ - -document.addEventListener("DOMContentLoaded", function () { - document.querySelectorAll("table").forEach(function (table) { - table.classList.add("docutils"); - }); -}); diff --git a/docs/js/table.js b/docs/js/table.js new file mode 100644 index 0000000..0dc6f15 --- /dev/null +++ b/docs/js/table.js @@ -0,0 +1,5 @@ +document.addEventListener("DOMContentLoaded", function() { + document.querySelectorAll("table").forEach(function(table) { + table.classList.add("docutils"); + }); +}); diff --git a/docs/resources/harbor_label.md b/docs/resources/harbor_label.md new file mode 100644 index 0000000..9dd153b --- /dev/null +++ b/docs/resources/harbor_label.md @@ -0,0 +1,53 @@ +# Resource: harbor_label + +Harbor Doc: [Managing Labels](https://goharbor.io/docs/1.10/working-with-projects/working-with-images/create-labels/) +Harbor Api: [/labels](https://demo.goharbor.io/#/Products/post_labels) + +## Example Usage + +```hcl +resource "harbor_label" "main" { + name = "testlabel" + description = "Test Label" + color = "#61717D" + scope = "g" +} + +resource "harbor_label" "project_label" { + name = "projectlabel" + description = "Test Label for Project" + color = "#333333" + scope = "p" + project_id = harbor_project.main.id +} +``` + +## Argument Reference + +The following arguments are required: + +* `name` - (Required) Name of the Project. + +The following arguments are optional: + +* `description` - (Optional) The description of the label account will be displayed in harbor. + +* `color` - (Optional) The color the label. + +* `scope` - (Optional) The scope the label, `p` for project and `g` for global. + +* `project_id` - (Optional) The ID of project that the label belongs to, must be set if sope project. + +## Attributes Reference + +In addition to all argument, the folloing attributes are exported: + +* `id` - The id of the registry with harbor. + +## Import + +Harbor Projects can be imported using the `harbor_label`, e.g. + +```sh +terraform import harbor_label.helmhub 1 +``` diff --git a/docs/resources/harbor_project.md b/docs/resources/harbor_project.md index 9b23b3f..4666b20 100644 --- a/docs/resources/harbor_project.md +++ b/docs/resources/harbor_project.md @@ -7,13 +7,15 @@ description: |- # Resource: harbor_project -Manages an Access Analyzer Analyzer. More information can be found in the [Access Analyzer User Guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html). +Handle a [Harbor Project Ressource](https://goharbor.io/docs/1.10/working-with-projects/create-projects/). ## Example Usage ```hcl -resource "aws_accessanalyzer_analyzer" "example" { - analyzer_name = "example" +resource "harbor_project" "main" { + name = "main" + public = false # (Optional) Default value is false + vulnerability_scanning = true # (Optional) Default vale is true. Automatically scan images on push } ``` @@ -21,23 +23,29 @@ resource "aws_accessanalyzer_analyzer" "example" { The following arguments are required: -* `analyzer_name` - (Required) Name of the Analyzer. +* `name` - (Required) Name of the Project. The following arguments are optional: -* `tags` - (Optional) Key-value map of resource tags. -* `type` - (Optional) Type of Analyzer. Valid value is currently only `ACCOUNT`. Defaults to `ACCOUNT`. +* `public` - (Optional) Handle the access to the hosted images. Default: `true` + + If `true` Any user can pull images from this project. This is a convenient way for you to share repositories with others. + + If `false` Only users who are members of the project can pull images + +* `vulnerability_scanning` - (Optional) Activate [Vulnerability Scanning](https://goharbor.io/docs/1.10/administration/vulnerability-scanning/). Default: `true` + ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `id` - Analyzer name. +* `id` - Harbor Project ID. ## Import -Access Analyzer Analyzers can be imported using the `analyzer_name`, e.g. +Harbor Projects can be imported using the `harbor_project`, e.g. ``` -$ terraform import aws_accessanalyzer_analyzer.example example +$ terraform import harbor_project.main 1 ``` diff --git a/docs/resources/harbor_project_member.md b/docs/resources/harbor_project_member.md deleted file mode 100644 index eb6612a..0000000 --- a/docs/resources/harbor_project_member.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -subcategory: "config" -page_title: "Harbor: harbor_project_member" -description: |- - Manages an user project Memeberships ---- - - -# Resource: harbor_project_member - -## Example Usage -``` -resource "haror_project" "main" { - name = "main" -} - -resource "harbor_project_member" "main" { - project_id = harbor_project.main.project_id - name = "testing1" - role = "master" - type = "oidc" -} - -``` - -## Argument Reference -The following arguments are supported: - -* **name** - (Required) The name of the member entity - -* **project_id** - (Required) The project id of the project that the entity will have access to. - -* **role** - (Required) The premissions that the entity will be granted. - -* **type** - (Requried) The group type. Can be set to **"ldap"**, **"internal"** or **"oidc"** - -`NOTE: odic group type can only be used with harbor version v1.10.1 and above` \ No newline at end of file diff --git a/docs/resources/harbor_registry.md b/docs/resources/harbor_registry.md index 888e7da..106eeb2 100644 --- a/docs/resources/harbor_registry.md +++ b/docs/resources/harbor_registry.md @@ -1,19 +1,11 @@ ---- -subcategory: "registry" -page_title: "Harbor: harbor_registry" -description: |- - Manages an Harbor registry ---- - - # Resource: harbor_registry Harbor Doc: [managing-registries](https://goharbor.io/docs/2.0.0/administration/configuring-replication/create-replication-endpoints/#managing-registries) Harbor Api: [Create](https://demo.goharbor.io/#/Products/post_registries) - ## Example Usage -``` + +```hcl resource "harbor_registry" "helmhub" { name = "helmhub" url = "https://hub.helm.sh" @@ -24,20 +16,29 @@ resource "harbor_registry" "helmhub" { ``` ## Argument Reference -The following arguments are supported: -* **name** - (Required) The of the project that will be created in harbor. +The following arguments are supported: -* **url** - (Required) The registry remote endpoint, like ```https://hub.docker.com```. +* `name` - (Required) The of the project that will be created in harbor. -* **type** - (Required) registry Type Posible values are ```huawei-SWR, aws-ecr, ali-acr, jfrog-artifactory, gitlab, docker-registry, docker-hub, azure-acr, quay-io, helm-hub, harbor, google-gcr```. +* `url` - (Required) The registry remote endpoint, like `https://hub.docker.com`. -* **description** - (Optional) The description of the registry will be displayed in harbor. +* `type` - (Required) registry Type possible values are `huawei-SWR, aws-ecr, ali-acr, jfrog-artifactory, gitlab, docker-registry, docker-hub, azure-acr, quay-io, helm-hub, harbor, google-gcr`. -* **insecure** - (Optional) Harbor ignores insecure external registry errors. Can be set to **"true"** or **"false"** (Default: false) +* `description` - (Optional) The description of the registry will be displayed in harbor. +* `insecure` - (Optional) Harbor ignores insecure external registry errors. Can be set to `true` or `false` (Default: `false`) ## Attributes Reference + In addition to all argument, the folloing attributes are exported: -* **repository_id** - The id of the registry with harbor. +* `id` - The id of the registry with harbor. + +## Import + +Harbor Projects can be imported using the `harbor_registry`, e.g. + +```sh +terraform import harbor_registry.helmhub 1 +``` diff --git a/docs/resources/harbor_robot_account.md b/docs/resources/harbor_robot_account.md index 9b267cd..4e0c44a 100644 --- a/docs/resources/harbor_robot_account.md +++ b/docs/resources/harbor_robot_account.md @@ -1,38 +1,48 @@ ---- -subcategory: "project" -page_title: "Harbor: harbor_robot_account" -description: |- - Manages an Harbor Robot Account ---- - # Resource: harbor_robot_account ## Example Usage -``` + +```hcl resource "haror_project" "main" { name = "main" } -resource "harbor_robot_account" "account" { - name = "${harbor_project.main.name}" +resource "harbor_robot_account" "master_robot" { + name = "god" description = "Robot account used to push images to harbor" - project_id = harbor_project.main.project_id - action = "push" + project_id = harbor_project.main.id + actions = ["docker_read", "docker_write", "helm_read", "helm_write"] +} + +output "harbor_robot_account_token" { + value = data.harbor_robot_account.master_robot.token } ``` ## Argument Reference + The following arguments are supported: -* **name** - (Required) The of the project that will be created in harbor. +* `name` - (Required) The of the project that will be created in harbor. -* **description** - (Optional) The description of the robot account will be displayed in harbor. +* `description` - (Optional) The description of the robot account will be displayed in harbor. -* **project_id** - (Required) The project id of the project that the robot account will be associated with. +* `project_id` - (Required) The project id of the project that the robot account will be associated with. -* **action** - (Optional) The action that the robot account will be able to perform on the project. Can be **"pull"** or **"push"** (Default: **pull**). +* `actions` - (Optional) ## Attributes Reference + In addition to all argument, the folloing attributes are exported: -* **token** - The token of the robot account. \ No newline at end of file +* `id` - The id of the robot account. + +* `token` - The token of the robot account. + +## Import + +Harbor Projects can be imported using the `harbor_robot_account`, e.g. + +```sh +terraform import harbor_robot_account.master_robot 29 +``` diff --git a/harbor/data_source_label.go b/harbor/data_source_label.go new file mode 100644 index 0000000..fba2925 --- /dev/null +++ b/harbor/data_source_label.go @@ -0,0 +1,79 @@ +package harbor + +import ( + "fmt" + "strconv" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceLabel() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "scope": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "id": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "project_id": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "color": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "deleted": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + }, + Read: dataSourceLabelRead, + } +} + +func dataSourceLabelRead(d *schema.ResourceData, m interface{}) error { + if _, ok := d.GetOk("name"); ok { + if _, ok := d.GetOk("scope"); ok { + registry, err := findLabelByNameAndScope(d, m) + if err != nil { + return err + } + if err := setLabelSchema(d, registry); err != nil { + return err + } + return nil + } + } + if labelID, ok := d.GetOk("id"); ok { + d.SetId(strconv.Itoa(labelID.(int))) + label, err := findLabelByID(d, m) + if err != nil { + return err + } + if err := setLabelSchema(d, label); err != nil { + return err + } + return nil + } + + return fmt.Errorf("please specify a combination of name and scope or Id to lookup for a label") +} diff --git a/harbor/data_source_project.go b/harbor/data_source_project.go index 27367df..3852c8d 100644 --- a/harbor/data_source_project.go +++ b/harbor/data_source_project.go @@ -1,9 +1,9 @@ package harbor import ( - "log" + "fmt" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -14,11 +14,22 @@ func dataSourceProject() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, - Required: true, - ForceNew: true, + Optional: true, + Computed: true, }, - "project_id": { + "id": { Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "public": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "vulnerability_scanning": { + Type: schema.TypeBool, + Optional: true, Computed: true, }, }, @@ -28,13 +39,28 @@ func dataSourceProject() *schema.Resource { } func dataSourceProjectRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - query := products.NewGetProjectsParams().WithName(d.Get("name").(*string)) - resp, err := apiClient.Client.Products.GetProjects(query, nil) - if err != nil { - log.Fatal(err) + apiClient := m.(*client.Harbor) + if _, ok := d.GetOk("name"); ok { + project, err := findProjectByName(d, m) + if err != nil { + return err + } + if err = setProjectSchema(d, project); err != nil { + return err + } + return nil } + if id, ok := d.GetOk("id"); ok { + resp, err := apiClient.Products.GetProjectsProjectID(products.NewGetProjectsProjectIDParams().WithProjectID(int64(id.(int))), nil) + if err != nil { + return err + } + if err = setProjectSchema(d, resp.Payload); err != nil { + return err + } + return nil - d.Set("project_id", resp.Payload[0].ProjectID) - return nil + } + d.SetId("") + return fmt.Errorf("please specify a name to lookup for a project") } diff --git a/harbor/data_source_registry.go b/harbor/data_source_registry.go index d13aaa4..e275505 100644 --- a/harbor/data_source_registry.go +++ b/harbor/data_source_registry.go @@ -1,10 +1,10 @@ package harbor import ( - "log" + "fmt" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" ) @@ -13,28 +13,62 @@ func dataSourceRegistry() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { Type: schema.TypeString, - Required: true, - ForceNew: true, + Optional: true, + Computed: true, }, - "repository_id": { + "id": { Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "url": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "insecure": { + Type: schema.TypeBool, + Optional: true, Computed: true, }, }, - Read: dataSourceProjectRead, + Read: dataSourceRegistryRead, } } func dataSourceRegistryRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) - query := products.NewGetRegistriesParams().WithName(d.Get("name").(*string)) - resp, err := apiClient.Client.Products.GetRegistries(query, nil) - if err != nil { - log.Fatal(err) + if _, ok := d.GetOk("name"); ok { + registry, err := findRegistryByName(d, m) + if err != nil { + return err + } + if err := setRegistrySchema(d, registry); err != nil { + return err + } + return nil + } + if id, ok := d.GetOk("id"); ok { + resp, err := apiClient.Products.GetRegistriesID(products.NewGetRegistriesIDParams().WithID(int64(id.(int))), nil) + if err != nil { + return err + } + if err := setRegistrySchema(d, resp.Payload); err != nil { + return err + } + return nil } - d.Set("repository_id", resp.Payload[0].ID) - - return nil + return fmt.Errorf("please specify a name to lookup for a registries") } diff --git a/harbor/provider.go b/harbor/provider.go index 1967d40..b587648 100644 --- a/harbor/provider.go +++ b/harbor/provider.go @@ -9,17 +9,23 @@ import ( func Provider() terraform.ResourceProvider { return &schema.Provider{ Schema: map[string]*schema.Schema{ - "url": { - Type: schema.TypeString, - Required: true, + "host": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("HARBOR_ENDPOINT", nil), }, "username": { Type: schema.TypeString, - Optional: true, + Required: true, }, "password": { + Type: schema.TypeString, + Required: true, + }, + "schema": { Type: schema.TypeString, Optional: true, + Default: "https", }, "insecure": { Type: schema.TypeBool, @@ -46,17 +52,19 @@ func Provider() terraform.ResourceProvider { DataSourcesMap: map[string]*schema.Resource{ "harbor_project": dataSourceProject(), "harbor_registry": dataSourceRegistry(), + "harbor_label": dataSourceLabel(), }, ConfigureFunc: providerConfigure, } } func providerConfigure(d *schema.ResourceData) (interface{}, error) { - url := d.Get("url").(string) + host := d.Get("host").(string) username := d.Get("username").(string) password := d.Get("password").(string) insecure := d.Get("insecure").(bool) basepath := d.Get("basepath").(string) + schema := d.Get("schema").(string) - return client.NewClient(url, username, password, insecure, basepath), nil + return client.NewClient(host, username, password, insecure, basepath, schema), nil } diff --git a/harbor/resource_config_auth.go b/harbor/resource_config_auth.go index 168d22a..3f7ca0c 100644 --- a/harbor/resource_config_auth.go +++ b/harbor/resource_config_auth.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -57,8 +57,8 @@ func resourceConfigAuth() *schema.Resource { // dasdas func resourceConfigAuthRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - resp, err := apiClient.Client.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) + apiClient := m.(*client.Harbor) + resp, err := apiClient.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) if err != nil { log.Fatal(err) } @@ -91,7 +91,7 @@ func resourceConfigAuthRead(d *schema.ResourceData, m interface{}) error { func resourceConfigAuthUpdate(d *schema.ResourceData, m interface{}) error { apiClient, body := newAPIClient(d, m) - _, err := apiClient.Client.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&body), nil) + _, err := apiClient.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&body), nil) if err != nil { return err } @@ -103,8 +103,8 @@ func resourceConfigAuthDelete(d *schema.ResourceData, m interface{}) error { return nil } -func newAPIClient(d *schema.ResourceData, m interface{}) (*client.Client, models.Configurations) { - apiClient := m.(*client.Client) +func newAPIClient(d *schema.ResourceData, m interface{}) (*client.Harbor, models.Configurations) { + apiClient := m.(*client.Harbor) body := models.Configurations{ AuthMode: d.Get("auth_mode").(string), diff --git a/harbor/resource_config_email.go b/harbor/resource_config_email.go index 7e6124f..4fa6980 100644 --- a/harbor/resource_config_email.go +++ b/harbor/resource_config_email.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -53,8 +53,8 @@ func resourceConfigEmail() *schema.Resource { } func resourceConfigEmailCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - _, err := apiClient.Client.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&models.Configurations{ + apiClient := m.(*client.Harbor) + _, err := apiClient.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&models.Configurations{ EmailHost: d.Get("email_host").(string), EmailPort: int64(d.Get("email_port").(int)), EmailUsername: d.Get("email_username").(string), @@ -70,9 +70,9 @@ func resourceConfigEmailCreate(d *schema.ResourceData, m interface{}) error { } func resourceConfigEmailRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) - resp, err := apiClient.Client.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) + resp, err := apiClient.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) if err != nil { log.Fatal(err) } diff --git a/harbor/resource_config_system.go b/harbor/resource_config_system.go index 3891856..34ae56a 100644 --- a/harbor/resource_config_system.go +++ b/harbor/resource_config_system.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -39,8 +39,8 @@ func resourceConfigSystem() *schema.Resource { func resourceConfigSystemRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - resp, err := apiClient.Client.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) + apiClient := m.(*client.Harbor) + resp, err := apiClient.Products.GetConfigurations(products.NewGetConfigurationsParams(), nil) if err != nil { log.Fatal(err) } @@ -63,8 +63,8 @@ func resourceConfigSystemRead(d *schema.ResourceData, m interface{}) error { } func resourceConfigSystemUpdate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - _, err := apiClient.Client.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&models.Configurations{ + apiClient := m.(*client.Harbor) + _, err := apiClient.Products.PutConfigurations(products.NewPutConfigurationsParams().WithConfigurations(&models.Configurations{ ProjectCreationRestriction: d.Get("project_creation_restriction").(string), TokenExpiration: int64(d.Get("robot_token_expiration").(int)), ReadOnly: d.Get("read_only").(bool), diff --git a/harbor/resource_labels.go b/harbor/resource_labels.go index 3cb2820..2f31894 100644 --- a/harbor/resource_labels.go +++ b/harbor/resource_labels.go @@ -3,10 +3,10 @@ package harbor import ( "fmt" "log" + "strconv" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -17,16 +17,12 @@ func resourceLabel() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ForceNew: true, }, "project_id": { Type: schema.TypeInt, Optional: true, Default: 0, - }, - "label_id": { - Type: schema.TypeInt, - Computed: true, + ForceNew: true, }, "description": { Type: schema.TypeString, @@ -36,7 +32,7 @@ func resourceLabel() *schema.Resource { "color": { Type: schema.TypeString, Optional: true, - Default: "green", + Default: "#61717D", }, "deleted": { Type: schema.TypeBool, @@ -55,6 +51,9 @@ func resourceLabel() *schema.Resource { Read: resourceLabelRead, Update: resourceLabelUpdate, Delete: resourceLabelDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, } } func buildLabel(d *schema.ResourceData) *models.Label { @@ -68,82 +67,118 @@ func buildLabel(d *schema.ResourceData) *models.Label { } } func resourceLabelCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) body := products.NewPostLabelsParams().WithLabel(buildLabel(d)) - - _, err := apiClient.Client.Products.PostLabels(body, nil) + _, err := apiClient.Products.PostLabels(body, nil) if err != nil { log.Fatal(err) } //d.Set("Label_id", resp.Payload[0].LabelID) - d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("name").(string)))) + label, err := findLabelByNameAndScope(d, m) + if err != nil { + return err + } + d.SetId(strconv.Itoa(int(label.ID))) return resourceLabelRead(d, m) } -func resourceLabelRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - LabelName := d.Get("name").(string) - query := products.NewGetLabelsParams().WithScope(d.Get("scope").(string)).WithName(&LabelName) - resp, err := apiClient.Client.Products.GetLabels(query, nil) - if err != nil { - log.Fatal(err) +func findLabelByNameAndScope(d *schema.ResourceData, m interface{}) (*models.Label, error) { + apiClient := m.(*client.Harbor) + if name, ok := d.GetOk("name"); ok { + if scope, ok := d.GetOk("scope"); ok { + searchName := name.(string) + scopeName := scope.(string) + query := products.NewGetLabelsParams().WithScope(scopeName).WithName(&searchName) + if scopeName == "p" { + projectID := int64(d.Get("project_id").(int)) + query = query.WithProjectID(&projectID) + } + resp, err := apiClient.Products.GetLabels(query, nil) + if err != nil { + d.SetId("") + return &models.Label{}, err + } + if len(resp.Payload) < 1 { + return &models.Label{}, fmt.Errorf("no label found with name %v", searchName) + } else if resp.Payload[0].Name != searchName { + return &models.Label{}, fmt.Errorf("Response Name %v not match with Expected Name %v", resp.Payload[0].Name, searchName) + } + return resp.Payload[0], nil + } } - if len(resp.Payload) < 1 { - d.SetId("") - return nil + return &models.Label{}, fmt.Errorf("Fail to lookup label by Name and Scope") +} + +func findLabelByID(d *schema.ResourceData, m interface{}) (*models.Label, error) { + apiClient := m.(*client.Harbor) + if searchID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + query := products.NewGetLabelsIDParams().WithID(searchID) + resp, err := apiClient.Products.GetLabelsID(query, nil) + if err != nil { + return &models.Label{}, err + } + return resp.Payload, nil } + fmt.Println(d.Id(), "is not an integer.") + return &models.Label{}, fmt.Errorf("fail to find the label") +} - if err := d.Set("label_id", int(resp.Payload[0].ID)); err != nil { +func setLabelSchema(d *schema.ResourceData, resp *models.Label) error { + d.SetId(strconv.Itoa(int(resp.ID))) + if err := d.Set("name", string(resp.Name)); err != nil { return err } - - if err := d.Set("name", string(resp.Payload[0].Name)); err != nil { + if err := d.Set("description", resp.Description); err != nil { return err } - if err := d.Set("description", resp.Payload[0].Description); err != nil { + if err := d.Set("deleted", resp.Deleted); err != nil { return err } - - if err := d.Set("deleted", resp.Payload[0].Deleted); err != nil { + if err := d.Set("color", resp.Color); err != nil { return err } - if err := d.Set("color", resp.Payload[0].Color); err != nil { + if err := d.Set("scope", resp.Scope); err != nil { return err } - if err := d.Set("scope", resp.Payload[0].Scope); err != nil { + if err := d.Set("project_id", int(resp.ProjectID)); err != nil { return err } - if err := d.Set("project_id", int(resp.Payload[0].ProjectID)); err != nil { + return nil +} +func resourceLabelRead(d *schema.ResourceData, m interface{}) error { + label, err := findLabelByID(d, m) + if err != nil { + return err + } + if err := setLabelSchema(d, label); err != nil { return err } - return nil } func resourceLabelUpdate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - - body := products.NewPutLabelsIDParams().WithLabel(buildLabel(d)) - - _, err := apiClient.Client.Products.PutLabelsID(body, nil) - if err != nil { - log.Fatal(err) + apiClient := m.(*client.Harbor) + if resourceID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + body := products.NewPutLabelsIDParams().WithLabel(buildLabel(d)).WithID(resourceID) + if _, err := apiClient.Products.PutLabelsID(body, nil); err != nil { + return err + } + return resourceLabelRead(d, m) } - - return resourceLabelRead(d, m) + return fmt.Errorf("Label Id not a Integer") } func resourceLabelDelete(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - labelID := d.Get("label_id").(int) - - delete := products.NewDeleteLabelsIDParams().WithID(int64(labelID)) - _, err := apiClient.Client.Products.DeleteLabelsID(delete, nil) - if err != nil { - log.Fatal(err) + apiClient := m.(*client.Harbor) + if resourceID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + delete := products.NewDeleteLabelsIDParams().WithID(resourceID) + if _, err := apiClient.Products.DeleteLabelsID(delete, nil); err != nil { + return err + } + d.SetId("") + return nil } - d.SetId("") - return nil + return fmt.Errorf("Label Id not a Integer") } diff --git a/harbor/resource_project.go b/harbor/resource_project.go index b23ccb7..c84aa65 100644 --- a/harbor/resource_project.go +++ b/harbor/resource_project.go @@ -2,11 +2,10 @@ package harbor import ( "fmt" - "log" + "strconv" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -19,17 +18,13 @@ func resourceProject() *schema.Resource { Required: true, ForceNew: true, }, - "project_id": { - Type: schema.TypeInt, - Computed: true, - }, "public": { - Type: schema.TypeString, + Type: schema.TypeBool, Optional: true, Default: false, }, "vulnerability_scanning": { - Type: schema.TypeString, + Type: schema.TypeBool, Optional: true, Default: true, }, @@ -38,86 +33,131 @@ func resourceProject() *schema.Resource { Read: resourceProjectRead, Update: resourceProjectUpdate, Delete: resourceProjectDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, } } func resourceProjectCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) + projectName := d.Get("name").(string) body := products.NewPostProjectsParams().WithProject(&models.ProjectReq{ - ProjectName: d.Get("name").(string), + ProjectName: projectName, Metadata: &models.ProjectMetadata{ - AutoScan: d.Get("vulnerability_scanning").(string), - Public: d.Get("public").(string), + AutoScan: strconv.FormatBool(d.Get("vulnerability_scanning").(bool)), + Public: strconv.FormatBool(d.Get("public").(bool)), }, }) - _, err := apiClient.Client.Products.PostProjects(body, nil) - if err != nil { - log.Fatal(err) + if _, err := apiClient.Products.PostProjects(body, nil); err != nil { + return err } - //d.Set("project_id", resp.Payload[0].ProjectID) - d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("name").(string)))) - return resourceProjectRead(d, m) -} - -func resourceProjectRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - projectName := d.Get("name").(string) - query := products.NewGetProjectsParams().WithName(&projectName) - resp, err := apiClient.Client.Products.GetProjects(query, nil) + project, err := findProjectByName(d, m) if err != nil { - log.Fatal(err) - } - if len(resp.Payload) < 1 { - d.SetId("") - return nil - } - if err := d.Set("project_id", int(resp.Payload[0].ProjectID)); err != nil { return err } + d.SetId(strconv.Itoa(int(project.ProjectID))) + return resourceProjectRead(d, m) - if err := d.Set("name", string(resp.Payload[0].Name)); err != nil { - return err - } +} - if err := d.Set("vulnerability_scanning", string(resp.Payload[0].Metadata.AutoScan)); err != nil { - return err +func findProjectByName(d *schema.ResourceData, m interface{}) (*models.Project, error) { + apiClient := m.(*client.Harbor) + if name, ok := d.GetOk("name"); ok { + projectName := name.(string) + query := products.NewGetProjectsParams().WithName(&projectName) + resp, err := apiClient.Products.GetProjects(query, nil) + if err != nil { + d.SetId("") + return &models.Project{}, err + } + if len(resp.Payload) < 1 { + return &models.Project{}, fmt.Errorf("no project found with name %v", projectName) + } else if resp.Payload[0].Name != projectName { + return &models.Project{}, fmt.Errorf("Response Name %v not match with Expected Name %v", resp.Payload[0].Name, projectName) + } + return resp.Payload[0], nil } + return &models.Project{}, fmt.Errorf("Fail to lookup project by Name") +} - if err := d.Set("public", string(resp.Payload[0].Metadata.Public)); err != nil { - return err +func resourceProjectRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Harbor) + + if projectID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + query := products.NewGetProjectsProjectIDParams().WithProjectID(projectID) + resp, err := apiClient.Products.GetProjectsProjectID(query, nil) + if err != nil { + return err + } + if err := setProjectSchema(d, resp.Payload); err != nil { + return err + } + return nil } - return nil + fmt.Println(d.Id(), "is not an integer.") + return fmt.Errorf("fail to load the project") } func resourceProjectUpdate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) + + if projectID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + body := products.NewPutProjectsProjectIDParams().WithProject(&models.ProjectReq{ + ProjectName: d.Get("name").(string), + Metadata: &models.ProjectMetadata{ + AutoScan: d.Get("vulnerability_scanning").(string), + Public: d.Get("public").(string), + }, + }).WithProjectID(projectID) - body := products.NewPutProjectsProjectIDParams().WithProject(&models.ProjectReq{ - ProjectName: d.Get("name").(string), - Metadata: &models.ProjectMetadata{ - AutoScan: d.Get("vulnerability_scanning").(string), - Public: d.Get("public").(string), - }, - }).WithProjectID(int64(d.Get("project_id").(int))) + if _, err := apiClient.Products.PutProjectsProjectID(body, nil); err != nil { + return err + } - _, err := apiClient.Client.Products.PutProjectsProjectID(body, nil) - if err != nil { - log.Fatal(err) + return resourceProjectRead(d, m) } + return fmt.Errorf("Project Id not a Integer") - return resourceProjectRead(d, m) } func resourceProjectDelete(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - projectId := d.Get("project_id").(int) + apiClient := m.(*client.Harbor) + if projectID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + delete := products.NewDeleteProjectsProjectIDParams().WithProjectID(projectID) + if _, err := apiClient.Products.DeleteProjectsProjectID(delete, nil); err != nil { + return err + } + return nil + } + return fmt.Errorf("Project Id not a Integer") +} + +func setProjectSchema(data *schema.ResourceData, project *models.Project) error { + data.SetId(strconv.Itoa(int(project.ProjectID))) + + if err := data.Set("name", project.Name); err != nil { + return err + } + + autoScan, err := strconv.ParseBool(project.Metadata.AutoScan) + if err != nil { + return err + } - delete := products.NewDeleteProjectsProjectIDParams().WithProjectID(int64(projectId)) - _, err := apiClient.Client.Products.DeleteProjectsProjectID(delete, nil) + if err := data.Set("vulnerability_scanning", autoScan); err != nil { + return err + } + public, err := strconv.ParseBool(project.Metadata.Public) if err != nil { - log.Fatal(err) + return err + } + + if err := data.Set("public", public); err != nil { + return err } + return nil } diff --git a/harbor/resource_registry.go b/harbor/resource_registry.go index 5678145..6429d03 100644 --- a/harbor/resource_registry.go +++ b/harbor/resource_registry.go @@ -3,10 +3,10 @@ package harbor import ( "fmt" "log" + "strconv" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) @@ -14,10 +14,6 @@ import ( func resourceRegistry() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ - "repository_id": { - Type: schema.TypeInt, - Computed: true, - }, "name": { Type: schema.TypeString, Required: true, @@ -45,11 +41,14 @@ func resourceRegistry() *schema.Resource { Read: resourceRegistryRead, Update: resourceRegistryUpdate, Delete: resourceRegistryDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, } } func resourceRegistryCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) body := products.NewPostRegistriesParams().WithRegistry(&models.Registry{ Description: d.Get("description").(string), @@ -58,72 +57,98 @@ func resourceRegistryCreate(d *schema.ResourceData, m interface{}) error { Type: d.Get("type").(string), URL: d.Get("url").(string), }) - _, err := apiClient.Client.Products.PostRegistries(body, nil) + _, err := apiClient.Products.PostRegistries(body, nil) if err != nil { log.Fatal(err) } + registry, err := findRegistryByName(d, m) + if err != nil { + return err + } + d.SetId(strconv.Itoa(int(registry.ID))) - d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", d.Get("name").(string)))) return resourceRegistryRead(d, m) } - +func findRegistryByName(d *schema.ResourceData, m interface{}) (*models.Registry, error) { + apiClient := m.(*client.Harbor) + if name, ok := d.GetOk("name"); ok { + projectName := name.(string) + query := products.NewGetRegistriesParams().WithName(&projectName) + resp, err := apiClient.Products.GetRegistries(query, nil) + if err != nil { + d.SetId("") + return &models.Registry{}, err + } + if len(resp.Payload) < 1 { + return &models.Registry{}, fmt.Errorf("no Registry found with name %v", projectName) + } else if resp.Payload[0].Name != projectName { + return &models.Registry{}, fmt.Errorf("Response Name %v not match with Expected Name %v", resp.Payload[0].Name, projectName) + } + return resp.Payload[0], nil + } + return &models.Registry{}, fmt.Errorf("Fail to lookup Registry by Name") +} func resourceRegistryRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - projectName := d.Get("name").(string) + apiClient := m.(*client.Harbor) + if registryID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + resp, err := apiClient.Products.GetRegistriesID(products.NewGetRegistriesIDParams().WithID(registryID), nil) + if err != nil { + return err + } + if err = setRegistrySchema(d, resp.Payload); err != nil { + return err + } + return nil + } + return fmt.Errorf("Registry Id not a Integer currently: '%s'", d.Id()) - query := products.NewGetRegistriesParams().WithName(&projectName) - resp, err := apiClient.Client.Products.GetRegistries(query, nil) - if err != nil { - log.Fatal(err) +} + +func resourceRegistryUpdate(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Harbor) + if registryID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + if _, err := apiClient.Products.PutRegistriesID(products.NewPutRegistriesIDParams().WithID(registryID).WithRepoTarget(&models.PutRegistry{ + Description: d.Get("description").(string), + Insecure: d.Get("insecure").(bool), + Name: d.Get("name").(string), + URL: d.Get("url").(string), + }), nil); err != nil { + return err + } + return resourceRegistryRead(d, m) } - if len(resp.Payload) < 1 { - d.SetId("") + return fmt.Errorf("Registry Id not a Integer") +} + +func resourceRegistryDelete(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Harbor) + if registryID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + if _, err := apiClient.Products.DeleteRegistriesID(products.NewDeleteRegistriesIDParams().WithID(registryID), nil); err != nil { + return err + } return nil } - if err := d.Set("repository_id", int(resp.Payload[0].ID)); err != nil { - return err - } - if err := d.Set("description", resp.Payload[0].Description); err != nil { + return fmt.Errorf("Registry Id not a Integer") +} + +func setRegistrySchema(d *schema.ResourceData, registry *models.Registry) error { + d.SetId(strconv.Itoa(int(registry.ID))) + + if err := d.Set("description", registry.Description); err != nil { return err } - if err := d.Set("insecure", resp.Payload[0].Insecure); err != nil { + if err := d.Set("insecure", registry.Insecure); err != nil { return err } - if err := d.Set("name", resp.Payload[0].Name); err != nil { + if err := d.Set("name", registry.Name); err != nil { return err } - if err := d.Set("type", resp.Payload[0].Type); err != nil { + if err := d.Set("type", registry.Type); err != nil { return err } - if err := d.Set("url", resp.Payload[0].URL); err != nil { + if err := d.Set("url", registry.URL); err != nil { return err } return nil } - -func resourceRegistryUpdate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - _, err := apiClient.Client.Products.PutRegistriesID(products.NewPutRegistriesIDParams().WithRepoTarget(&models.PutRegistry{ - Description: d.Get("description").(string), - Insecure: d.Get("insecure").(bool), - Name: d.Get("name").(string), - URL: d.Get("url").(string), - }), nil) - - if err != nil { - log.Fatal(err) - } - return resourceRegistryRead(d, m) -} - -func resourceRegistryDelete(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - - _, err := apiClient.Client.Products.DeleteRegistriesID(products.NewDeleteRegistriesIDParams().WithID(int64(d.Get("repository_id").(int))), nil) - if err != nil { - log.Fatal(err) - } - - return nil -} diff --git a/harbor/resource_robot_account.go b/harbor/resource_robot_account.go index 5b5f02a..a3731c2 100644 --- a/harbor/resource_robot_account.go +++ b/harbor/resource_robot_account.go @@ -1,17 +1,22 @@ package harbor import ( + "errors" "fmt" "log" "strconv" + "strings" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) +func robotAccountNamePrefix() string { + return "robot$" +} + func resourceRobotAccount() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -31,84 +36,173 @@ func resourceRobotAccount() *schema.Resource { Default: nil, ForceNew: true, }, - "action": { - Type: schema.TypeString, + "actions": { + Type: schema.TypeList, Optional: true, - Default: "pull", ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, "token": { Type: schema.TypeString, Computed: true, Sensitive: true, }, - "robot_id": { - Type: schema.TypeInt, + "disabled": { + Type: schema.TypeBool, Computed: true, }, }, Create: resourceRobotAccountCreate, Read: resourceRobotAccountRead, Delete: resourceRobotAccountDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + } +} + +func factoryRobotDockerEndpoint(projectID int64) string { + return "/project/" + strconv.FormatInt(projectID, 10) + "/repository" + +} +func factoryRobotAccountAccessDockerRead(projectID int64) *models.RobotAccountAccess { + return &models.RobotAccountAccess{ + Action: "pull", + Resource: factoryRobotDockerEndpoint(projectID), + } +} +func factoryRobotAccountAccessDockerPush(projectID int64) *models.RobotAccountAccess { + return &models.RobotAccountAccess{ + Action: "push", + Resource: factoryRobotDockerEndpoint(projectID), + } +} + +func factoryRobotAccountAccessHelmChartPush(projectID int64) *models.RobotAccountAccess { + return &models.RobotAccountAccess{ + Action: "create", + Resource: "/project/" + strconv.FormatInt(projectID, 10) + "/helm-chart-version", + } +} +func factoryRobotAccountAccessHelmChartRead(projectID int64) *models.RobotAccountAccess { + return &models.RobotAccountAccess{ + Action: "read", + Resource: "/project/" + strconv.FormatInt(projectID, 10) + "/helm-chart", } } func resourceRobotAccountCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) projectid := int64(d.Get("project_id").(int)) name := d.Get("name").(string) - resource := "/project/" + strconv.FormatInt(projectid, 10) + "/repository" + permissionsRoles := d.Get("actions").([]interface{}) + // create the permission list for the robot account + robotAccountAccess := make([]*models.RobotAccountAccess, len(permissionsRoles)) - resp, err := apiClient.Client.Products.PostProjectsProjectIDRobots(products.NewPostProjectsProjectIDRobotsParams().WithProjectID(projectid).WithRobot(&models.RobotAccountCreate{ + for i, role := range permissionsRoles { + switch role.(string) { + case "docker_read": + robotAccountAccess[i] = (factoryRobotAccountAccessDockerRead(projectid)) + case "docker_write": + robotAccountAccess[i] = (factoryRobotAccountAccessDockerPush(projectid)) + case "helm_read": + robotAccountAccess[i] = (factoryRobotAccountAccessHelmChartRead(projectid)) + case "helm_write": + robotAccountAccess[i] = (factoryRobotAccountAccessHelmChartPush(projectid)) + } + } + + resp, err := apiClient.Products.PostProjectsProjectIDRobots(products.NewPostProjectsProjectIDRobotsParams().WithProjectID(projectid).WithRobot(&models.RobotAccountCreate{ Name: name, Description: d.Get("description").(string), - Access: []*models.RobotAccountAccess{ - { - Action: d.Get("action").(string), - Resource: resource, - }, - }, + Access: robotAccountAccess, }), nil) if err != nil { - log.Fatal(err) + return err } if err := d.Set("token", resp.Payload.Token); err != nil { return err } + robot, err := findRobotAccountByProjectAndName(d, m) + if err != nil { + return err + } + d.SetId(strconv.Itoa(int(robot.ID))) return resourceRobotAccountRead(d, m) } -func resourceRobotAccountRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - projectid := int64(d.Get("project_id").(int)) - name := d.Get("name").(string) - log.Printf("Load Robot Accounts from %v Project", projectid) - resp, err := apiClient.Client.Products.GetProjectsProjectIDRobots(products.NewGetProjectsProjectIDRobotsParams().WithProjectID(projectid), nil) +func findRobotAccountByProjectAndName(d *schema.ResourceData, m interface{}) (*models.RobotAccount, error) { + apiClient := m.(*client.Harbor) + name, nameOk := d.GetOk("name") + projectID, projectIDOk := d.GetOk("project_id") - if err != nil { - log.Fatal(err) - } - for _, v := range resp.Payload { - if v.Name == "robot$"+name { - d.Set("robot_id", int(v.ID)) - d.SetId(resource.PrefixedUniqueId(fmt.Sprintf("%s-", v.Name))) + if !nameOk || !projectIDOk { + return &models.RobotAccount{}, errors.New("Fail to get the name and/or project_id for robot account request") + } else { + + query := products.NewGetProjectsProjectIDRobotsParams().WithProjectID(int64(projectID.(int))) + resp, err := apiClient.Products.GetProjectsProjectIDRobots(query, nil) + if err != nil { + return &models.RobotAccount{}, err + } + for _, v := range resp.Payload { + if v.Name == "robot$"+name.(string) { + return v, nil + } } } - return nil + return &models.RobotAccount{}, fmt.Errorf("No Robot found for ProjectID %d, with Name %s", projectID.(int), name.(string)) + } +func resourceRobotAccountRead(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Harbor) + projectID := d.Get("project_id").(int) -func resourceRobotAccountDelete(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + log.Printf("Load Robot Accounts from %v Project", projectID) + if robotID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + query := products.NewGetProjectsProjectIDRobotsRobotIDParams().WithProjectID(int64(projectID)).WithRobotID(robotID) + resp, err := apiClient.Products.GetProjectsProjectIDRobotsRobotID(query, nil) + if err != nil { + return err + } - robotID := int64(d.Get("robot_id").(int)) - projectID := int64(d.Get("project_id").(int)) + if err := setRobotSchema(d, resp.Payload); err != nil { + return err + } - _, err := apiClient.Client.Products.DeleteProjectsProjectIDRobotsRobotID(products.NewDeleteProjectsProjectIDRobotsRobotIDParams().WithRobotID(robotID).WithProjectID(projectID), nil) + } + return nil +} +func setRobotSchema(d *schema.ResourceData, model *models.RobotAccount) error { + d.SetId(strconv.Itoa(int(model.ID))) + if err := d.Set("name", strings.Replace(model.Name, robotAccountNamePrefix(), "", 1)); err != nil { + return err + } + if err := d.Set("description", model.Description); err != nil { + return err + } + if err := d.Set("project_id", int(model.ProjectID)); err != nil { + return err + } - if err != nil { - log.Fatal(err) + if err := d.Set("disabled", model.Disabled); err != nil { + return err } return nil } + +func resourceRobotAccountDelete(d *schema.ResourceData, m interface{}) error { + apiClient := m.(*client.Harbor) + projectID := int64(d.Get("project_id").(int)) + if robotID, err := strconv.ParseInt(d.Id(), 10, 64); err == nil { + _, err := apiClient.Products.DeleteProjectsProjectIDRobotsRobotID(products.NewDeleteProjectsProjectIDRobotsRobotIDParams().WithRobotID(robotID).WithProjectID(projectID), nil) + if err != nil { + return err + } + d.SetId("") + return nil + } + return fmt.Errorf("Fail to Remove Robot Account") +} diff --git a/harbor/resource_tasks.go b/harbor/resource_tasks.go index 160b776..748f47e 100644 --- a/harbor/resource_tasks.go +++ b/harbor/resource_tasks.go @@ -7,12 +7,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/nolte/terraform-provider-harbor/client" + "github.com/nolte/terraform-provider-harbor/gen/harborctl/client" "github.com/nolte/terraform-provider-harbor/gen/harborctl/client/products" "github.com/nolte/terraform-provider-harbor/gen/harborctl/models" ) -var pathVuln = "/api/system/scanAll/schedule" var TypeStr string var CronStr string @@ -32,7 +31,7 @@ func resourceTasks() *schema.Resource { } func resourceTasksCreate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) vulnSchedule := d.Get("vulnerability_scan_policy").(string) getSchedule(vulnSchedule) @@ -43,7 +42,7 @@ func resourceTasksCreate(d *schema.ResourceData, m interface{}) error { Type: TypeStr, }} - resp, err := apiClient.Client.Products.GetSystemScanAllSchedule(products.NewGetSystemScanAllScheduleParams(), nil) + resp, err := apiClient.Products.GetSystemScanAllSchedule(products.NewGetSystemScanAllScheduleParams(), nil) if err != nil { log.Fatalf("Fail to load vulnerability_scan %v", err) } @@ -51,13 +50,13 @@ func resourceTasksCreate(d *schema.ResourceData, m interface{}) error { time := resp.Payload.Schedule.Type if time != "" { log.Printf("Shedule found performing PUT request") - _, err = apiClient.Client.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) + _, err = apiClient.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) if err != nil { log.Fatalf("Fail to update vulnerability_scan %v", err) } } else { log.Printf("No shedule found performing POST request") - _, err = apiClient.Client.Products.PostSystemScanAllSchedule(products.NewPostSystemScanAllScheduleParams().WithSchedule(body), nil) + _, err = apiClient.Products.PostSystemScanAllSchedule(products.NewPostSystemScanAllScheduleParams().WithSchedule(body), nil) if err != nil { log.Fatalf("Fail to create new vulnerability_scan %v", err) } @@ -68,8 +67,8 @@ func resourceTasksCreate(d *schema.ResourceData, m interface{}) error { } func resourceTasksRead(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) - resp, err := apiClient.Client.Products.GetSystemScanAllSchedule(products.NewGetSystemScanAllScheduleParams(), nil) + apiClient := m.(*client.Harbor) + resp, err := apiClient.Products.GetSystemScanAllSchedule(products.NewGetSystemScanAllScheduleParams(), nil) if err != nil { log.Fatal(err) } @@ -82,7 +81,7 @@ func resourceTasksRead(d *schema.ResourceData, m interface{}) error { } func resourceTasksUpdate(d *schema.ResourceData, m interface{}) error { - apiClient := m.(*client.Client) + apiClient := m.(*client.Harbor) vulnSchedule := d.Get("vulnerability_scan_policy").(string) getSchedule(vulnSchedule) @@ -93,7 +92,7 @@ func resourceTasksUpdate(d *schema.ResourceData, m interface{}) error { Type: TypeStr, }} - _, err := apiClient.Client.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) + _, err := apiClient.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) if err != nil { log.Fatal(err) } @@ -103,14 +102,14 @@ func resourceTasksUpdate(d *schema.ResourceData, m interface{}) error { func resourceTasksDelete(d *schema.ResourceData, m interface{}) error { // https://github.com/goharbor/harbor/issues/11083 - // apiClient := m.(*client.Client) + // apiClient := m.(*client.Harbor) // // body := &models.AdminJobSchedule{ // Schedule: &models.AdminJobScheduleObj{ // Cron: "", // }} // - // _, err := apiClient.Client.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) + // _, err := apiClient.Products.PutSystemScanAllSchedule(products.NewPutSystemScanAllScheduleParams().WithSchedule(body), nil) // if err != nil { // log.Fatal(err) // } diff --git a/mkdocs.yml b/mkdocs.yml index 00464ad..8dcab72 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,25 +6,25 @@ nav: - Getting Started: index.md - Data Sources: - harbor_project: data_sources/harbor_project.md - - harbor_registry: "" - + - harbor_registry: data_sources/harbor_registry.md + - harbor_label: data_sources/harbor_label.md - Resources: - harbor_config_system: resources/harbor_config_system.md - harbor_configuration: resources/harbor_configuration.md - - harbor_project_member: resources/harbor_project_member.md - harbor_project: resources/harbor_project.md - harbor_registry: resources/harbor_registry.md - harbor_robot_account: resources/harbor_robot_account.md - harbor_tasks: resources/harbor_tasks.md - - harbor_label: "" + - harbor_label: resources/harbor_label.md - Guides: - Development: guides/development.md - Local E2E Tests: guides/kind.md theme: readthedocs -extra_css: [index.css] markdown_extensions: - toc: permalink: True +extra_css: + - css/table.css extra_javascript: # fix for https://github.com/mkdocs/mkdocs/issues/2028 - - js/extra.js + - js/table.js diff --git a/scripts/test/bats/build/01-acception-test.bats b/scripts/test/bats/build/01-acception-test.bats index 5fd325b..3647bab 100644 --- a/scripts/test/bats/build/01-acception-test.bats +++ b/scripts/test/bats/build/01-acception-test.bats @@ -6,12 +6,13 @@ setup() { terraform init } -teardown() { - terraform destroy -force -var harbor_endpoint=${HARBOR_ENDPOINT} -var harbor_base_path='/api' -# rm -rf .terraform -# rm -rf terraform.tfstate* -} +#teardown() { +# terraform destroy -force -var harbor_endpoint=${HARBOR_ENDPOINT} -var harbor_base_path='/api' +## rm -rf .terraform +## rm -rf terraform.tfstate* +#} @test "Build 1: apply Terraform Script" { + echo "Start test ${HARBOR_ENDPOINT}" terraform apply -auto-approve -parallelism=1 -var harbor_endpoint=${HARBOR_ENDPOINT} -var harbor_base_path='/api' } diff --git a/scripts/test/tf-acception-test/main.tf b/scripts/test/tf-acception-test/main.tf index 3d7620b..dcc24bb 100644 --- a/scripts/test/tf-acception-test/main.tf +++ b/scripts/test/tf-acception-test/main.tf @@ -7,9 +7,9 @@ variable "harbor_base_path" { } provider "harbor" { - url = var.harbor_endpoint + host = var.harbor_endpoint + schema = "https" insecure = true - #url = "demo.goharbor.io" basepath = var.harbor_base_path username = "admin" password = "Harbor12345" @@ -21,32 +21,26 @@ resource "harbor_project" "main" { vulnerability_scanning = true # (Optional) Default vale is true. Automatically scan images on push } -resource "harbor_robot_account" "account" { - name = "myrobot" +resource "harbor_robot_account" "master_robot" { + name = "god" description = "Robot account used to push images to harbor" - project_id = harbor_project.main.project_id - action = "push" + project_id = harbor_project.main.id + actions = ["docker_read", "docker_write", "helm_read", "helm_write"] } -# #resource "harbor_tasks" "main" { -# # vulnerability_scan_policy = "daily" -# #} -# - +output "harbor_robot_account_token" { + value = harbor_robot_account.master_robot.token +} -# v2 problems !!! -### resource "harbor_tasks" "main" { -### vulnerability_scan_policy = "daily" -### } - -resource "harbor_registry" "main" { +# +resource "harbor_registry" "dockerhub" { name = "dockerhub" url = "https://hub.docker.com" type = "docker-hub" description = "Docker Hub Registry" insecure = false } - +# resource "harbor_registry" "helmhub" { name = "helmhub" url = "https://hub.helm.sh" @@ -54,8 +48,63 @@ resource "harbor_registry" "helmhub" { description = "Helm Hub Registry" insecure = false } -## - +# resource "harbor_label" "main" { - name = "testlabel" + name = "testlabel" + description = "Test Label" + color = "#61717D" + scope = "g" +} + +resource "harbor_label" "project_label" { + name = "projectlabel" + description = "Test Label for Project" + color = "#333333" + scope = "p" + project_id = harbor_project.main.id +} + +data "harbor_label" "label_by_name_and_scope" { + name = harbor_label.main.name + scope = harbor_label.main.scope +} + +data "harbor_label" "label_by_id" { + id = harbor_label.main.id +} +output "label_by_id_name" { + value = data.harbor_label.label_by_id.name +} +output "label_by_name_and_scope_name" { + value = data.harbor_label.label_by_name_and_scope.name +} +# registry lookups +data "harbor_registry" "registry_by_id" { + id = harbor_registry.dockerhub.id +} +output "registry_by_id_name" { + value = data.harbor_registry.registry_by_id.name +} + +data "harbor_registry" "registry_by_name" { + name = harbor_registry.dockerhub.name +} +output "registry_by_name_name" { + value = data.harbor_registry.registry_by_name.name +} + +# project lookups + +data "harbor_project" "by_id" { + id = harbor_project.main.id +} +output "project_by_id_name" { + value = data.harbor_project.by_id.name +} + +data "harbor_project" "by_name" { + name = harbor_project.main.name +} +output "project_by_name_name" { + value = data.harbor_project.by_name.name } diff --git a/scripts/test/tf-project-only/main.tf b/scripts/test/tf-project-only/main.tf index 00e102e..ac7c760 100644 --- a/scripts/test/tf-project-only/main.tf +++ b/scripts/test/tf-project-only/main.tf @@ -6,9 +6,9 @@ variable "harbor_base_path" { } provider "harbor" { - url = var.harbor_endpoint + host = var.harbor_endpoint + schema = "https" insecure = true - #url = "demo.goharbor.io" basepath = var.harbor_base_path username = "admin" password = "Harbor12345"