From 3fd4383455c6bb461341e9a757b0ee3ede2e5ccb Mon Sep 17 00:00:00 2001 From: Dennis Ploeger Date: Fri, 22 Dec 2023 15:38:45 +0100 Subject: [PATCH] feat: Include swagger endpoint and docs --- .github/workflows/docs.yml | 42 +++ README.md | 21 +- api.md | 624 +++++++++++++++++++++++++++++++ cmd/docs/docs.go | 466 +++++++++++++++++++++++ cmd/docs/swagger.json | 439 ++++++++++++++++++++++ cmd/docs/swagger.yaml | 277 ++++++++++++++ cmd/serve.go | 39 +- go.mod | 43 ++- go.sum | 65 ++++ internal/endpoints/datastores.go | 26 +- internal/endpoints/endpoint.go | 8 +- internal/endpoints/hosts.go | 26 +- internal/endpoints/status.go | 14 +- internal/endpoints/vms.go | 62 ++- 14 files changed, 2102 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 api.md create mode 100644 cmd/docs/docs.go create mode 100644 cmd/docs/swagger.json create mode 100644 cmd/docs/swagger.yaml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..31a2528 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,42 @@ +name: "Update docs" + +on: + push: + tags-ignore: + - '*' + branches-ignore: + - main +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.21 + + - name: Update Swagger + run: | + go install github.com/swaggo/swag/cmd/swag@latest + swag init -g ./cmd/serve.go -o cmd/docs + + - name: Update API.md + uses: addnab/docker-run-action@v3 + with: + image: quay.io/goswagger/swagger:latest + options: -v ${{ github.workspace }}:/api + run: | + cd /api + swagger generate markdown -f cmd/docs/swagger.json --output api.md + + - name: Add & Commit + uses: EndBug/add-and-commit@v9.1.3 + with: + add: '["cmd/docs", "api.md"]' + author_name: "DO! DevOps bot" + author_email: "info@dodevops.io" + message: "docs: Automatic docs update" + push: true diff --git a/README.md b/README.md index b114f30..bfa481b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Start the server by running go run cmd/serve.go +# Configuration + The following environment variables are used for configuration: * BASE_URL (required): The base URL of the vCenter to connect to like https://vcenter.company.com @@ -15,23 +17,10 @@ The following environment variables are used for configuration: * LOG_LEVEL: Maximum log level to use (see (https://pkg.go.dev/github.com/sirupsen/logrus#readme-level-logging)) [INFO] * TLS_INSECURE_SKIP_VERIFY: If set, will disable TLS verification for the API client * VCENTER_PROXY_URL: Connect to the vCenter using this proxy +* EXTERNAL_BASE_URL: Base URL the service is hosted on. Will be used for the Swagger API docs # APIs -## /vms - -### GET - -Return all VM names and their IDs - -## /vms/:vm/tags - -### GET - -Return all assigned tags and their categories for the specified vm `:vm`. - -## /vms/:vm/fqdn - -### GET +The service includes a generated OpenAPI documentation available at `/swagger`. -Return the fqdn of the specified vm `:vm` from the VMware guest tools \ No newline at end of file +See [the generated API documentation](api.md) \ No newline at end of file diff --git a/api.md b/api.md new file mode 100644 index 0000000..4359533 --- /dev/null +++ b/api.md @@ -0,0 +1,624 @@ + + + +# vmware-rest-proxy + + +## Informations + +### Version + +0.1.0 + +### Contact + +DO!DevOps info@dodevops.io http://dodevops.io + +## Content negotiation + +### URI Schemes + * http + +### Consumes + * application/json + +### Produces + * application/json + +## Access control + +### Security Schemes + +#### BasicAuth + + + +> **Type**: basic + +## All endpoints + +### datastore + +| Method | URI | Name | Summary | +|---------|---------|--------|---------| +| GET | /datastores | [get datastores](#get-datastores) | Retrieve a list of datastores | + + + +### host + +| Method | URI | Name | Summary | +|---------|---------|--------|---------| +| GET | /hosts | [get hosts](#get-hosts) | Retrieve a list of ESXi hosts | + + + +### operations + +| Method | URI | Name | Summary | +|---------|---------|--------|---------| +| GET | /status | [get status](#get-status) | Checks whether the service is running | + + + +### vm + +| Method | URI | Name | Summary | +|---------|---------|--------|---------| +| GET | /vms | [get vms](#get-vms) | Retrieve a list of all vms | +| GET | /vms/{id}/fqdn | [get vms ID fqdn](#get-vms-id-fqdn) | Get fqdn of VM | +| GET | /vms/{id}/info | [get vms ID info](#get-vms-id-info) | Get informational data about a VM | +| GET | /vms/{id}/tags | [get vms ID tags](#get-vms-id-tags) | Retrieve tags | + + + +## Paths + +### Retrieve a list of datastores (*GetDatastores*) + +``` +GET /datastores +``` + +Fetches a list of registered datastores in the vCenter + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-datastores-200) | OK | OK | | [schema](#get-datastores-200-schema) | +| [400](#get-datastores-400) | Bad Request | Invalid request | | [schema](#get-datastores-400-schema) | +| [401](#get-datastores-401) | Unauthorized | Authorization is required | | [schema](#get-datastores-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsDatastores](#endpoints-datastores) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +### Retrieve a list of ESXi hosts (*GetHosts*) + +``` +GET /hosts +``` + +Fetches a list of registered ESXi hosts in the vCenter + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-hosts-200) | OK | OK | | [schema](#get-hosts-200-schema) | +| [400](#get-hosts-400) | Bad Request | Invalid request | | [schema](#get-hosts-400-schema) | +| [401](#get-hosts-401) | Unauthorized | Authorization is required | | [schema](#get-hosts-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsHosts](#endpoints-hosts) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +### Checks whether the service is running (*GetStatus*) + +``` +GET /status +``` + +Just responses with a 200 to signal that the service is running + +#### Produces + * application/json + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-status-200) | OK | OK | | [schema](#get-status-200-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsStatus](#endpoints-status) + +### Retrieve a list of all vms (*GetVms*) + +``` +GET /vms +``` + +Fetches a list of vms from the vCenter + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-vms-200) | OK | OK | | [schema](#get-vms-200-schema) | +| [400](#get-vms-400) | Bad Request | Invalid request | | [schema](#get-vms-400-schema) | +| [401](#get-vms-401) | Unauthorized | Authorization is required | | [schema](#get-vms-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsVMS](#endpoints-vm-s) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +### Get fqdn of VM (*GetVmsIDFqdn*) + +``` +GET /vms/{id}/fqdn +``` + +Try to find out the fqdn of the given VM using the guest tools + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### Parameters + +| Name | Source | Type | Go type | Separator | Required | Default | Description | +|------|--------|------|---------|-----------| :------: |---------|-------------| +| id | `path` | string | `string` | | ✓ | | ID of VM | + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-vms-id-fqdn-200) | OK | OK | | [schema](#get-vms-id-fqdn-200-schema) | +| [400](#get-vms-id-fqdn-400) | Bad Request | Invalid request | | [schema](#get-vms-id-fqdn-400-schema) | +| [401](#get-vms-id-fqdn-401) | Unauthorized | Authorization is required | | [schema](#get-vms-id-fqdn-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsFQDN](#endpoints-f-q-d-n) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +### Get informational data about a VM (*GetVmsIDInfo*) + +``` +GET /vms/{id}/info +``` + +Find out some information about a VM and return them + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### Parameters + +| Name | Source | Type | Go type | Separator | Required | Default | Description | +|------|--------|------|---------|-----------| :------: |---------|-------------| +| id | `path` | string | `string` | | ✓ | | ID of VM | + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-vms-id-info-200) | OK | OK | | [schema](#get-vms-id-info-200-schema) | +| [400](#get-vms-id-info-400) | Bad Request | Invalid request | | [schema](#get-vms-id-info-400-schema) | +| [401](#get-vms-id-info-401) | Unauthorized | Authorization is required | | [schema](#get-vms-id-info-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[APIVMInfo](#api-vm-info) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +### Retrieve tags (*GetVmsIDTags*) + +``` +GET /vms/{id}/tags +``` + +Retrieve tags and their categories for a vm + +#### Produces + * application/json + +#### Security Requirements + * BasicAuth + +#### Parameters + +| Name | Source | Type | Go type | Separator | Required | Default | Description | +|------|--------|------|---------|-----------| :------: |---------|-------------| +| id | `path` | string | `string` | | ✓ | | ID of VM | + +#### All responses +| Code | Status | Description | Has headers | Schema | +|------|--------|-------------|:-----------:|--------| +| [200](#get-vms-id-tags-200) | OK | OK | | [schema](#get-vms-id-tags-200-schema) | +| [400](#get-vms-id-tags-400) | Bad Request | Invalid request | | [schema](#get-vms-id-tags-400-schema) | +| [401](#get-vms-id-tags-401) | Unauthorized | Authorization is required | | [schema](#get-vms-id-tags-401-schema) | + +#### Responses + + +##### 200 - OK +Status: OK + +###### Schema + + + +[EndpointsTags](#endpoints-tags) + +##### 400 - Invalid request +Status: Bad Request + +###### Schema + +##### 401 - Authorization is required +Status: Unauthorized + +###### Schema + +## Models + +### api.Datastore + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| capacity | integer| `int64` | | | | | +| datastore | string| `string` | | | | | +| free_space | integer| `int64` | | | | | +| name | string| `string` | | | | | +| type | string| `string` | | | | | + + + +### api.Host + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| connection_state | string| `string` | | | | | +| host | string| `string` | | | | | +| name | string| `string` | | | | | +| power_state | string| `string` | | | | | + + + +### api.VM + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| name | string| `string` | | | | | +| power_state | string| `string` | | | | | +| vm | string| `string` | | | | | + + + +### api.VMInfo + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| cpu_cores | integer| `int64` | | | | | +| name | string| `string` | | | | | +| provisioned_ram | integer| `int64` | | | | | +| provisioned_storage | integer| `int64` | | | | | +| used_storage | integer| `int64` | | | | | + + + +### api.VMTag + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| category | string| `string` | | | Category holds the tag category | | +| value | string| `string` | | | Value holds the value of the tag | | + + + +### endpoints.Datastores + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| datastores | [EndpointsDatastoresResult](#endpoints-datastores-result)| `EndpointsDatastoresResult` | | | | | + + + +### endpoints.DatastoresResult + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| count | integer| `int64` | | | | | +| datastores | [][APIDatastore](#api-datastore)| `[]*APIDatastore` | | | | | + + + +### endpoints.FQDN + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| fqdn | string| `string` | | | | | + + + +### endpoints.Hosts + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| hosts | [EndpointsHostsResult](#endpoints-hosts-result)| `EndpointsHostsResult` | | | | | + + + +### endpoints.HostsResult + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| count | integer| `int64` | | | | | +| hosts | [][APIHost](#api-host)| `[]*APIHost` | | | | | + + + +### endpoints.Status + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| status | string| `string` | | | | | + + + +### endpoints.Tags + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| tags | [EndpointsTagsResult](#endpoints-tags-result)| `EndpointsTagsResult` | | | | | + + + +### endpoints.TagsResult + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| count | integer| `int64` | | | | | +| tags | [][APIVMTag](#api-vm-tag)| `[]*APIVMTag` | | | | | + + + +### endpoints.VMS + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| vms | [EndpointsVMSResult](#endpoints-vm-s-result)| `EndpointsVMSResult` | | | | | + + + +### endpoints.VMSResult + + + + + + +**Properties** + +| Name | Type | Go type | Required | Default | Description | Example | +|------|------|---------|:--------:| ------- |-------------|---------| +| count | integer| `int64` | | | | | +| vms | [][APIVM](#api-vm)| `[]*APIVM` | | | | | + + diff --git a/cmd/docs/docs.go b/cmd/docs/docs.go new file mode 100644 index 0000000..2974152 --- /dev/null +++ b/cmd/docs/docs.go @@ -0,0 +1,466 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "DO!DevOps", + "url": "http://dodevops.io", + "email": "info@dodevops.io" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/datastores": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of registered datastores in the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "datastore" + ], + "summary": "Retrieve a list of datastores", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Datastores" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/hosts": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of registered ESXi hosts in the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "host" + ], + "summary": "Retrieve a list of ESXi hosts", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Hosts" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/status": { + "get": { + "description": "Just responses with a 200 to signal that the service is running", + "produces": [ + "application/json" + ], + "summary": "Checks whether the service is running", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Status" + } + } + } + } + }, + "/vms": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of vms from the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Retrieve a list of all vms", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.VMS" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/fqdn": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Try to find out the fqdn of the given VM using the guest tools", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Get fqdn of VM", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.FQDN" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/info": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Find out some information about a VM and return them", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Get informational data about a VM", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.VMInfo" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/tags": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Retrieve tags and their categories for a vm", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Retrieve tags", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Tags" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + } + }, + "definitions": { + "api.Datastore": { + "type": "object", + "properties": { + "capacity": { + "type": "integer" + }, + "datastore": { + "type": "string" + }, + "free_space": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "api.Host": { + "type": "object", + "properties": { + "connection_state": { + "type": "string" + }, + "host": { + "type": "string" + }, + "name": { + "type": "string" + }, + "power_state": { + "type": "string" + } + } + }, + "api.VM": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "power_state": { + "type": "string" + }, + "vm": { + "type": "string" + } + } + }, + "api.VMInfo": { + "type": "object", + "properties": { + "cpu_cores": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "provisioned_ram": { + "type": "integer" + }, + "provisioned_storage": { + "type": "integer" + }, + "used_storage": { + "type": "integer" + } + } + }, + "api.VMTag": { + "type": "object", + "properties": { + "category": { + "description": "Category holds the tag category", + "type": "string" + }, + "value": { + "description": "Value holds the value of the tag", + "type": "string" + } + } + }, + "endpoints.Datastores": { + "type": "object", + "properties": { + "datastores": { + "$ref": "#/definitions/endpoints.DatastoresResult" + } + } + }, + "endpoints.DatastoresResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "datastores": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Datastore" + } + } + } + }, + "endpoints.FQDN": { + "type": "object", + "properties": { + "fqdn": { + "type": "string" + } + } + }, + "endpoints.Hosts": { + "type": "object", + "properties": { + "hosts": { + "$ref": "#/definitions/endpoints.HostsResult" + } + } + }, + "endpoints.HostsResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Host" + } + } + } + }, + "endpoints.Status": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + }, + "endpoints.Tags": { + "type": "object", + "properties": { + "tags": { + "$ref": "#/definitions/endpoints.TagsResult" + } + } + }, + "endpoints.TagsResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/api.VMTag" + } + } + } + }, + "endpoints.VMS": { + "type": "object", + "properties": { + "vms": { + "$ref": "#/definitions/endpoints.VMSResult" + } + } + }, + "endpoints.VMSResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "vms": { + "type": "array", + "items": { + "$ref": "#/definitions/api.VM" + } + } + } + } + }, + "securityDefinitions": { + "BasicAuth": { + "type": "basic" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "0.1.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "vmware-rest-proxy", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/cmd/docs/swagger.json b/cmd/docs/swagger.json new file mode 100644 index 0000000..a660f52 --- /dev/null +++ b/cmd/docs/swagger.json @@ -0,0 +1,439 @@ +{ + "swagger": "2.0", + "info": { + "title": "vmware-rest-proxy", + "contact": { + "name": "DO!DevOps", + "url": "http://dodevops.io", + "email": "info@dodevops.io" + }, + "version": "0.1.0" + }, + "paths": { + "/datastores": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of registered datastores in the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "datastore" + ], + "summary": "Retrieve a list of datastores", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Datastores" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/hosts": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of registered ESXi hosts in the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "host" + ], + "summary": "Retrieve a list of ESXi hosts", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Hosts" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/status": { + "get": { + "description": "Just responses with a 200 to signal that the service is running", + "produces": [ + "application/json" + ], + "summary": "Checks whether the service is running", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Status" + } + } + } + } + }, + "/vms": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Fetches a list of vms from the vCenter", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Retrieve a list of all vms", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.VMS" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/fqdn": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Try to find out the fqdn of the given VM using the guest tools", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Get fqdn of VM", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.FQDN" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/info": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Find out some information about a VM and return them", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Get informational data about a VM", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.VMInfo" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + }, + "/vms/{id}/tags": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "description": "Retrieve tags and their categories for a vm", + "produces": [ + "application/json" + ], + "tags": [ + "vm" + ], + "summary": "Retrieve tags", + "parameters": [ + { + "type": "string", + "description": "ID of VM", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/endpoints.Tags" + } + }, + "400": { + "description": "Invalid request" + }, + "401": { + "description": "Authorization is required" + } + } + } + } + }, + "definitions": { + "api.Datastore": { + "type": "object", + "properties": { + "capacity": { + "type": "integer" + }, + "datastore": { + "type": "string" + }, + "free_space": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "api.Host": { + "type": "object", + "properties": { + "connection_state": { + "type": "string" + }, + "host": { + "type": "string" + }, + "name": { + "type": "string" + }, + "power_state": { + "type": "string" + } + } + }, + "api.VM": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "power_state": { + "type": "string" + }, + "vm": { + "type": "string" + } + } + }, + "api.VMInfo": { + "type": "object", + "properties": { + "cpu_cores": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "provisioned_ram": { + "type": "integer" + }, + "provisioned_storage": { + "type": "integer" + }, + "used_storage": { + "type": "integer" + } + } + }, + "api.VMTag": { + "type": "object", + "properties": { + "category": { + "description": "Category holds the tag category", + "type": "string" + }, + "value": { + "description": "Value holds the value of the tag", + "type": "string" + } + } + }, + "endpoints.Datastores": { + "type": "object", + "properties": { + "datastores": { + "$ref": "#/definitions/endpoints.DatastoresResult" + } + } + }, + "endpoints.DatastoresResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "datastores": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Datastore" + } + } + } + }, + "endpoints.FQDN": { + "type": "object", + "properties": { + "fqdn": { + "type": "string" + } + } + }, + "endpoints.Hosts": { + "type": "object", + "properties": { + "hosts": { + "$ref": "#/definitions/endpoints.HostsResult" + } + } + }, + "endpoints.HostsResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "hosts": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Host" + } + } + } + }, + "endpoints.Status": { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + }, + "endpoints.Tags": { + "type": "object", + "properties": { + "tags": { + "$ref": "#/definitions/endpoints.TagsResult" + } + } + }, + "endpoints.TagsResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/api.VMTag" + } + } + } + }, + "endpoints.VMS": { + "type": "object", + "properties": { + "vms": { + "$ref": "#/definitions/endpoints.VMSResult" + } + } + }, + "endpoints.VMSResult": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "vms": { + "type": "array", + "items": { + "$ref": "#/definitions/api.VM" + } + } + } + } + }, + "securityDefinitions": { + "BasicAuth": { + "type": "basic" + } + } +} \ No newline at end of file diff --git a/cmd/docs/swagger.yaml b/cmd/docs/swagger.yaml new file mode 100644 index 0000000..23ac39e --- /dev/null +++ b/cmd/docs/swagger.yaml @@ -0,0 +1,277 @@ +definitions: + api.Datastore: + properties: + capacity: + type: integer + datastore: + type: string + free_space: + type: integer + name: + type: string + type: + type: string + type: object + api.Host: + properties: + connection_state: + type: string + host: + type: string + name: + type: string + power_state: + type: string + type: object + api.VM: + properties: + name: + type: string + power_state: + type: string + vm: + type: string + type: object + api.VMInfo: + properties: + cpu_cores: + type: integer + name: + type: string + provisioned_ram: + type: integer + provisioned_storage: + type: integer + used_storage: + type: integer + type: object + api.VMTag: + properties: + category: + description: Category holds the tag category + type: string + value: + description: Value holds the value of the tag + type: string + type: object + endpoints.Datastores: + properties: + datastores: + $ref: '#/definitions/endpoints.DatastoresResult' + type: object + endpoints.DatastoresResult: + properties: + count: + type: integer + datastores: + items: + $ref: '#/definitions/api.Datastore' + type: array + type: object + endpoints.FQDN: + properties: + fqdn: + type: string + type: object + endpoints.Hosts: + properties: + hosts: + $ref: '#/definitions/endpoints.HostsResult' + type: object + endpoints.HostsResult: + properties: + count: + type: integer + hosts: + items: + $ref: '#/definitions/api.Host' + type: array + type: object + endpoints.Status: + properties: + status: + type: string + type: object + endpoints.Tags: + properties: + tags: + $ref: '#/definitions/endpoints.TagsResult' + type: object + endpoints.TagsResult: + properties: + count: + type: integer + tags: + items: + $ref: '#/definitions/api.VMTag' + type: array + type: object + endpoints.VMS: + properties: + vms: + $ref: '#/definitions/endpoints.VMSResult' + type: object + endpoints.VMSResult: + properties: + count: + type: integer + vms: + items: + $ref: '#/definitions/api.VM' + type: array + type: object +info: + contact: + email: info@dodevops.io + name: DO!DevOps + url: http://dodevops.io + title: vmware-rest-proxy + version: 0.1.0 +paths: + /datastores: + get: + description: Fetches a list of registered datastores in the vCenter + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.Datastores' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Retrieve a list of datastores + tags: + - datastore + /hosts: + get: + description: Fetches a list of registered ESXi hosts in the vCenter + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.Hosts' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Retrieve a list of ESXi hosts + tags: + - host + /status: + get: + description: Just responses with a 200 to signal that the service is running + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.Status' + summary: Checks whether the service is running + /vms: + get: + description: Fetches a list of vms from the vCenter + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.VMS' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Retrieve a list of all vms + tags: + - vm + /vms/{id}/fqdn: + get: + description: Try to find out the fqdn of the given VM using the guest tools + parameters: + - description: ID of VM + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.FQDN' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Get fqdn of VM + tags: + - vm + /vms/{id}/info: + get: + description: Find out some information about a VM and return them + parameters: + - description: ID of VM + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.VMInfo' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Get informational data about a VM + tags: + - vm + /vms/{id}/tags: + get: + description: Retrieve tags and their categories for a vm + parameters: + - description: ID of VM + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/endpoints.Tags' + "400": + description: Invalid request + "401": + description: Authorization is required + security: + - BasicAuth: [] + summary: Retrieve tags + tags: + - vm +securityDefinitions: + BasicAuth: + type: basic +swagger: "2.0" diff --git a/cmd/serve.go b/cmd/serve.go index 10f509b..e731f77 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -2,17 +2,29 @@ package main import ( "crypto/tls" + "fmt" "github.com/gin-gonic/gin" "github.com/go-resty/resty/v2" "github.com/sirupsen/logrus" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" "log" + "net/http" + "net/url" "os" + "vmware-rest-proxy/cmd/docs" api2 "vmware-rest-proxy/internal/api" "vmware-rest-proxy/internal/endpoints" ) // REST server that proxies request through to a vCenter web service making it easier to request certain details. - +// @title vmware-rest-proxy +// @version 0.1.0 +// @contact.name DO!DevOps +// @contact.url http://dodevops.io +// @contact.email info@dodevops.io +// +// @securityDefinitions.basic BasicAuth func main() { r := resty.New() @@ -53,6 +65,16 @@ func main() { r.SetProxy(p) } + externalBaseUrl, _ := url.Parse("http://localhost:8080") + if p, found := os.LookupEnv("EXTERNAL_BASE_URL"); found && p != "" { + logrus.Debug("Setting external base URL") + if b, err := url.Parse(p); err != nil { + log.Fatalf("Can not parse external base url %s: %s", p, err) + } else { + externalBaseUrl = b + } + } + logrus.Debug("Starting server") gin.SetMode(gin.ReleaseMode) @@ -62,8 +84,21 @@ func main() { log.Fatalf("Error disabling trusted proxies: %s", err) } api := api2.DefaultVSphereProxyApi{Resty: r} - for _, endpoint := range []endpoints.Endpoint{&endpoints.VMSEndpoint{API: api}, &endpoints.StatusEndpoint{}} { + for _, endpoint := range []endpoints.Endpoint{&endpoints.VMSEndpoint{API: api}, &endpoints.HostsEndpoint{API: api}, &endpoints.StatusEndpoint{}, &endpoints.DataStoreEndpoint{API: api}} { endpoint.Register(s) } + docs.SwaggerInfo.Title = "vmware-rest-proxy" + docs.SwaggerInfo.Description = fmt.Sprintf("This is the API of the vmware-rest-proxy pointing at %s", r.BaseURL) + docs.SwaggerInfo.Version = "1.0" + docs.SwaggerInfo.BasePath = "/" + docs.SwaggerInfo.Host = externalBaseUrl.Host + docs.SwaggerInfo.Schemes = []string{externalBaseUrl.Scheme} + s.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + s.GET("/", func(context *gin.Context) { + context.Redirect(http.StatusMovedPermanently, "/swagger/index.html") + }) + s.GET("/swagger", func(context *gin.Context) { + context.Redirect(http.StatusMovedPermanently, "/swagger/index.html") + }) _ = s.Run(bindAddress) } diff --git a/go.mod b/go.mod index 9f41dd4..f6932ab 100644 --- a/go.mod +++ b/go.mod @@ -11,29 +11,44 @@ require ( ) require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.2.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/bytedance/sonic v1.10.2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/spec v0.20.13 // indirect + github.com/go-openapi/swag v0.22.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect + github.com/swaggo/swag v1.16.2 // indirect github.com/thoas/go-funk v0.9.3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.6.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.16.1 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 827740f..a7ceb18 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,23 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= +github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= +github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -11,10 +25,20 @@ github.com/dodevops/golang-handlerinspector v0.1.0 h1:iPSaw9izmNSvoVGUn3btGbpjXz github.com/dodevops/golang-handlerinspector v0.1.0/go.mod h1:0oVA3heviGeSZQ1eqt/yjcouhP3B95g/2l732lK48r4= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/spec v0.20.13 h1:XJDIN+dLH6vqXgafnl5SUIMnzaChQ6QTo0/UPMbkIaE= +github.com/go-openapi/spec v0.20.13/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= +github.com/go-openapi/swag v0.22.6 h1:dnqg1XfHXL9aBxSbktBqFR5CxVyVI+7fYWhAf1JOeTw= +github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -23,6 +47,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= +github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-resty/resty/v2 v2.10.0 h1:Qla4W/+TMmv0fOeeRqzEpXPLfTUnR5HZ1+lGs+CkiCo= github.com/go-resty/resty/v2 v2.10.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -31,15 +57,25 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -47,6 +83,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -63,29 +101,45 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= +golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -101,6 +155,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -113,22 +169,31 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/endpoints/datastores.go b/internal/endpoints/datastores.go index 2c43531..a8bb803 100644 --- a/internal/endpoints/datastores.go +++ b/internal/endpoints/datastores.go @@ -14,6 +14,24 @@ func (d DataStoreEndpoint) Register(engine *gin.Engine) { engine.GET("/datastores", d.getDatastores) } +type DatastoresResult struct { + Count int `json:"count"` + Datastores []api.Datastore `json:"datastores"` +} + +type Datastores struct { + Datastores DatastoresResult `json:"datastores"` +} + +// @Summary Retrieve a list of datastores +// @Description Fetches a list of registered datastores in the vCenter +// @Tags datastore +// @Produce json +// @Security BasicAuth +// @Success 200 {object} Datastores +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /datastores [get] func (d DataStoreEndpoint) getDatastores(context *gin.Context) { if r, ok := HandleRequest(context); ok { if datastores, err := d.API.GetDatastores(r.Username, r.Password); err != nil { @@ -21,10 +39,10 @@ func (d DataStoreEndpoint) getDatastores(context *gin.Context) { "error": fmt.Sprintf("Error getting datastores: %s", err), }) } else { - context.JSON(200, gin.H{ - "datastores": gin.H{ - "count": len(datastores), - "datastores": datastores, + context.JSON(200, Datastores{ + Datastores: DatastoresResult{ + Count: len(datastores), + Datastores: datastores, }, }) } diff --git a/internal/endpoints/endpoint.go b/internal/endpoints/endpoint.go index c5dd334..238fe18 100644 --- a/internal/endpoints/endpoint.go +++ b/internal/endpoints/endpoint.go @@ -24,10 +24,8 @@ type RequestData struct { Password string } -/* -HandleRequest manages incoming requests and extracts authorization data and optionally fails them if no authorization -is present. -*/ +// HandleRequest manages incoming requests and extracts authorization data and optionally fails them if no authorization +// is present. func HandleRequest(context *gin.Context) (RequestData, bool) { if u, p, err := getAuthData(context.GetHeader("Authorization")); err != nil { var missingAuthenticationHeaderError internal.MissingAuthorizationHeaderError @@ -36,7 +34,7 @@ func HandleRequest(context *gin.Context) (RequestData, bool) { "error": "Missing authentication header", }) } else { - context.AbortWithStatusJSON(403, gin.H{ + context.AbortWithStatusJSON(400, gin.H{ "error": fmt.Sprintf("Error getting Authorization header: %s", err), }) } diff --git a/internal/endpoints/hosts.go b/internal/endpoints/hosts.go index 59a5e52..6248220 100644 --- a/internal/endpoints/hosts.go +++ b/internal/endpoints/hosts.go @@ -14,6 +14,24 @@ func (H HostsEndpoint) Register(engine *gin.Engine) { engine.GET("/hosts", H.getHosts) } +type HostsResult struct { + Count int `json:"count"` + Hosts []api.Host `json:"hosts"` +} + +type Hosts struct { + Hosts HostsResult `json:"hosts"` +} + +// @Summary Retrieve a list of ESXi hosts +// @Description Fetches a list of registered ESXi hosts in the vCenter +// @Tags host +// @Produce json +// @Security BasicAuth +// @Success 200 {object} Hosts +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /hosts [get] func (H HostsEndpoint) getHosts(context *gin.Context) { if r, ok := HandleRequest(context); ok { if hosts, err := H.API.GetHosts(r.Username, r.Password); err != nil { @@ -22,10 +40,10 @@ func (H HostsEndpoint) getHosts(context *gin.Context) { }) } else { context.JSON(200, gin.H{ - "hosts": gin.H{ - "count": len(hosts), - "hosts": hosts, - }, + "hosts": Hosts{Hosts: HostsResult{ + Count: len(hosts), + Hosts: hosts, + }}, }) } } diff --git a/internal/endpoints/status.go b/internal/endpoints/status.go index 0bef567..4ad8c3f 100644 --- a/internal/endpoints/status.go +++ b/internal/endpoints/status.go @@ -9,10 +9,18 @@ type StatusEndpoint struct{} var _ Endpoint = &StatusEndpoint{} +type Status struct { + Status string `json:"status"` +} + +// Register registers the status endpoint +// @Summary Checks whether the service is running +// @Description Just responses with a 200 to signal that the service is running +// @Produce json +// @Success 200 {object} Status +// @Router /status [get] func (StatusEndpoint) Register(engine *gin.Engine) { engine.GET("/status", func(context *gin.Context) { - context.JSON(200, gin.H{ - "status": "running", - }) + context.JSON(200, Status{Status: "running"}) }) } diff --git a/internal/endpoints/vms.go b/internal/endpoints/vms.go index 31f094d..708a274 100644 --- a/internal/endpoints/vms.go +++ b/internal/endpoints/vms.go @@ -25,7 +25,23 @@ func (V *VMSEndpoint) Register(engine *gin.Engine) { engine.GET("/vms/:vm/info", V.getVMInfo) } -// getVMS exposes all VMS of the vCenter at /VMS +type VMSResult struct { + Count int `json:"count"` + VMS []api.VM `json:"vms"` +} +type VMS struct { + VMS VMSResult `json:"vms"` +} + +// @Summary Retrieve a list of all vms +// @Description Fetches a list of vms from the vCenter +// @Tags vm +// @Produce json +// @Security BasicAuth +// @Success 200 {object} VMS +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /vms [get] func (V *VMSEndpoint) getVMS(context *gin.Context) { if r, ok := HandleRequest(context); ok { if vms, err := V.API.GetVMs(r.Username, r.Password); err != nil { @@ -43,7 +59,25 @@ func (V *VMSEndpoint) getVMS(context *gin.Context) { } } -// getVMTags exposes a list of tags associated with a vm at /VMS/:vm/tags +type TagsResult struct { + Count int `json:"count"` + Tags []api.VMTag `json:"tags"` +} + +type Tags struct { + Tags TagsResult `json:"tags"` +} + +// @Summary Retrieve tags +// @Description Retrieve tags and their categories for a vm +// @Param id path string true "ID of VM" +// @Tags vm +// @Produce json +// @Security BasicAuth +// @Success 200 {object} Tags +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /vms/{id}/tags [get] func (V *VMSEndpoint) getVMTags(context *gin.Context) { if r, ok := HandleRequest(context); ok { var vm VMBinding @@ -68,6 +102,20 @@ func (V *VMSEndpoint) getVMTags(context *gin.Context) { } } +type FQDN struct { + FQDN string `json:"fqdn"` +} + +// @Summary Get fqdn of VM +// @Description Try to find out the fqdn of the given VM using the guest tools +// @Param id path string true "ID of VM" +// @Tags vm +// @Produce json +// @Security BasicAuth +// @Success 200 {object} FQDN +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /vms/{id}/fqdn [get] func (V *VMSEndpoint) getFQDN(context *gin.Context) { if r, ok := HandleRequest(context); ok { var vm VMBinding @@ -89,6 +137,16 @@ func (V *VMSEndpoint) getFQDN(context *gin.Context) { } } +// @Summary Get informational data about a VM +// @Description Find out some information about a VM and return them +// @Param id path string true "ID of VM" +// @Tags vm +// @Produce json +// @Security BasicAuth +// @Success 200 {object} api.VMInfo +// @Failure 401 "Authorization is required" +// @Failure 400 "Invalid request" +// @Router /vms/{id}/info [get] func (V *VMSEndpoint) getVMInfo(context *gin.Context) { if r, ok := HandleRequest(context); ok { var vm VMBinding