package linodego import ( "context" "encoding/json" "fmt" "time" "github.com/go-resty/resty/v2" "github.com/linode/linodego/internal/parseabletime" ) // Stackscript represents a Linode StackScript type Stackscript struct { ID int `json:"id"` Username string `json:"username"` Label string `json:"label"` Description string `json:"description"` Ordinal int `json:"ordinal"` LogoURL string `json:"logo_url"` Images []string `json:"images"` DeploymentsTotal int `json:"deployments_total"` DeploymentsActive int `json:"deployments_active"` IsPublic bool `json:"is_public"` Mine bool `json:"mine"` Created *time.Time `json:"-"` Updated *time.Time `json:"-"` RevNote string `json:"rev_note"` Script string `json:"script"` UserDefinedFields *[]StackscriptUDF `json:"user_defined_fields"` UserGravatarID string `json:"user_gravatar_id"` } // StackscriptUDF define a single variable that is accepted by a Stackscript type StackscriptUDF struct { // A human-readable label for the field that will serve as the input prompt for entering the value during deployment. Label string `json:"label"` // The name of the field. Name string `json:"name"` // An example value for the field. Example string `json:"example"` // A list of acceptable single values for the field. OneOf string `json:"oneOf,omitempty"` // A list of acceptable values for the field in any quantity, combination or order. ManyOf string `json:"manyOf,omitempty"` // The default value. If not specified, this value will be used. Default string `json:"default,omitempty"` } // StackscriptCreateOptions fields are those accepted by CreateStackscript type StackscriptCreateOptions struct { Label string `json:"label"` Description string `json:"description"` Images []string `json:"images"` IsPublic bool `json:"is_public"` RevNote string `json:"rev_note"` Script string `json:"script"` } // StackscriptUpdateOptions fields are those accepted by UpdateStackscript type StackscriptUpdateOptions StackscriptCreateOptions // UnmarshalJSON implements the json.Unmarshaler interface func (i *Stackscript) UnmarshalJSON(b []byte) error { type Mask Stackscript p := struct { *Mask Created *parseabletime.ParseableTime `json:"created"` Updated *parseabletime.ParseableTime `json:"updated"` }{ Mask: (*Mask)(i), } if err := json.Unmarshal(b, &p); err != nil { return err } i.Created = (*time.Time)(p.Created) i.Updated = (*time.Time)(p.Updated) return nil } // GetCreateOptions converts a Stackscript to StackscriptCreateOptions for use in CreateStackscript func (i Stackscript) GetCreateOptions() StackscriptCreateOptions { return StackscriptCreateOptions{ Label: i.Label, Description: i.Description, Images: i.Images, IsPublic: i.IsPublic, RevNote: i.RevNote, Script: i.Script, } } // GetUpdateOptions converts a Stackscript to StackscriptUpdateOptions for use in UpdateStackscript func (i Stackscript) GetUpdateOptions() StackscriptUpdateOptions { return StackscriptUpdateOptions{ Label: i.Label, Description: i.Description, Images: i.Images, IsPublic: i.IsPublic, RevNote: i.RevNote, Script: i.Script, } } // StackscriptsPagedResponse represents a paginated Stackscript API response type StackscriptsPagedResponse struct { *PageOptions Data []Stackscript `json:"data"` } // endpoint gets the endpoint URL for Stackscript func (StackscriptsPagedResponse) endpoint(_ ...any) string { return "linode/stackscripts" } func (resp *StackscriptsPagedResponse) castResult(r *resty.Request, e string) (int, int, error) { res, err := coupleAPIErrors(r.SetResult(StackscriptsPagedResponse{}).Get(e)) if err != nil { return 0, 0, err } castedRes := res.Result().(*StackscriptsPagedResponse) resp.Data = append(resp.Data, castedRes.Data...) return castedRes.Pages, castedRes.Results, nil } // ListStackscripts lists Stackscripts func (c *Client) ListStackscripts(ctx context.Context, opts *ListOptions) ([]Stackscript, error) { response := StackscriptsPagedResponse{} err := c.listHelper(ctx, &response, opts) if err != nil { return nil, err } return response.Data, nil } // GetStackscript gets the Stackscript with the provided ID func (c *Client) GetStackscript(ctx context.Context, scriptID int) (*Stackscript, error) { e := fmt.Sprintf("linode/stackscripts/%d", scriptID) req := c.R(ctx).SetResult(&Stackscript{}) r, err := coupleAPIErrors(req.Get(e)) if err != nil { return nil, err } return r.Result().(*Stackscript), nil } // CreateStackscript creates a StackScript func (c *Client) CreateStackscript(ctx context.Context, opts StackscriptCreateOptions) (*Stackscript, error) { body, err := json.Marshal(opts) if err != nil { return nil, err } e := "linode/stackscripts" req := c.R(ctx).SetResult(&Stackscript{}).SetBody(string(body)) r, err := coupleAPIErrors(req.Post(e)) if err != nil { return nil, err } return r.Result().(*Stackscript), nil } // UpdateStackscript updates the StackScript with the specified id func (c *Client) UpdateStackscript(ctx context.Context, scriptID int, opts StackscriptUpdateOptions) (*Stackscript, error) { body, err := json.Marshal(opts) if err != nil { return nil, err } req := c.R(ctx).SetResult(&Stackscript{}).SetBody(string(body)) e := fmt.Sprintf("linode/stackscripts/%d", scriptID) r, err := coupleAPIErrors(req.Put(e)) if err != nil { return nil, err } return r.Result().(*Stackscript), nil } // DeleteStackscript deletes the StackScript with the specified id func (c *Client) DeleteStackscript(ctx context.Context, scriptID int) error { e := fmt.Sprintf("linode/stackscripts/%d", scriptID) _, err := coupleAPIErrors(c.R(ctx).Delete(e)) return err }