Skip to content

Commit

Permalink
Merge pull request #338 from hashicorp/mpminardi/archive-config-versions
Browse files Browse the repository at this point in the history
Add new states and endpoint for configuration version archiving
  • Loading branch information
mpminardi committed Mar 16, 2022
2 parents fc4c887 + 9a3dbab commit 6590bf1
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 0 deletions.
26 changes: 26 additions & 0 deletions configuration_version.go
Expand Up @@ -39,6 +39,10 @@ type ConfigurationVersions interface {
// the upload URL from a configuration version and the full path to the
// configuration files on disk.
Upload(ctx context.Context, url string, path string) error

// Archive a configuration version. This can only be done on configuration versions that
// were created with the API or CLI, are in an uploaded state, and have no runs in progress.
Archive(ctx context.Context, cvID string) error
}

// configurationVersions implements ConfigurationVersions.
Expand All @@ -51,7 +55,9 @@ type ConfigurationStatus string

// List all available configuration version statuses.
const (
ConfigurationArchived ConfigurationStatus = "archived"
ConfigurationErrored ConfigurationStatus = "errored"
ConfigurationFetching ConfigurationStatus = "fetching"
ConfigurationPending ConfigurationStatus = "pending"
ConfigurationUploaded ConfigurationStatus = "uploaded"
)
Expand Down Expand Up @@ -95,6 +101,8 @@ type ConfigurationVersion struct {
// CVStatusTimestamps holds the timestamps for individual configuration version
// statuses.
type CVStatusTimestamps struct {
ArchivedAt time.Time `jsonapi:"attr,archived-at,rfc3339"`
FetchingAt time.Time `jsonapi:"attr,fetching-at,rfc3339"`
FinishedAt time.Time `jsonapi:"attr,finished-at,rfc3339"`
QueuedAt time.Time `jsonapi:"attr,queued-at,rfc3339"`
StartedAt time.Time `jsonapi:"attr,started-at,rfc3339"`
Expand Down Expand Up @@ -274,6 +282,24 @@ func (s *configurationVersions) Upload(ctx context.Context, u, path string) erro
return s.client.do(ctx, req, nil)
}

// Archive a configuration version. This can only be done on configuration versions that
// were created with the API or CLI, are in an uploaded state, and have no runs in progress.
func (s *configurationVersions) Archive(ctx context.Context, cvID string) error {
if !validStringID(&cvID) {
return ErrInvalidConfigVersionID
}

body := bytes.NewBuffer(nil)

u := fmt.Sprintf("configuration-versions/%s/actions/archive", url.QueryEscape(cvID))
req, err := s.client.newRequest("POST", u, body)
if err != nil {
return err
}

return s.client.do(ctx, req, nil)
}

func (o *ConfigurationVersionReadOptions) valid() error {
if o == nil {
return nil // nothing to validate
Expand Down
64 changes: 64 additions & 0 deletions configuration_version_integration_test.go
Expand Up @@ -237,6 +237,70 @@ func TestConfigurationVersionsUpload(t *testing.T) {
})
}

func TestConfigurationVersionsArchive(t *testing.T) {
client := testClient(t)
ctx := context.Background()

cv, cvCleanup := createConfigurationVersion(t, client, nil)
defer cvCleanup()

t.Run("when the configuration version exists and has been uploaded", func(t *testing.T) {
err := client.ConfigurationVersions.Upload(
ctx,
cv.UploadURL,
"test-fixtures/config-version",
)
require.NoError(t, err)

// We do this is a small loop, because it can take a second
// before the upload is finished.
for i := 0; ; i++ {
refreshed, err := client.ConfigurationVersions.Read(ctx, cv.ID)
require.NoError(t, err)

if refreshed.Status == ConfigurationUploaded {
break
}

if i > 10 {
t.Fatal("Timeout waiting for the configuration version to be uploaded")
}

time.Sleep(1 * time.Second)
}

err = client.ConfigurationVersions.Archive(ctx, cv.ID)
require.NoError(t, err)

// We do this is a small loop, because it can take a second
// before the archive is finished.
for i := 0; ; i++ {
refreshed, err := client.ConfigurationVersions.Read(ctx, cv.ID)
require.NoError(t, err)

if refreshed.Status == ConfigurationArchived {
break
}

if i > 10 {
t.Fatal("Timeout waiting for the configuration version to be archived")
}

time.Sleep(1 * time.Second)
}
})

t.Run("when the configuration version does not exist", func(t *testing.T) {
err := client.ConfigurationVersions.Archive(ctx, "nonexisting")
assert.Equal(t, err, ErrResourceNotFound)
})

t.Run("with invalid configuration version id", func(t *testing.T) {
err := client.ConfigurationVersions.Archive(ctx, badIdentifier)
assert.EqualError(t, err, ErrInvalidConfigVersionID.Error())
})
}

func TestConfigurationVersions_Unmarshal(t *testing.T) {
data := map[string]interface{}{
"data": map[string]interface{}{
Expand Down
14 changes: 14 additions & 0 deletions mocks/configuration_version_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions run.go
Expand Up @@ -59,6 +59,7 @@ const (
RunCostEstimating RunStatus = "cost_estimating"
RunDiscarded RunStatus = "discarded"
RunErrored RunStatus = "errored"
RunFetching RunStatus = "fetching"
RunPending RunStatus = "pending"
RunPlanQueued RunStatus = "plan_queued"
RunPlanned RunStatus = "planned"
Expand Down Expand Up @@ -148,6 +149,8 @@ type RunStatusTimestamps struct {
CostEstimatingAt time.Time `jsonapi:"attr,cost-estimating-at,rfc3339"`
DiscardedAt time.Time `jsonapi:"attr,discarded-at,rfc3339"`
ErroredAt time.Time `jsonapi:"attr,errored-at,rfc3339"`
FetchedAt time.Time `jsonapi:"attr,fetched-at,rfc3339"`
FetchingAt time.Time `jsonapi:"attr,fetching-at,rfc3339"`
ForceCanceledAt time.Time `jsonapi:"attr,force-canceled-at,rfc3339"`
PlanQueueableAt time.Time `jsonapi:"attr,plan-queueable-at,rfc3339"`
PlanQueuedAt time.Time `jsonapi:"attr,plan-queued-at,rfc3339"`
Expand Down

0 comments on commit 6590bf1

Please sign in to comment.