diff --git a/internal/provider/client.go b/internal/provider/client.go index ee30254..4cacb81 100644 --- a/internal/provider/client.go +++ b/internal/provider/client.go @@ -23,6 +23,11 @@ type Client struct { HTTPClient *http.Client } +type ServerInfo struct { + Version string `json:"version"` + Metadata map[string]string `json:"metadata"` +} + func NewClient(serverURL, apiKey string) *Client { return &Client{ ServerURL: serverURL, @@ -97,6 +102,21 @@ func (c *Client) doRequest(method, path string, body interface{}) (*http.Respons return resp, nil } +// GetServerInfo fetches server info to determine version and capabilities +func (c *Client) GetServerInfo() (*ServerInfo, error) { + resp, err := c.doRequest("GET", "/api/v1/info", nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var result ServerInfo + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("error decoding server info: %v", err) + } + return &result, nil +} + // Stack operations func (c *Client) CreateStack(workspace string, stack StackRequest) (*StackResponse, error) { // Check server version to determine which endpoint to use @@ -105,9 +125,13 @@ func (c *Client) CreateStack(workspace string, stack StackRequest) (*StackRespon return nil, fmt.Errorf("failed to get server info: %v", err) } + log.Printf("Server info: %+v", info) + endpoint := fmt.Sprintf("/api/v1/workspaces/%s/stacks", workspace) - if isLowerVersion(info.Version, "0.65.0") { - endpoint = fmt.Sprintf("/api/v1/workspaces/%s/full-stack", workspace) + + // Set workspace in request if not already set + if stack.Workspace == nil { + stack.Workspace = &workspace } resp, err := c.doRequest("POST", endpoint, stack) @@ -123,32 +147,6 @@ func (c *Client) CreateStack(workspace string, stack StackRequest) (*StackRespon return &result, nil } -// GetServerInfo fetches server info to determine version and capabilities -func (c *Client) GetServerInfo() (*ServerInfo, error) { - resp, err := c.doRequest("GET", "/api/v1/info", nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var result ServerInfo - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return nil, fmt.Errorf("error decoding server info: %v", err) - } - return &result, nil -} - -type ServerInfo struct { - Version string `json:"version"` - Metadata map[string]string `json:"metadata"` -} - -// Helper function to compare versions -func isLowerVersion(version, compare string) bool { - // Simple version comparison - in production you'd want a more robust version comparison - return version < compare -} - // Remaining methods from the original client... func (c *Client) GetStack(id string) (*StackResponse, error) { resp, err := c.doRequest("GET", fmt.Sprintf("/api/v1/stacks/%s", id), nil) @@ -219,8 +217,11 @@ func (c *Client) ListStacks(params *ListParams) (*Page[StackResponse], error) { } // Component operations... -func (c *Client) CreateComponent(workspace string, body ComponentRequest) (*ComponentResponse, error) { - resp, err := c.doRequest("POST", fmt.Sprintf("/api/v1/workspaces/%s/components", workspace), body) +func (c *Client) CreateComponent(workspace string, component ComponentRequest) (*ComponentResponse, error) { + // Ensure workspace and user are set in the request + component.Workspace = workspace + + resp, err := c.doRequest("POST", fmt.Sprintf("/api/v1/workspaces/%s/components", workspace), component) if err != nil { return nil, err } @@ -380,4 +381,25 @@ func (c *Client) ListServiceConnectors(params *ListParams) (*Page[ServiceConnect } return &result, nil -} \ No newline at end of file +} + +// Add this new method to the Client +func (c *Client) GetServiceConnectorByName(workspace, name string) (*ServiceConnectorResponse, error) { + params := &ListParams{ + Filter: map[string]string{ + "name": name, + "workspace": workspace, + }, + } + + connectors, err := c.ListServiceConnectors(params) + if err != nil { + return nil, err + } + + if len(connectors.Items) == 0 { + return nil, fmt.Errorf("no service connector found with name %s", name) + } + + return &connectors.Items[0], nil +} diff --git a/internal/provider/data_source_service_connector.go b/internal/provider/data_source_service_connector.go index ee8ea07..6bc02c5 100644 --- a/internal/provider/data_source_service_connector.go +++ b/internal/provider/data_source_service_connector.go @@ -54,10 +54,10 @@ func setServiceConnectorFields(d *schema.ResourceData, connector *ServiceConnect if err := d.Set("name", connector.Name); err != nil { return fmt.Errorf("error setting name: %v", err) } - if err := d.Set("type", connector.Type); err != nil { + if err := d.Set("type", connector.Body.ConnectorType); err != nil { return fmt.Errorf("error setting type: %v", err) } - if err := d.Set("auth_method", connector.AuthMethod); err != nil { + if err := d.Set("auth_method", connector.Body.AuthMethod); err != nil { return fmt.Errorf("error setting auth_method: %v", err) } @@ -67,10 +67,11 @@ func setServiceConnectorFields(d *schema.ResourceData, connector *ServiceConnect return fmt.Errorf("error setting resource_types: %v", err) } } - if connector.Body.Workspace != "" { - if err := d.Set("workspace", connector.Body.Workspace); err != nil { - return fmt.Errorf("error setting workspace: %v", err) - } + } + + if connector.Metadata != nil && connector.Metadata.Workspace != nil { + if err := d.Set("workspace", connector.Metadata.Workspace.Name); err != nil { + return fmt.Errorf("error setting workspace: %v", err) } } diff --git a/internal/provider/data_source_stack.go b/internal/provider/data_source_stack.go index ca29db0..ed53330 100644 --- a/internal/provider/data_source_stack.go +++ b/internal/provider/data_source_stack.go @@ -74,15 +74,8 @@ func setStackData(d *schema.ResourceData, stack *StackResponse) error { d.SetId(stack.ID) d.Set("name", stack.Name) - components := make(map[string]string) - for k, v := range stack.Components { - components[k] = v.ID - } - d.Set("components", components) - - if stack.Labels != nil { - d.Set("labels", stack.Labels) - } + d.Set("components", stack.Metadata.Components) + d.Set("labels", stack.Metadata.Labels) return nil } diff --git a/internal/provider/data_source_stack_component.go b/internal/provider/data_source_stack_component.go index 62e1cb7..1544a32 100644 --- a/internal/provider/data_source_stack_component.go +++ b/internal/provider/data_source_stack_component.go @@ -44,26 +44,30 @@ func dataSourceStackComponentRead(d *schema.ResourceData, m interface{}) error { } func setStackComponentFields(d *schema.ResourceData, component *ComponentResponse) error { - if component.Body == nil { - return fmt.Errorf("received empty response body") + if err := d.Set("name", component.Name); err != nil { + return fmt.Errorf("error setting name: %v", err) } - // Access all fields through component.Body - d.Set("name", component.Body.Name) - d.Set("type", component.Body.Type) - d.Set("flavor", component.Body.Flavor) - d.Set("configuration", component.Body.Configuration) - - if component.Body.Workspace != "" { - d.Set("workspace", component.Body.Workspace) - } - - if component.Body.ConnectorResourceID != "" { - d.Set("connector_resource_id", component.Body.ConnectorResourceID) - } - - if component.Body.Labels != nil { - d.Set("labels", component.Body.Labels) + if component.Metadata != nil { + if err := d.Set("configuration", component.Metadata.Configuration); err != nil { + return fmt.Errorf("error setting configuration: %v", err) + } + + if component.Metadata.Workspace != nil { + if err := d.Set("workspace", component.Metadata.Workspace.Name); err != nil { + return fmt.Errorf("error setting workspace: %v", err) + } + } + + if component.Metadata.ConnectorResourceID != nil { + if err := d.Set("connector_resource_id", component.Metadata.ConnectorResourceID); err != nil { + return fmt.Errorf("error setting connector_resource_id: %v", err) + } + } + + if err := d.Set("labels", component.Metadata.Labels); err != nil { + return fmt.Errorf("error setting labels: %v", err) + } } return nil diff --git a/internal/provider/models.go b/internal/provider/models.go index 292c14e..206079b 100644 --- a/internal/provider/models.go +++ b/internal/provider/models.go @@ -1,115 +1,176 @@ -// models.go +// Package provider contains data models for the ZenML API package provider -import "fmt" -// Common response format +// Page represents a paginated response from the API type Page[T any] struct { - Total int64 `json:"total"` - Items []T `json:"items"` - Cursor any `json:"cursor,omitempty"` + Index int `json:"index"` + MaxSize int `json:"max_size"` + TotalPages int `json:"total_pages"` + Total int `json:"total"` + Items []T `json:"items"` } -// Stack models +// APIError represents an error response from the API +type APIError struct { + Detail string `json:"detail"` +} + +func (e *APIError) Error() string { + return e.Detail +} + +// StackRequest represents a request to create a new stack +type StackRequest struct { + Name string `json:"name"` + Components map[string][]string `json:"components"` // Change to UUID strings + Description string `json:"description,omitempty"` +} + +// StackResponse represents a stack response from the API type StackResponse struct { - ID string `json:"id"` - Name string `json:"name"` - Components map[string]Component `json:"components"` - Labels map[string]string `json:"labels,omitempty"` - Metadata *ResponseMetadata `json:"metadata,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Components map[string][]ComponentResponse `json:"components"` +} + +type StackResponseBody struct { + Created string `json:"created"` + Updated string `json:"updated"` + User *UserResponse `json:"user,omitempty"` +} + +type StackResponseMetadata struct { + Workspace *WorkspaceResponse `json:"workspace"` + Components map[string][]ComponentResponse `json:"components"` + Description string `json:"description,omitempty"` + StackSpecPath string `json:"stack_spec_path,omitempty"` + Labels map[string]string `json:"labels,omitempty"` } +// StackUpdate represents an update to an existing stack type StackUpdate struct { - Name string `json:"name,omitempty"` - Components map[string]Component `json:"components,omitempty"` - Labels map[string]string `json:"labels,omitempty"` -} - -// Component models -type Component struct { - ID string `json:"id"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` - Flavor string `json:"flavor,omitempty"` - Configuration map[string]interface{} `json:"configuration,omitempty"` - ConnectorID string `json:"connector_id,omitempty"` -} - -// ComponentBody represents the common fields for component requests/responses -type ComponentBody struct { - Name string `json:"name"` - Type string `json:"type"` - Flavor string `json:"flavor"` - Configuration map[string]interface{} `json:"configuration"` - Workspace string `json:"workspace"` - User string `json:"user,omitempty"` - ConnectorResourceID string `json:"connector_resource_id,omitempty"` - Labels map[string]string `json:"labels,omitempty"` -} - -// ComponentResponse represents the API response for a component + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + Components map[string][]string `json:"components,omitempty"` // Only UUIDs for updates + Labels map[string]string `json:"labels,omitempty"` + StackSpecPath *string `json:"stack_spec_path,omitempty"` +} + +// ComponentRequest represents a request to create a new component +type ComponentRequest struct { + User string `json:"user"` + Workspace string `json:"workspace"` + Name string `json:"name"` + Type string `json:"type"` + Flavor string `json:"flavor"` + Configuration map[string]interface{} `json:"configuration"` + ConnectorID *string `json:"connector,omitempty"` + ConnectorResourceID *string `json:"connector_resource_id,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + ComponentSpecPath *string `json:"component_spec_path,omitempty"` +} + +// ComponentResponse represents a stack component response from the API type ComponentResponse struct { - ID string `json:"id"` - Body *ComponentBody `json:"body"` + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Flavor string `json:"flavor"` + Configuration map[string]interface{} `json:"configuration"` } +type ComponentResponseBody struct { + Created string `json:"created"` + Updated string `json:"updated"` + User *UserResponse `json:"user,omitempty"` + Type string `json:"type"` + Flavor string `json:"flavor"` + Integration *string `json:"integration,omitempty"` +} + +type ComponentResponseMetadata struct { + Workspace *WorkspaceResponse `json:"workspace"` + Configuration map[string]interface{} `json:"configuration"` + Labels map[string]string `json:"labels,omitempty"` + ComponentSpecPath *string `json:"component_spec_path,omitempty"` + ConnectorResourceID *string `json:"connector_resource_id,omitempty"` + Connector *ServiceConnectorResponse `json:"connector,omitempty"` +} + +// ComponentUpdate represents an update to an existing component type ComponentUpdate struct { - Name string `json:"name,omitempty"` - Configuration map[string]interface{} `json:"configuration,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - ComponentSpecPath *string `json:"component_spec_path,omitempty"` - Connector *string `json:"connector,omitempty"` + Name *string `json:"name,omitempty"` + Type *string `json:"type,omitempty"` + Flavor *string `json:"flavor,omitempty"` + Configuration map[string]interface{} `json:"configuration,omitempty"` + ConnectorID *string `json:"connector,omitempty"` + ConnectorResourceID *string `json:"connector_resource_id,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + ComponentSpecPath *string `json:"component_spec_path,omitempty"` } -type ComponentCreate struct { - Name string `json:"name"` - Type string `json:"type"` - Flavor string `json:"flavor"` - Configuration map[string]interface{} `json:"configuration"` - Workspace string `json:"workspace"` - User string `json:"user"` +// ServiceConnectorRequest represents a request to create a new service connector +type ServiceConnectorRequest struct { + User string `json:"user"` + Workspace string `json:"workspace"` + Name string `json:"name"` + ConnectorType string `json:"connector_type"` + AuthMethod string `json:"auth_method"` + ResourceTypes []string `json:"resource_types"` + Configuration map[string]interface{} `json:"configuration"` + Secrets map[string]string `json:"secrets,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + ResourceID *string `json:"resource_id,omitempty"` + ExpiresAt *string `json:"expires_at,omitempty"` } -// Service Connector models +// ServiceConnectorResponse represents a service connector response from the API type ServiceConnectorResponse struct { - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - AuthMethod string `json:"auth_method"` - Body *ServiceConnectorBody `json:"body,omitempty"` - Metadata *ResponseMetadata `json:"metadata,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Body *ServiceConnectorResponseBody `json:"body,omitempty"` + Metadata *ServiceConnectorResponseMetadata `json:"metadata,omitempty"` } -type ServiceConnectorBody struct { - User string `json:"user"` - Workspace string `json:"workspace"` - Configuration map[string]interface{} `json:"configuration"` - Secrets map[string]interface{} `json:"secrets,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - ResourceTypes []string `json:"resource_types,omitempty"` +type ServiceConnectorResponseBody struct { + Created string `json:"created"` + Updated string `json:"updated"` + User *UserResponse `json:"user,omitempty"` + ConnectorType string `json:"connector_type"` + AuthMethod string `json:"auth_method"` + ResourceTypes []string `json:"resource_types"` + ResourceID *string `json:"resource_id,omitempty"` + ExpiresAt *string `json:"expires_at,omitempty"` } -type ServiceConnectorUpdate struct { - Name string `json:"name,omitempty"` - Configuration map[string]interface{} `json:"configuration,omitempty"` - Secrets map[string]interface{} `json:"secrets,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - ResourceTypes []string `json:"resource_types,omitempty"` +type ServiceConnectorResponseMetadata struct { + Workspace *WorkspaceResponse `json:"workspace"` + Configuration map[string]interface{} `json:"configuration"` + SecretID *string `json:"secret_id,omitempty"` + Labels map[string]string `json:"labels,omitempty"` } -type ResponseMetadata struct { - Created string `json:"created"` - Updated string `json:"updated"` - User string `json:"user"` - Workspace string `json:"workspace"` +// ServiceConnectorUpdate represents an update to an existing service connector +type ServiceConnectorUpdate struct { + Name *string `json:"name,omitempty"` + Configuration map[string]interface{} `json:"configuration,omitempty"` + Secrets map[string]string `json:"secrets,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + ResourceID *string `json:"resource_id,omitempty"` + ExpiresAt *string `json:"expires_at,omitempty"` } -// APIError represents an error response from the API -type APIError struct { - Code int `json:"code"` - Message string `json:"message"` - Detail string `json:"detail"` +// UserResponse represents a user response from the API +type UserResponse struct { + ID string `json:"id"` + Name string `json:"name"` } -func (e *APIError) Error() string { - return fmt.Sprintf("API error (code: %d): %s - %s", e.Code, e.Message, e.Detail) +// WorkspaceResponse represents a workspace response from the API +type WorkspaceResponse struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Created string `json:"created"` + Updated string `json:"updated"` } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 0b5a266..ed87b49 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -56,6 +56,7 @@ func providerConfigure(_ context.Context, d *schema.ResourceData) (interface{}, // Test the client connection // You might want to add a simple API call here to verify the connection - + client.GetServerInfo() + return client, diags } diff --git a/openapi.json b/openapi.json new file mode 100644 index 0000000..2e9212b --- /dev/null +++ b/openapi.json @@ -0,0 +1,1500 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "ZenML Components API", + "version": "0.68.0" + }, + "paths": { + "/api/v1/components": { + "get": { + "tags": ["stack_components"], + "summary": "List Stack Components", + "description": "Get a list of all stack components for a specific type.", + "operationId": "list_stack_components_api_v1_components_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "hydrate", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "title": "Hydrate" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "created", + "title": "Sort By" + } + }, + { + "name": "logical_operator", + "in": "query", + "required": false, + "schema": { + "allOf": [{"$ref": "#/components/schemas/LogicalOperators"}], + "default": "and", + "title": "Logical Operator" + } + }, + { + "name": "type", + "in": "query", + "required": false, + "schema": { + "anyOf": [{"$ref": "#/components/schemas/StackComponentType"}, {"type": "null"}], + "title": "Type" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_ComponentResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + } + } + } + }, + "/api/v1/components/{component_id}": { + "get": { + "tags": ["stack_components"], + "summary": "Get Stack Component", + "description": "Returns the requested stack component.", + "operationId": "get_stack_component_api_v1_components__component_id__get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "component_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Component Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComponentResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": ["stack_components"], + "summary": "Update Stack Component", + "description": "Updates a stack component.", + "operationId": "update_stack_component_api_v1_components__component_id__put", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "component_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Component Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComponentUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComponentResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": ["stack_components"], + "summary": "Delete Stack Component", + "description": "Deletes a stack component.", + "operationId": "delete_stack_component_api_v1_components__component_id__delete", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "component_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Component Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/api/v1/stacks": { + "get": { + "tags": ["stacks"], + "summary": "List Stacks", + "description": "Returns all stacks.", + "operationId": "list_stacks_api_v1_stacks_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "hydrate", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "title": "Hydrate" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_StackResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/api/v1/stacks/{stack_id}": { + "get": { + "tags": ["stacks"], + "summary": "Get Stack", + "description": "Returns the requested stack.", + "operationId": "get_stack_api_v1_stacks__stack_id__get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "stack_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Stack Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StackResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": ["stacks"], + "summary": "Delete Stack", + "description": "Deletes a stack.", + "operationId": "delete_stack_api_v1_stacks__stack_id__delete", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "stack_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Stack Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": ["stacks"], + "summary": "Update Stack", + "description": "Updates a stack.", + "operationId": "update_stack_api_v1_stacks__stack_id__put", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "stack_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Stack Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StackUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StackResponse" + } + } + } + } + } + } + }, + "/api/v1/service_connectors": { + "get": { + "tags": ["service_connectors"], + "summary": "List Service Connectors", + "description": "Get a list of all service connectors.", + "operationId": "list_service_connectors_api_v1_service_connectors_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "hydrate", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "title": "Hydrate" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_ServiceConnectorResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + } + }, + "/api/v1/workspaces": { + "get": { + "tags": ["workspaces"], + "summary": "List Workspaces", + "description": "Lists all workspaces in the organization.", + "operationId": "list_workspaces_api_v1_workspaces_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "hydrate", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "title": "Hydrate" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_WorkspaceResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + } + } + }, + "post": { + "tags": ["workspaces"], + "summary": "Create Workspace", + "description": "Creates a workspace based on the requestBody.", + "operationId": "create_workspace_api_v1_workspaces_post", + "security": [{"CookieOAuth2TokenBearer": []}], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/api/v1/workspaces/{workspace_name_or_id}": { + "get": { + "tags": ["workspaces"], + "summary": "Get Workspace", + "description": "Get a workspace for given name.", + "operationId": "get_workspace_api_v1_workspaces__workspace_name_or_id__get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": ["workspaces"], + "summary": "Update Workspace", + "description": "Update a workspace for given name.", + "operationId": "update_workspace_api_v1_workspaces__workspace_name_or_id__put", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Workspace Name Or Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkspaceResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": ["workspaces"], + "summary": "Delete Workspace", + "description": "Deletes a workspace.", + "operationId": "delete_workspace_api_v1_workspaces__workspace_name_or_id__delete", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response" + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/api/v1/workspaces/{workspace_name_or_id}/stacks": { + "get": { + "tags": ["workspaces"], + "summary": "List Workspace Stacks", + "description": "Get stacks that are part of a specific workspace for the user.", + "operationId": "list_workspace_stacks_api_v1_workspaces__workspace_name_or_id__stacks_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_StackResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "tags": ["workspaces"], + "summary": "Create Stack", + "description": "Creates a stack for a particular workspace.", + "operationId": "create_stack_api_v1_workspaces__workspace_name_or_id__stacks_post", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StackRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StackResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/api/v1/workspaces/{workspace_name_or_id}/components": { + "get": { + "tags": ["workspaces"], + "summary": "List Workspace Stack Components", + "description": "List stack components that are part of a specific workspace.", + "operationId": "list_workspace_stack_components_api_v1_workspaces__workspace_name_or_id__components_get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Page_ComponentResponse_" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "tags": ["workspaces"], + "summary": "Create Stack Component", + "description": "Creates a stack component.", + "operationId": "create_stack_component_api_v1_workspaces__workspace_name_or_id__components_post", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComponentRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ComponentResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "409": { + "description": "Conflict" + } + } + } + }, + "/api/v1/service_connectors/{connector_id}": { + "get": { + "tags": ["service_connectors"], + "summary": "Get Service Connector", + "description": "Gets a specific service connector.", + "operationId": "get_service_connector_api_v1_service_connectors__connector_id__get", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "connector_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Connector Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceConnectorResponse" + } + } + } + } + } + }, + "put": { + "tags": ["service_connectors"], + "summary": "Update Service Connector", + "description": "Updates a service connector.", + "operationId": "update_service_connector_api_v1_service_connectors__connector_id__put", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "connector_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Connector Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceConnectorUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceConnectorResponse" + } + } + } + } + } + }, + "delete": { + "tags": ["service_connectors"], + "summary": "Delete Service Connector", + "description": "Deletes a service connector.", + "operationId": "delete_service_connector_api_v1_service_connectors__connector_id__delete", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "connector_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid", + "title": "Connector Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response" + } + } + } + }, + "/api/v1/workspaces/{workspace_name_or_id}/service_connectors": { + "post": { + "tags": ["workspaces"], + "summary": "Create Service Connector", + "description": "Creates a service connector.", + "operationId": "create_service_connector_api_v1_workspaces__workspace_name_or_id__service_connectors_post", + "security": [{"CookieOAuth2TokenBearer": []}], + "parameters": [ + { + "name": "workspace_name_or_id", + "in": "path", + "required": true, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string", + "format": "uuid" + } + ], + "title": "Workspace Name Or Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceConnectorRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceConnectorResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "StackComponentType": { + "type": "string", + "enum": [ + "alerter", + "annotator", + "artifact_store", + "container_registry", + "data_validator", + "experiment_tracker", + "feature_store", + "image_builder", + "model_deployer", + "orchestrator", + "step_operator", + "model_registry" + ], + "title": "StackComponentType", + "description": "All possible types a `StackComponent` can have." + }, + "ComponentResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "The unique resource id." + }, + "name": { + "type": "string", + "maxLength": 255, + "title": "The name of the stack component." + }, + "type": { + "$ref": "#/components/schemas/StackComponentType" + }, + "flavor": { + "type": "string", + "title": "The flavor of the stack component." + }, + "configuration": { + "type": "object", + "title": "The stack component configuration." + } + }, + "required": ["id", "name", "type", "flavor", "configuration"], + "title": "ComponentResponse", + "description": "Response model for components." + }, + "ComponentUpdate": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The name of the stack component." + }, + "configuration": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "The stack component configuration." + } + }, + "title": "ComponentUpdate", + "description": "Update model for stack components." + }, + "Page_ComponentResponse_": { + "properties": { + "index": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Index" + }, + "max_size": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Max Size" + }, + "total_pages": { + "type": "integer", + "minimum": 0.0, + "title": "Total Pages" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "items": { + "items": { + "$ref": "#/components/schemas/ComponentResponse" + }, + "type": "array", + "title": "Items" + } + }, + "required": ["index", "max_size", "total_pages", "total", "items"], + "title": "Page[ComponentResponse]" + }, + "StackResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "The unique resource id." + }, + "name": { + "type": "string", + "maxLength": 255, + "title": "The name of the stack." + }, + "components": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ComponentResponse" + } + }, + "title": "The components in this stack." + } + }, + "required": ["id", "name", "components"], + "title": "StackResponse", + "description": "Response model for stacks." + }, + "Page_StackResponse_": { + "properties": { + "index": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Index" + }, + "max_size": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Max Size" + }, + "total_pages": { + "type": "integer", + "minimum": 0.0, + "title": "Total Pages" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "items": { + "items": { + "$ref": "#/components/schemas/StackResponse" + }, + "type": "array", + "title": "Items" + } + }, + "required": ["index", "max_size", "total_pages", "total", "items"], + "title": "Page[StackResponse]" + }, + "ServiceConnectorResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "The unique resource id." + }, + "name": { + "type": "string", + "maxLength": 255, + "title": "The service connector name." + }, + "connector_type": { + "type": "string", + "title": "The type of service connector." + }, + "configuration": { + "type": "object", + "title": "The service connector configuration." + } + }, + "required": ["id", "name", "connector_type", "configuration"], + "title": "ServiceConnectorResponse", + "description": "Response model for service connectors." + }, + "Page_ServiceConnectorResponse_": { + "properties": { + "index": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Index" + }, + "max_size": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Max Size" + }, + "total_pages": { + "type": "integer", + "minimum": 0.0, + "title": "Total Pages" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "items": { + "items": { + "$ref": "#/components/schemas/ServiceConnectorResponse" + }, + "type": "array", + "title": "Items" + } + }, + "required": ["index", "max_size", "total_pages", "total", "items"], + "title": "Page[ServiceConnectorResponse]" + }, + "LogicalOperators": { + "type": "string", + "enum": ["or", "and"], + "title": "LogicalOperators", + "description": "Logical Ops to use to combine filters on list methods." + }, + "ServiceConnectorRequest": { + "properties": { + "name": { + "type": "string", + "maxLength": 255, + "title": "The service connector name." + }, + "connector_type": { + "type": "string", + "title": "The type of service connector." + }, + "configuration": { + "type": "object", + "title": "The service connector configuration, not including secrets." + }, + "secrets": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "format": "password", + "writeOnly": true + }, + { + "type": "null" + } + ] + }, + "title": "The service connector secrets." + } + }, + "required": ["name", "connector_type", "configuration"], + "title": "ServiceConnectorRequest", + "description": "Request model for service connectors." + }, + "ServiceConnectorUpdate": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The service connector name." + }, + "configuration": { + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "title": "The service connector configuration, not including secrets." + }, + "secrets": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string", + "format": "password", + "writeOnly": true + }, + { + "type": "null" + } + ] + } + }, + { + "type": "null" + } + ], + "title": "The service connector secrets." + } + }, + "title": "ServiceConnectorUpdate", + "description": "Update model for service connectors." + }, + "ServiceConnectorTypeModel": { + "properties": { + "name": { + "type": "string", + "title": "User readable name for the service connector type." + }, + "connector_type": { + "type": "string", + "maxLength": 255, + "title": "The type of service connector." + }, + "description": { + "type": "string", + "title": "A description of the service connector.", + "default": "" + }, + "auth_methods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AuthenticationMethodModel" + }, + "title": "A list of authentication methods that are supported by the service connector." + } + }, + "required": ["name", "connector_type", "auth_methods"], + "title": "ServiceConnectorTypeModel", + "description": "Service connector type specification." + }, + "AuthenticationMethodModel": { + "properties": { + "name": { + "type": "string", + "title": "User readable name for the authentication method." + }, + "auth_method": { + "type": "string", + "maxLength": 255, + "title": "The name of the authentication method." + }, + "description": { + "type": "string", + "title": "A description of the authentication method.", + "default": "" + } + }, + "required": ["name", "auth_method"], + "title": "AuthenticationMethodModel", + "description": "Authentication method specification." + }, + "StackRequest": { + "properties": { + "name": { + "type": "string", + "maxLength": 255, + "title": "The name of the stack." + }, + "components": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "title": "The components in this stack." + }, + "description": { + "type": "string", + "maxLength": 255, + "title": "The description of the stack", + "default": "" + } + }, + "required": ["name", "components"], + "title": "StackRequest", + "description": "Request model for stacks." + }, + "WorkspaceRequest": { + "properties": { + "name": { + "type": "string", + "maxLength": 255, + "title": "The unique name of the workspace." + }, + "description": { + "type": "string", + "maxLength": 255, + "title": "The description of the workspace.", + "default": "" + } + }, + "required": ["name"], + "title": "WorkspaceRequest", + "description": "Request model for workspaces." + }, + "WorkspaceResponse": { + "properties": { + "id": { + "type": "string", + "format": "uuid", + "title": "The unique resource id." + }, + "name": { + "type": "string", + "maxLength": 255, + "title": "The unique name of the workspace." + }, + "description": { + "type": "string", + "maxLength": 255, + "title": "The description of the workspace.", + "default": "" + }, + "created": { + "type": "string", + "format": "date-time", + "title": "The timestamp when this resource was created." + }, + "updated": { + "type": "string", + "format": "date-time", + "title": "The timestamp when this resource was last updated." + } + }, + "required": ["id", "name", "created", "updated"], + "title": "WorkspaceResponse", + "description": "Response model for workspaces." + }, + "WorkspaceUpdate": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The unique name of the workspace." + }, + "description": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The description of the workspace." + } + }, + "title": "WorkspaceUpdate", + "description": "Update model for workspaces." + }, + "Page_WorkspaceResponse_": { + "properties": { + "index": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Index" + }, + "max_size": { + "type": "integer", + "exclusiveMinimum": 0.0, + "title": "Max Size" + }, + "total_pages": { + "type": "integer", + "minimum": 0.0, + "title": "Total Pages" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "items": { + "items": { + "$ref": "#/components/schemas/WorkspaceResponse" + }, + "type": "array", + "title": "Items" + } + }, + "required": ["index", "max_size", "total_pages", "total", "items"], + "title": "Page[WorkspaceResponse]" + }, + "StackUpdate": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The name of the stack." + }, + "description": { + "anyOf": [ + { + "type": "string", + "maxLength": 255 + }, + { + "type": "null" + } + ], + "title": "The description of the stack" + }, + "components": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "type": "null" + } + ], + "title": "The components in this stack." + } + }, + "title": "StackUpdate", + "description": "Update model for stacks." + } + }, + "securitySchemes": { + "CookieOAuth2TokenBearer": { + "type": "oauth2", + "flows": { + "password": { + "scopes": {}, + "tokenUrl": "/api/v1/login" + } + } + } + } + } +} \ No newline at end of file