From 227f284b21d57ea410eadc114e0638b85c98e3bc Mon Sep 17 00:00:00 2001 From: Noah Fontes Date: Wed, 14 Jun 2023 13:59:07 -0700 Subject: [PATCH] Add support for reading state versions --- run.go | 1 + scalr.go | 2 + state_version.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 state_version.go diff --git a/run.go b/run.go index 4a40b64e..4f912d4a 100644 --- a/run.go +++ b/run.go @@ -79,6 +79,7 @@ type Run struct { Plan *Plan `jsonapi:"relation,plan"` PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"` Workspace *Workspace `jsonapi:"relation,workspace"` + StateVersions []*StateVersion `jsonapi:"relation,state-versions,omitempty"` } // RunCreateOptions represents the options for creating a new run. diff --git a/scalr.go b/scalr.go index fd967561..f623be84 100644 --- a/scalr.go +++ b/scalr.go @@ -140,6 +140,7 @@ type Client struct { ServiceAccountTokens ServiceAccountTokens ServiceAccounts ServiceAccounts SlackIntegrations SlackIntegrations + StateVersions StateVersions Tags Tags Teams Teams Users Users @@ -239,6 +240,7 @@ func NewClient(cfg *Config) (*Client, error) { client.ServiceAccountTokens = &serviceAccountTokens{client: client} client.ServiceAccounts = &serviceAccounts{client: client} client.SlackIntegrations = &slackIntegrations{client: client} + client.StateVersions = &stateVersions{client: client} client.Tags = &tags{client: client} client.Teams = &teams{client: client} client.Users = &users{client: client} diff --git a/state_version.go b/state_version.go new file mode 100644 index 00000000..6abe027c --- /dev/null +++ b/state_version.go @@ -0,0 +1,97 @@ +package scalr + +import ( + "context" + "errors" + "fmt" + "net/url" + "time" +) + +// Compile-time proof of interface implementation. +var _ StateVersions = (*stateVersions)(nil) + +type StateVersions interface { + // Read gets a state version resource from its ID. + Read(ctx context.Context, stateVersionID string) (*StateVersion, error) + + // ReadCurrentForWorkspace gets the current state version for a given + // workspace. + ReadCurrentForWorkspace(ctx context.Context, workspaceID string) (*StateVersion, error) +} + +// stateVersions implements StateVersions. +type stateVersions struct { + client *Client +} + +// StateVersionOutput describes a particular output of a state version. +type StateVersionOutput struct { + Name string `json:"name"` + Value interface{} `json:"value"` + Sensitive bool `json:"sensitive"` +} + +// StateVersionResource describes a resource in a state version. +type StateVersionResource struct { + Type string `json:"type"` + Module string `json:"module,omitempty"` + Address string `json:"address"` +} + +// StateVersion is a particular instance of Terraform state. +type StateVersion struct { + ID string `jsonapi:"primary,state-versions"` + Outputs []*StateVersionOutput `jsonapi:"attr,outputs"` + Resources []*StateVersionResource `jsonapi:"attr,resources"` + Force bool `jsonapi:"attr,force"` + Lineage string `jsonapi:"attr,lineage"` + MD5 string `jsonapi:"attr,md5"` + Serial int `jsonapi:"attr,serial"` + Size int `jsonapi:"attr,size"` + CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"` + + // Relations + Run *Run `jsonapi:"relation,run,omitempty"` + NextStateVersion *StateVersion `jsonapi:"relation,next-state-version,omitempty"` + PreviousStateVersion *StateVersion `jsonapi:"relation,previous-state-version,omitempty"` + Workspace *Workspace `jsonapi:"relation,workspace"` +} + +func (s *stateVersions) Read(ctx context.Context, stateVersionID string) (*StateVersion, error) { + if !validStringID(&stateVersionID) { + return nil, errors.New("invalid value for state version ID") + } + + u := fmt.Sprintf("state-versions/%s", url.PathEscape(stateVersionID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + sv := &StateVersion{} + if err := s.client.do(ctx, req, sv); err != nil { + return nil, err + } + + return sv, nil +} + +func (s *stateVersions) ReadCurrentForWorkspace(ctx context.Context, workspaceID string) (*StateVersion, error) { + if !validStringID(&workspaceID) { + return nil, errors.New("invalid value for workspace ID") + } + + u := fmt.Sprintf("workspaces/%s/current-state-version", url.PathEscape(workspaceID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + sv := &StateVersion{} + if err := s.client.do(ctx, req, sv); err != nil { + return nil, err + } + + return sv, nil +}