Skip to content

Commit

Permalink
Calm Base POC Code
Browse files Browse the repository at this point in the history
  • Loading branch information
siddharth-nutanix committed Jan 24, 2025
1 parent fff432c commit 351c982
Show file tree
Hide file tree
Showing 8 changed files with 2,214 additions and 0 deletions.
47 changes: 47 additions & 0 deletions client/calm/calm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package calm

import (
"fmt"
"strings"

"github.com/terraform-providers/terraform-provider-nutanix/nutanix/client"
)

const (
libraryVersion = "v3"
absolutePath = "api/nutanix/" + libraryVersion
userAgent = "nutanix/" + libraryVersion
clientName = "calm"
)

// Client manages the foundation central API
type Client struct {
client *client.Client
Service Service
}

func NewCalmClient(credentials client.Credentials) (*Client, error) {
var baseClient *client.Client

// check if all required fields are present. Else create an empty client
if credentials.Username != "" && credentials.Password != "" && credentials.Endpoint != "" {
c, err := client.NewClient(&credentials, userAgent, absolutePath, false)
if err != nil {
return nil, err
}
baseClient = c
} else {
errorMsg := fmt.Sprintf("Calm Client is missing. "+
"Please provide required details - %s in provider configuration.", strings.Join(credentials.RequiredFields[clientName], ", "))

baseClient = &client.Client{UserAgent: userAgent, ErrorMsg: errorMsg}
}

fc := &Client{
client: baseClient,
Service: Operations{
client: baseClient,
},
}
return fc, nil
}
156 changes: 156 additions & 0 deletions client/calm/calm_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package calm

import (
"context"
"fmt"
"net/http"

"github.com/terraform-providers/terraform-provider-nutanix/nutanix/client"
)

type Operations struct {
client *client.Client
}

type Service interface {
ProvisionBlueprint(ctx context.Context, uuid string, input *BlueprintProvisionInput) (*AppProvisionTaskOutput, error)
GetBlueprint(ctx context.Context, uuid string) (*BlueprintResponse, error)
TaskPoll(ctx context.Context, bpUUID string, launchID string) (*PollResponse, error)
DeleteApp(ctx context.Context, appUUID string) (*DeleteAppResp, error)
GetApp(ctx context.Context, appUUID string) (*AppResponse, error)
PerformAction(ctx context.Context, appUUID string, spec *ActionSpec) (*AppActionResponse, error)
AppRunlogs(ctx context.Context, appUUID, runlogUUID string) (*AppRunlogsResponse, error)
ListBlueprint(ctx context.Context, filter *BlueprintListInput) (*BlueprintListResponse, error)
GetRuntimeEditables(ctx context.Context, bpUUID string) (*RuntimeEditablesResponse, error)
PatchApp(ctx context.Context, appUUID string, patchUUID string, input *PatchInput) (*AppPatchResponse, error)
}

func (op Operations) ProvisionBlueprint(ctx context.Context, bpUUID string, input *BlueprintProvisionInput) (*AppProvisionTaskOutput, error) {
path := fmt.Sprintf("/blueprints/%s/simple_launch", bpUUID)

req, err := op.client.NewRequest(ctx, http.MethodPost, path, input)

appResponse := new(AppProvisionTaskOutput)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) GetBlueprint(ctx context.Context, bpUUID string) (*BlueprintResponse, error) {
path := fmt.Sprintf("/blueprints/%s", bpUUID)

req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil)

appResponse := new(BlueprintResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) TaskPoll(ctx context.Context, bpUUID string, launchID string) (*PollResponse, error) {
path := fmt.Sprintf("/blueprints/%s/pending_launches/%s", bpUUID, launchID)

req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil)

appResponse := new(PollResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) DeleteApp(ctx context.Context, id string) (*DeleteAppResp, error) {
httpReq, err := op.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("/apps/%s", id), nil)
if err != nil {
return nil, err
}
res := new(DeleteAppResp)
return res, op.client.Do(ctx, httpReq, res)
}

func (op Operations) GetApp(ctx context.Context, id string) (*AppResponse, error) {
httpReq, err := op.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("/apps/%s", id), nil)
if err != nil {
return nil, err
}
res := new(AppResponse)
return res, op.client.Do(ctx, httpReq, res)
}

func (op Operations) PerformAction(ctx context.Context, appUUID string, input *ActionSpec) (*AppActionResponse, error) {
path := fmt.Sprintf("/apps/%s/actions/run", appUUID)

req, err := op.client.NewRequest(ctx, http.MethodPost, path, input)

appResponse := new(AppActionResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) AppRunlogs(ctx context.Context, appUUID string, runlogUUID string) (*AppRunlogsResponse, error) {
path := fmt.Sprintf("/apps/%s/app_runlogs/%s/output", appUUID, runlogUUID)

req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil)

appResponse := new(AppRunlogsResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) ListBlueprint(ctx context.Context, filter *BlueprintListInput) (*BlueprintListResponse, error) {
path := "/blueprints/list"

req, err := op.client.NewRequest(ctx, http.MethodPost, path, filter)

appResponse := new(BlueprintListResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) GetRuntimeEditables(ctx context.Context, bpUUID string) (*RuntimeEditablesResponse, error) {
path := fmt.Sprintf("/blueprints/%s/runtime_editables", bpUUID)

req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil)

appResponse := new(RuntimeEditablesResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}

func (op Operations) PatchApp(ctx context.Context, appUUID string, patchUUID string, input *PatchInput) (*AppPatchResponse, error) {
path := fmt.Sprintf("/apps/%s/patch/%s/run", appUUID, patchUUID)

req, err := op.client.NewRequest(ctx, http.MethodPost, path, input)

appResponse := new(AppPatchResponse)

if err != nil {
return nil, err
}

return appResponse, op.client.Do(ctx, req, appResponse)
}
174 changes: 174 additions & 0 deletions client/calm/calm_structs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package calm

import "encoding/json"

type BlueprintProvisionInput struct {
Spec BPspec `json:"spec,omitempty"`
}

type BPspec struct {
AppName string `json:"app_name,omitempty"`
AppDesc string `json:"app_description,omitempty"`
RuntimeEditables *RuntimeEditables `json:"runtime_editables,omitempty"`
AppProfileReference AppProfileReference `json:"app_profile_reference,omitempty"`
}

type AppProfileReference struct {
Kind string `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
UUID string `json:"uuid,omitempty"`
}

type AppProvisionTaskOutput struct {
AppName string `json:"app_name"`
AppDesc string `json:"app_description"`
Spec json.RawMessage `json:"spec"`
Status BpRespStatus `json:"status"`
}

type BlueprintResponse struct {
APIVersion *string `json:"api_version" mapstructure:"api_version"`

Spec json.RawMessage `json:"spec,omitempty" mapstructure:"spec,omitempty"`

Status BpRespStatus `json:"status,omitempty" mapstructure:"status,omitempty"`
}

type BpRespStatus struct {
RequestID string `json:"request_id,omitempty" mapstructure:"request_id,omitempty"`
}

type PollResponse struct {
Status PollStatus `json:"status,omitempty"`
APIVersion *string `json:"api_version,omitempty"`
}

type PollStatus struct {
AppUUID *string `json:"application_uuid,omitempty"`
AppName *string `json:"app_name,omitempty"`
State *string `json:"state,omitempty"`
BlueprintUUID *string `json:"bp_uuid,omitempty"`
BpName *string `json:"bp_name,omitempty"`
}

type DeleteAppResp struct {
Status DeleteAppStatus `json:"status"`
ApiVersion string `json:"api_version"`

Check failure on line 56 in client/calm/calm_structs.go

View workflow job for this annotation

GitHub Actions / tests

struct field `ApiVersion` should be `APIVersion` (golint)
}

type DeleteAppStatus struct {
RunlogUUID string `json:"runlog_uuid"`
ErgonTaskUUID string `json:"ergon_task_uuid"`
}

type AppResponse struct {
Status json.RawMessage `json:"status"`
Spec json.RawMessage `json:"spec"`
APIVersion string `json:"api_version"`
Metadata json.RawMessage `json:"metadata"`
}

type ActionSpec struct {
Name string `json:"name"`
// Spec *ActionPayload `json:"spec"`
// ApiVersion string `json:"api_version"`
// Metadata map[string]interface{} `json:"metadata"`
}

type AppActionResponse struct {
RunlogUUID string `json:"runlog_uuid"`
}

type AppRunlogsResponse struct {
APIVersion *string `json:"api_version"`
Status *AppRunlogStatus `json:"status"`
OutputList []*OutputList `json:"output_list"`
}

type AppRunlogStatus struct {
RunlogState *string `json:"runlog_state"`
ExitCode *int `json:"exit_code"`
}

type OutputList struct {
Output *string `json:"output"`
Script *string `json:"script"`
}

type BlueprintListInput struct {
Filter string `json:"filter"`
}

type BlueprintListResponse struct {
Entities json.RawMessage `json:"entities"`
}

// type ActionPayload struct {
// TargetUUID string `json:"target_uuid"`
// TargetKind string `json:"target_kind"`
// }

type RuntimeEditablesResponse struct {
Resources []*Resources `json:"resources"`
}

type Resources struct {
AppProfileReference *AppProfileReference `json:"app_profile_reference"`
RuntimeEditables *RuntimeEditables `json:"runtime_editables"`
}

type RuntimeEditables struct {
ActionList []*RuntimeSpec `json:"action_list,omitempty"`
ServiceList []*RuntimeSpec `json:"service_list,omitempty"`
CredentialList []*RuntimeSpec `json:"credential_list,omitempty"`
SubstrateList []*RuntimeSpec `json:"substrate_list,omitempty"`
PackageList []*RuntimeSpec `json:"package_list,omitempty"`
SnapshotConfifList []*RuntimeSpec `json:"snapshot_config_list,omitempty"`
AppProfile *RuntimeSpec `json:"app_profile,omitempty"`
TaskList []*RuntimeSpec `json:"task_list,omitempty"`
RestoreConfigList []*RuntimeSpec `json:"restore_config_list,omitempty"`
VariableList []*RuntimeSpec `json:"variable_list,omitempty"`
DeploymentList []*RuntimeSpec `json:"deployment_list,omitempty"`
}

type RuntimeSpec struct {
Description *string `json:"description,omitempty"`
Value *json.RawMessage `json:"value,omitempty"`
Name *string `json:"name,omitempty"`
Context *string `json:"context,omitempty"`
Type *string `json:"type,omitempty"`
UUID *string `json:"uuid,omitempty"`
}
type PatchInput struct {
Spec PatchSpec `json:"spec"`
APIVersion string `json:"api_version"`
Metadata map[string]interface{} `json:"metadata"`
}

type PatchSpec struct {
Args ArgsSpec `json:"args"`
TargetUUID string `json:"target_uuid"`
TargetKind string `json:"target_kind"`
}

type ArgsSpec struct {
Variables []*VariableList `json:"variables"`
Patch map[string]interface{} `json:"patch"`
}

type VariableList struct {
TaskUUID string `json:"task_uuid,omitempty"`
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
}

type AppPatchResponse struct {
Status ActionRunStatus `json:"status"`
Spec json.RawMessage `json:"spec"`
APIVersion string `json:"api_version"`
Metadata json.RawMessage `json:"metadata"`
}

type ActionRunStatus struct {
RunlogUUID string `json:"runlog_uuid"`
}
Loading

0 comments on commit 351c982

Please sign in to comment.