From b51e27a5f0deac0ec4b54d14785503c4229134e7 Mon Sep 17 00:00:00 2001 From: Robert Hoppe Date: Mon, 8 Jul 2024 15:34:09 +0200 Subject: [PATCH] Introduce ServiceEnablement (#215) Co-authored-by: Robert Hoppe --- .../service-enablement/v1.0/config.yaml | 27 + .../service-enablement/v1.0/generate.go | 3 + .../v1.0/service-enablement.json | 393 ++++++++++ pkg/services/service-enablement/v1/service.go | 15 + .../v1/serviceenablement.go | 717 ++++++++++++++++++ pkg/services/service-enablement/v1/wait.go | 34 + pkg/services/services.go | 3 + 7 files changed, 1192 insertions(+) create mode 100644 internal/config/service-enablement/v1.0/config.yaml create mode 100644 internal/config/service-enablement/v1.0/generate.go create mode 100644 internal/config/service-enablement/v1.0/service-enablement.json create mode 100644 pkg/services/service-enablement/v1/service.go create mode 100644 pkg/services/service-enablement/v1/serviceenablement.go create mode 100644 pkg/services/service-enablement/v1/wait.go diff --git a/internal/config/service-enablement/v1.0/config.yaml b/internal/config/service-enablement/v1.0/config.yaml new file mode 100644 index 0000000..7f5bd4c --- /dev/null +++ b/internal/config/service-enablement/v1.0/config.yaml @@ -0,0 +1,27 @@ +package: serviceenablement +output: ../../../../pkg/services/service-enablement/v1/serviceenablement.go +generate: + models: true + client: true +output-options: + custom-doer: + enabled: true + import: contracts "github.com/SchwarzIT/community-stackit-go-client/pkg/contracts" + name: "contracts.BaseClientInterface" + split-by-tags: + verbose: false + enabled: true +tidy: + verbose: true + functions: + - replace: Id + with: ID + all: true + params: + - replace: Id + with: ID + all: true + schemas: + - replace: Id + with: ID + all: true diff --git a/internal/config/service-enablement/v1.0/generate.go b/internal/config/service-enablement/v1.0/generate.go new file mode 100644 index 0000000..3293c1a --- /dev/null +++ b/internal/config/service-enablement/v1.0/generate.go @@ -0,0 +1,3 @@ +package gen + +//go:generate go run github.com/do87/stackit-client-generator/cmd/oapi-codegen@v0.0.2 -config config.yaml service-enablement.json diff --git a/internal/config/service-enablement/v1.0/service-enablement.json b/internal/config/service-enablement/v1.0/service-enablement.json new file mode 100644 index 0000000..15639aa --- /dev/null +++ b/internal/config/service-enablement/v1.0/service-enablement.json @@ -0,0 +1,393 @@ +{ + "components": { + "schemas": { + "ActionError": { + "description": "the last error for this service.", + "properties": { + "action": { + "description": "the last action which was triggered on this service", + "enum": [ + "DISABLE", + "ENABLE" + ], + "example": "DISABLE", + "type": "string" + }, + "code": { + "description": "the error code if provided by the service", + "example": "ABC-01", + "type": "string" + }, + "reason": { + "description": "the error reason provided by the service", + "example": "something went wrong", + "type": "string" + } + }, + "type": "object" + }, + "Dependencies": { + "properties": { + "hard": { + "description": "a list of service IDs which this service depend on. If the service is enabled, those service are enabled as well automatically.", + "items": { + "$ref": "#/components/schemas/ServiceId" + }, + "type": "array" + }, + "soft": { + "description": "a list of service IDs which this service depend on. When they are disabled a notification is sent.", + "items": { + "$ref": "#/components/schemas/ServiceId" + }, + "type": "array" + } + }, + "type": "object" + }, + "Parameters": { + "additionalProperties": { + "additionalProperties": { + "maxLength": 255, + "type": "string" + }, + "example": { + "param1": "value1", + "param2": "value2" + }, + "type": "object" + }, + "description": "service parameters", + "example": { + "cloud.stackit.my-service": { + "param1": "value1", + "param2": "value2" + }, + "general": { + "organizationId": "39fb3ac9-c5af-46a6-91d5-a2455047630f", + "projectName": "my new project name", + "projectScope": "PUBLIC" + } + }, + "properties": { + "general": { + "properties": { + "organizationId": { + "example": "39fb3ac9-c5af-46a6-91d5-a2455047630f", + "type": "string" + }, + "projectName": { + "type": "string" + }, + "projectScope": { + "default": "PUBLIC", + "enum": [ + "SCHWARZ", + "PUBLIC" + ], + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ProjectCloudService": { + "properties": { + "dependencies": { + "$ref": "#/components/schemas/Dependencies" + }, + "enablement": { + "default": "REQUEST", + "enum": [ + "REQUEST", + "AUTO" + ], + "type": "string" + }, + "error": { + "$ref": "#/components/schemas/ActionError" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "example": { + "category": "database" + }, + "type": "object" + }, + "lifecycle": { + "default": "FLEX", + "enum": [ + "FLEX", + "PROJECT" + ], + "type": "string" + }, + "parameters": { + "$ref": "#/components/schemas/Parameters" + }, + "scope": { + "default": "PUBLIC", + "enum": [ + "PRIVATE", + "PUBLIC" + ], + "type": "string" + }, + "serviceId": { + "$ref": "#/components/schemas/ServiceId" + }, + "state": { + "default": "ENABLED", + "description": "the state of a service within a project", + "enum": [ + "ENABLED", + "ENABLING", + "DISABLED", + "DISABLING" + ], + "type": "string" + } + }, + "type": "object", + "x-stackit-sdk": { + "schema-name": "ServiceStatus" + } + }, + "ServiceId": { + "description": "the id of the service", + "example": "cloud.stackit.my-service", + "maxLength": 255, + "minLength": 10, + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{1,254}$", + "type": "string" + } + } + }, + "info": { + "description": "STACKIT Service Enablement API", + "title": "STACKIT Service Enablement API", + "version": "1.1" + }, + "openapi": "3.0.3", + "paths": { + "/v1/projects/{projectId}/services": { + "get": { + "description": "returns a list of all available services for a project.", + "operationId": "listServices", + "parameters": [ + { + "in": "query", + "name": "cursor", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/ProjectCloudService" + }, + "type": "array" + }, + "nextCursor": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "OK" + } + }, + "tags": [ + "Public" + ], + "x-stackit-authorization": { + "actions": [ + "service-enablement.service-state.get" + ], + "resource-id": "projectId", + "resource-id-type": "dynamic", + "resource-type": "project" + }, + "x-stackit-sdk": { + "include": true, + "method-name": "ListServiceStatus" + }, + "x-viewer-permissions": { + "actions": [ + "service-enablement.service-state.get" + ], + "implicit-actions": null + } + }, + "parameters": [ + { + "in": "path", + "name": "projectId", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "/v1/projects/{projectId}/services/{serviceId}": { + "delete": { + "description": "disables the service in a project.", + "operationId": "disableService", + "responses": { + "202": { + "description": "Accepted" + }, + "404": { + "description": "service not found" + } + }, + "tags": [ + "Public" + ], + "x-stackit-authorization": { + "actions": [ + "service-enablement.service-state.edit" + ], + "resource-id": "projectId", + "resource-id-type": "dynamic", + "resource-type": "project" + }, + "x-stackit-sdk": { + "include": true, + "method-name": "DisableService" + }, + "x-viewer-permissions": { + "actions": [ + "service-enablement.service-state.edit" + ], + "implicit-actions": null + } + }, + "get": { + "description": "returns the current status of a service in a project.", + "operationId": "getService", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectCloudService" + } + } + }, + "description": "OK" + }, + "404": { + "description": "service not found" + } + }, + "tags": [ + "Public" + ], + "x-stackit-authorization": { + "actions": [ + "service-enablement.service-state.get" + ], + "resource-id": "projectId", + "resource-id-type": "dynamic", + "resource-type": "project" + }, + "x-stackit-sdk": { + "include": true, + "method-name": "GetServiceStatus" + }, + "x-viewer-permissions": { + "actions": [ + "service-enablement.service-state.get" + ], + "implicit-actions": null + } + }, + "parameters": [ + { + "in": "path", + "name": "projectId", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "serviceId", + "required": true, + "schema": { + "type": "string" + } + } + ], + "post": { + "description": "enables the service in a project.", + "operationId": "enableService", + "responses": { + "202": { + "description": "Accepted" + }, + "404": { + "description": "service not found" + } + }, + "tags": [ + "Public" + ], + "x-stackit-authorization": { + "actions": [ + "service-enablement.service-state.edit" + ], + "resource-id": "projectId", + "resource-id-type": "dynamic", + "resource-type": "project" + }, + "x-stackit-sdk": { + "include": true, + "method-name": "EnableService" + }, + "x-viewer-permissions": { + "actions": [ + "service-enablement.service-state.edit" + ], + "implicit-actions": null + } + } + } + }, + "tags": [ + { + "name": "Public" + } + ], + "servers": [ + { + "description": "STACKIT Service Enablement API", + "url": "https://service-enablement.api.eu01.stackit.cloud" + } + ], + "x-stackit-api": { + "type": "stackit" + }, + "x-stackit-portal": { + "cors": true + }, + "x-stackit-scope": { + "visibility": "public" + } +} \ No newline at end of file diff --git a/pkg/services/service-enablement/v1/service.go b/pkg/services/service-enablement/v1/service.go new file mode 100644 index 0000000..a6f7940 --- /dev/null +++ b/pkg/services/service-enablement/v1/service.go @@ -0,0 +1,15 @@ +package serviceenablement + +import ( + "github.com/SchwarzIT/community-stackit-go-client/pkg/baseurl" + "github.com/SchwarzIT/community-stackit-go-client/pkg/contracts" +) + +var BaseURLs = baseurl.New( + "kubernetes", + "https://service-enablement.api.eu01.stackit.cloud/", +) + +func NewService(c contracts.BaseClientInterface) *ClientWithResponses { + return NewClient(BaseURLs.Get(), c) +} diff --git a/pkg/services/service-enablement/v1/serviceenablement.go b/pkg/services/service-enablement/v1/serviceenablement.go new file mode 100644 index 0000000..1e14890 --- /dev/null +++ b/pkg/services/service-enablement/v1/serviceenablement.go @@ -0,0 +1,717 @@ +// Package serviceenablement provides primitives to interact with the openapi HTTP API. +// +// Code generated by github.com/do87/stackit-client-generator version v0.0.2 DO NOT EDIT. +package serviceenablement + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/pkg/errors" + + contracts "github.com/SchwarzIT/community-stackit-go-client/pkg/contracts" + "github.com/SchwarzIT/community-stackit-go-client/pkg/helpers/runtime" + "github.com/SchwarzIT/community-stackit-go-client/pkg/validate" +) + +// Defines values for ActionErrorAction. +const ( + DISABLE ActionErrorAction = "DISABLE" + ENABLE ActionErrorAction = "ENABLE" +) + +// Defines values for ParametersGeneralProjectScope. +const ( + PARAMETERS_GENERAL_PROJECT_SCOPE_PUBLIC ParametersGeneralProjectScope = "PUBLIC" + PARAMETERS_GENERAL_PROJECT_SCOPE_SCHWARZ ParametersGeneralProjectScope = "SCHWARZ" +) + +// Defines values for ProjectCloudServiceEnablement. +const ( + AUTO ProjectCloudServiceEnablement = "AUTO" + REQUEST ProjectCloudServiceEnablement = "REQUEST" +) + +// Defines values for ProjectCloudServiceLifecycle. +const ( + FLEX ProjectCloudServiceLifecycle = "FLEX" + PROJECT ProjectCloudServiceLifecycle = "PROJECT" +) + +// Defines values for ProjectCloudServiceScope. +const ( + PROJECT_CLOUD_SERVICE_SCOPE_PRIVATE ProjectCloudServiceScope = "PRIVATE" + PROJECT_CLOUD_SERVICE_SCOPE_PUBLIC ProjectCloudServiceScope = "PUBLIC" +) + +// Defines values for ProjectCloudServiceState. +const ( + DISABLED ProjectCloudServiceState = "DISABLED" + DISABLING ProjectCloudServiceState = "DISABLING" + ENABLED ProjectCloudServiceState = "ENABLED" + ENABLING ProjectCloudServiceState = "ENABLING" +) + +// ActionError the last error for this service. +type ActionError struct { + // Action the last action which was triggered on this service + Action *ActionErrorAction `json:"action,omitempty"` + + // Code the error code if provided by the service + Code *string `json:"code,omitempty"` + + // Reason the error reason provided by the service + Reason *string `json:"reason,omitempty"` +} + +// ActionErrorAction the last action which was triggered on this service +type ActionErrorAction string + +// Dependencies defines model for Dependencies. +type Dependencies struct { + // Hard a list of service IDs which this service depend on. If the service is enabled, those service are enabled as well automatically. + Hard *[]ServiceID `json:"hard,omitempty"` + + // Soft a list of service IDs which this service depend on. When they are disabled a notification is sent. + Soft *[]ServiceID `json:"soft,omitempty"` +} + +// Parameters service parameters +type Parameters struct { + General *struct { + OrganizationID *string `json:"organizationId,omitempty"` + ProjectName *string `json:"projectName,omitempty"` + ProjectScope *ParametersGeneralProjectScope `json:"projectScope,omitempty"` + } `json:"general,omitempty"` + AdditionalProperties map[string]map[string]string `json:"-"` +} + +// ParametersGeneralProjectScope defines model for Parameters.General.ProjectScope. +type ParametersGeneralProjectScope string + +// ProjectCloudService defines model for ProjectCloudService. +type ProjectCloudService struct { + Dependencies *Dependencies `json:"dependencies,omitempty"` + Enablement *ProjectCloudServiceEnablement `json:"enablement,omitempty"` + + // Error the last error for this service. + Error *ActionError `json:"error,omitempty"` + Labels *map[string]string `json:"labels,omitempty"` + Lifecycle *ProjectCloudServiceLifecycle `json:"lifecycle,omitempty"` + + // Parameters service parameters + Parameters *Parameters `json:"parameters,omitempty"` + Scope *ProjectCloudServiceScope `json:"scope,omitempty"` + + // ServiceId the id of the service + ServiceID *ServiceID `json:"serviceId,omitempty"` + + // State the state of a service within a project + State *ProjectCloudServiceState `json:"state,omitempty"` +} + +// ProjectCloudServiceEnablement defines model for ProjectCloudService.Enablement. +type ProjectCloudServiceEnablement string + +// ProjectCloudServiceLifecycle defines model for ProjectCloudService.Lifecycle. +type ProjectCloudServiceLifecycle string + +// ProjectCloudServiceScope defines model for ProjectCloudService.Scope. +type ProjectCloudServiceScope string + +// ProjectCloudServiceState the state of a service within a project +type ProjectCloudServiceState string + +// ServiceID the id of the service +type ServiceID = string + +// ListServicesParams defines parameters for ListServices. +type ListServicesParams struct { + Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` +} + +// Getter for additional properties for Parameters. Returns the specified +// element and whether it was found +func (a Parameters) Get(fieldName string) (value map[string]string, found bool) { + if a.AdditionalProperties != nil { + value, found = a.AdditionalProperties[fieldName] + } + return +} + +// Setter for additional properties for Parameters +func (a *Parameters) Set(fieldName string, value map[string]string) { + if a.AdditionalProperties == nil { + a.AdditionalProperties = make(map[string]map[string]string) + } + a.AdditionalProperties[fieldName] = value +} + +// Override default JSON handling for Parameters to handle AdditionalProperties +func (a *Parameters) UnmarshalJSON(b []byte) error { + object := make(map[string]json.RawMessage) + err := json.Unmarshal(b, &object) + if err != nil { + return err + } + + if raw, found := object["general"]; found { + err = json.Unmarshal(raw, &a.General) + if err != nil { + return fmt.Errorf("error reading 'general': %w", err) + } + delete(object, "general") + } + + if len(object) != 0 { + a.AdditionalProperties = make(map[string]map[string]string) + for fieldName, fieldBuf := range object { + var fieldVal map[string]string + err := json.Unmarshal(fieldBuf, &fieldVal) + if err != nil { + return fmt.Errorf("error unmarshalling field %s: %w", fieldName, err) + } + a.AdditionalProperties[fieldName] = fieldVal + } + } + return nil +} + +// Override default JSON handling for Parameters to handle AdditionalProperties +func (a Parameters) MarshalJSON() ([]byte, error) { + var err error + object := make(map[string]json.RawMessage) + + if a.General != nil { + object["general"], err = json.Marshal(a.General) + if err != nil { + return nil, fmt.Errorf("error marshaling 'general': %w", err) + } + } + + for fieldName, field := range a.AdditionalProperties { + object[fieldName], err = json.Marshal(field) + if err != nil { + return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err) + } + } + return json.Marshal(object) +} + +// RequestEditorFn is the function signature for the RequestEditor callback function +type RequestEditorFn func(ctx context.Context, req *http.Request) error + +// Client which conforms to the OpenAPI3 specification for this service. +type Client struct { + // The endpoint of the server conforming to this interface, with scheme, + // https://api.deepmap.com for example. This can contain a path relative + // to the server, such as https://api.deepmap.com/dev-test, and all the + // paths in the swagger spec will be appended to the server. + Server string + + // Doer for performing requests, typically a *http.Client with any + // customized settings, such as certificate chains. + Client contracts.BaseClientInterface +} + +// NewRawClient Creates a new Client, with reasonable defaults +func NewRawClient(server string, httpClient contracts.BaseClientInterface) *Client { + // create a client with sane default values + client := Client{ + Server: server, + Client: httpClient, + } + return &client +} + +// The interface specification for the client above. +type rawClientInterface interface { + // ListServices request + ListServicesRaw(ctx context.Context, projectId string, params *ListServicesParams, reqEditors ...RequestEditorFn) (*http.Response, error) + + // DisableService request + DisableServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // GetService request + GetServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) + + // EnableService request + EnableServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) +} + +func (c *Client) ListServicesRaw(ctx context.Context, projectId string, params *ListServicesParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListServicesRequest(ctx, c.Server, projectId, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) DisableServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewDisableServiceRequest(ctx, c.Server, projectId, serviceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) GetServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewGetServiceRequest(ctx, c.Server, projectId, serviceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) EnableServiceRaw(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewEnableServiceRequest(ctx, c.Server, projectId, serviceId) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +// NewListServicesRequest generates requests for ListServices +func NewListServicesRequest(ctx context.Context, server string, projectId string, params *ListServicesParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "projectId", runtime.ParamLocationPath, projectId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/services", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + queryValues := queryURL.Query() + + if params.Cursor != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "cursor", runtime.ParamLocationQuery, *params.Cursor); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + + req, err := http.NewRequestWithContext(ctx, "GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewDisableServiceRequest generates requests for DisableService +func NewDisableServiceRequest(ctx context.Context, server string, projectId string, serviceId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "projectId", runtime.ParamLocationPath, projectId) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "serviceId", runtime.ParamLocationPath, serviceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/services/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, "DELETE", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewGetServiceRequest generates requests for GetService +func NewGetServiceRequest(ctx context.Context, server string, projectId string, serviceId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "projectId", runtime.ParamLocationPath, projectId) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "serviceId", runtime.ParamLocationPath, serviceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/services/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, "GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +// NewEnableServiceRequest generates requests for EnableService +func NewEnableServiceRequest(ctx context.Context, server string, projectId string, serviceId string) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "projectId", runtime.ParamLocationPath, projectId) + if err != nil { + return nil, err + } + + var pathParam1 string + + pathParam1, err = runtime.StyleParamWithLocation("simple", false, "serviceId", runtime.ParamLocationPath, serviceId) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/v1/projects/%s/services/%s", pathParam0, pathParam1) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, "POST", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + +func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { + for _, r := range additionalEditors { + if err := r(ctx, req); err != nil { + return err + } + } + return nil +} + +// ClientWithResponses builds on rawClientInterface to offer response payloads +type ClientWithResponses struct { + rawClientInterface +} + +// NewClient creates a new ClientWithResponses, which wraps +// Client with return type handling +func NewClient(server string, httpClient contracts.BaseClientInterface) *ClientWithResponses { + return &ClientWithResponses{NewRawClient(server, httpClient)} +} + +// ClientWithResponsesInterface is the interface specification for the client with responses above. +type ClientWithResponsesInterface interface { + // ListServices request + ListServices(ctx context.Context, projectId string, params *ListServicesParams, reqEditors ...RequestEditorFn) (*ListServicesResponse, error) + + // DisableService request + DisableService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*DisableServiceResponse, error) + + // GetService request + GetService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*GetServiceResponse, error) + + // EnableService request + EnableService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*EnableServiceResponse, error) +} + +type ListServicesResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Items *[]ProjectCloudService `json:"items,omitempty"` + NextCursor *string `json:"nextCursor,omitempty"` + } +} + +// Status returns HTTPResponse.Status +func (r ListServicesResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListServicesResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type DisableServiceResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r DisableServiceResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r DisableServiceResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type GetServiceResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *ProjectCloudService +} + +// Status returns HTTPResponse.Status +func (r GetServiceResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r GetServiceResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type EnableServiceResponse struct { + Body []byte + HTTPResponse *http.Response +} + +// Status returns HTTPResponse.Status +func (r EnableServiceResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r EnableServiceResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +// ListServices request returning *ListServicesResponse +func (c *ClientWithResponses) ListServices(ctx context.Context, projectId string, params *ListServicesParams, reqEditors ...RequestEditorFn) (*ListServicesResponse, error) { + rsp, err := c.ListServicesRaw(ctx, projectId, params, reqEditors...) + if err != nil { + return nil, err + } + return c.ParseListServicesResponse(rsp) +} + +// DisableService request returning *DisableServiceResponse +func (c *ClientWithResponses) DisableService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*DisableServiceResponse, error) { + rsp, err := c.DisableServiceRaw(ctx, projectId, serviceId, reqEditors...) + if err != nil { + return nil, err + } + return c.ParseDisableServiceResponse(rsp) +} + +// GetService request returning *GetServiceResponse +func (c *ClientWithResponses) GetService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*GetServiceResponse, error) { + rsp, err := c.GetServiceRaw(ctx, projectId, serviceId, reqEditors...) + if err != nil { + return nil, err + } + return c.ParseGetServiceResponse(rsp) +} + +// EnableService request returning *EnableServiceResponse +func (c *ClientWithResponses) EnableService(ctx context.Context, projectId string, serviceId string, reqEditors ...RequestEditorFn) (*EnableServiceResponse, error) { + rsp, err := c.EnableServiceRaw(ctx, projectId, serviceId, reqEditors...) + if err != nil { + return nil, err + } + return c.ParseEnableServiceResponse(rsp) +} + +// ParseListServicesResponse parses an HTTP response from a ListServices call +func (c *ClientWithResponses) ParseListServicesResponse(rsp *http.Response) (*ListServicesResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListServicesResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Items *[]ProjectCloudService `json:"items,omitempty"` + NextCursor *string `json:"nextCursor,omitempty"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("body was: %s", string(bodyBytes))) + } + response.JSON200 = &dest + + } + + return response, validate.ResponseObject(response) +} + +// ParseDisableServiceResponse parses an HTTP response from a DisableService call +func (c *ClientWithResponses) ParseDisableServiceResponse(rsp *http.Response) (*DisableServiceResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &DisableServiceResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, validate.ResponseObject(response) +} + +// ParseGetServiceResponse parses an HTTP response from a GetService call +func (c *ClientWithResponses) ParseGetServiceResponse(rsp *http.Response) (*GetServiceResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &GetServiceResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest ProjectCloudService + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("body was: %s", string(bodyBytes))) + } + response.JSON200 = &dest + + } + + return response, validate.ResponseObject(response) +} + +// ParseEnableServiceResponse parses an HTTP response from a EnableService call +func (c *ClientWithResponses) ParseEnableServiceResponse(rsp *http.Response) (*EnableServiceResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &EnableServiceResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + return response, validate.ResponseObject(response) +} diff --git a/pkg/services/service-enablement/v1/wait.go b/pkg/services/service-enablement/v1/wait.go new file mode 100644 index 0000000..a0302fa --- /dev/null +++ b/pkg/services/service-enablement/v1/wait.go @@ -0,0 +1,34 @@ +package serviceenablement + +import ( + "context" + "fmt" + "github.com/SchwarzIT/community-stackit-go-client/pkg/wait" + "github.com/pkg/errors" +) + +func (*GetServiceResponse) WaitHandler(ctx context.Context, c *ClientWithResponses, projectID, serviceID string) *wait.Handler { + return wait.New(func() (res interface{}, done bool, err error) { + + resp, err := c.GetService(ctx, projectID, serviceID) + if err != nil { + return nil, false, errors.Wrap(err, "failed during create request preparation") + } + if err != nil { + return nil, false, err + } + + switch *resp.JSON200.State { + case DISABLING: + return nil, false, fmt.Errorf("received state: %s for project ID: %s and service ID: %s", + *resp.JSON200.State, + projectID, + *resp.JSON200.ServiceID, + ) + case ENABLED: + return nil, true, nil + } + + return nil, false, nil + }) +} diff --git a/pkg/services/services.go b/pkg/services/services.go index 228f791..b03f76e 100644 --- a/pkg/services/services.go +++ b/pkg/services/services.go @@ -3,6 +3,7 @@ package services import ( "errors" iaas "github.com/SchwarzIT/community-stackit-go-client/pkg/services/iaas-api/v1alpha" + serviceenablement "github.com/SchwarzIT/community-stackit-go-client/pkg/services/service-enablement/v1" "github.com/SchwarzIT/community-stackit-go-client/pkg/clients" "github.com/SchwarzIT/community-stackit-go-client/pkg/contracts" @@ -34,6 +35,7 @@ type Services struct { ResourceManagement *resourcemanagement.ClientWithResponses SecretsManager *secretsmanager.ClientWithResponses ServiceAccounts *serviceaccounts.ClientWithResponses + ServiceEnablement *serviceenablement.ClientWithResponses // DSA ElasticSearch *dataservices.ClientWithResponses @@ -68,6 +70,7 @@ func Init(c contracts.BaseClientInterface) (*Services, error) { ResourceManagement: resourcemanagement.NewService(newClient(c)), ServiceAccounts: serviceaccounts.NewService(newClient(c)), SecretsManager: secretsmanager.NewService(newClient(c)), + ServiceEnablement: serviceenablement.NewService(newClient(c)), // DSA ElasticSearch: dataservices.NewService(newClient(c), dataservices.ElasticSearch),