From 5af2dc6c3aaa2e26ec1f368345cf61a865eab904 Mon Sep 17 00:00:00 2001 From: Abner Garcia Date: Mon, 14 Feb 2022 14:30:08 -0700 Subject: [PATCH 1/3] added snapshot export jobs support --- .../cloud_provider_snapshot_export_jobs.go | 160 +++++++++++ ...loud_provider_snapshot_export_jobs_test.go | 259 ++++++++++++++++++ mongodbatlas/mongodbatlas.go | 2 + 3 files changed, 421 insertions(+) create mode 100644 mongodbatlas/cloud_provider_snapshot_export_jobs.go create mode 100644 mongodbatlas/cloud_provider_snapshot_export_jobs_test.go diff --git a/mongodbatlas/cloud_provider_snapshot_export_jobs.go b/mongodbatlas/cloud_provider_snapshot_export_jobs.go new file mode 100644 index 000000000..a76b1cd01 --- /dev/null +++ b/mongodbatlas/cloud_provider_snapshot_export_jobs.go @@ -0,0 +1,160 @@ +// Copyright 2022 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongodbatlas + +import ( + "context" + "fmt" + "net/http" +) + +const ( + cloudProviderSnapshotExportJobsPath = "api/atlas/v1.0/groups/%s/clusters/%s/backup/exports" +) + +// CloudProviderSnapshotExportJobsService is an interface for interfacing with the Cloud Provider Snapshots Export Jobs +// of the MongoDB Atlas API. +type CloudProviderSnapshotExportJobsService interface { + List(context.Context, string, string, *ListOptions) (*CloudProviderSnapshotExportJobs, *Response, error) + Get(context.Context, string, string, string) (*CloudProviderSnapshotExportJob, *Response, error) + Create(context.Context, string, string, *CloudProviderSnapshotExportJob) (*CloudProviderSnapshotExportJob, *Response, error) +} + +// CloudProviderSnapshotExportJobsServiceOp handles communication with the CloudProviderSnapshotExportJobsService related methods of the +// MongoDB Atlas API. +type CloudProviderSnapshotExportJobsServiceOp service + +// List Retrieve all the export jobs for the specified project. +// +// See more: https://docs.atlas.mongodb.com/reference/api/cloud-backup/export/get-all-export-jobs/ +func (c CloudProviderSnapshotExportJobsServiceOp) List(ctx context.Context, projectID, clusterName string, options *ListOptions) (*CloudProviderSnapshotExportJobs, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + + path := fmt.Sprintf(cloudProviderSnapshotExportJobsPath, projectID, clusterName) + + path, err := setListOptions(path, options) + if err != nil { + return nil, nil, err + } + + req, err := c.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(CloudProviderSnapshotExportJobs) + resp, err := c.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + if l := root.Links; l != nil { + resp.Links = l + } + + return root, resp, nil +} + +// Get Allows you to retrieve one export job specified by the bucket ID. +// +// See more: https://docs.atlas.mongodb.com/reference/api/cloud-backup/export/get-one-export-job/ +func (c CloudProviderSnapshotExportJobsServiceOp) Get(ctx context.Context, projectID, clusterName, bucketID string) (*CloudProviderSnapshotExportJob, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + if bucketID == "" { + return nil, nil, NewArgError("bucketID", "must be set") + } + + path := fmt.Sprintf("api/atlas/v1.0/groups/%s/clusters/%s/backup/exports/%s", projectID, clusterName, bucketID) + + req, err := c.Client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, nil, err + } + + root := new(CloudProviderSnapshotExportJob) + resp, err := c.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} + +// Create Allows you to grant Atlas access to the specified export job for exporting backup snapshots. +// +// See more: https://docs.atlas.mongodb.com/reference/api/cloud-backup/export/create-one-export-job/ +func (c CloudProviderSnapshotExportJobsServiceOp) Create(ctx context.Context, projectID, clusterName string, bucket *CloudProviderSnapshotExportJob) (*CloudProviderSnapshotExportJob, *Response, error) { + if projectID == "" { + return nil, nil, NewArgError("projectID", "must be set") + } + + path := fmt.Sprintf(cloudProviderSnapshotExportJobsPath, projectID, clusterName) + + req, err := c.Client.NewRequest(ctx, http.MethodPost, path, bucket) + if err != nil { + return nil, nil, err + } + + root := new(CloudProviderSnapshotExportJob) + resp, err := c.Client.Do(ctx, req, root) + if err != nil { + return nil, resp, err + } + + return root, resp, err +} + +var _ CloudProviderSnapshotExportJobsService = &CloudProviderSnapshotExportJobsServiceOp{} + +// CloudProviderSnapshotExportJobs represents all cloud provider snapshot export jobs. +type CloudProviderSnapshotExportJobs struct { + Results []*CloudProviderSnapshotExportJob `json:"results,omitempty"` // Includes one CloudProviderSnapshotExportJob object for each item detailed in the results array section. + Links []*Link `json:"links,omitempty"` // One or more links to sub-resources and/or related resources. + TotalCount int `json:"totalCount,omitempty"` // Count of the total number of items in the result set. It may be greater than the number of objects in the results array if the entire result set is paginated. +} + +type CloudProviderSnapshotExportJobComponent struct { + ExportID string `json:"exportID,omitempty"` // Returned for sharded clusters only. Unique identifier of the export job for the replica set. + ReplicaSetName string `json:"replicaSetName,omitempty"` // Returned for sharded clusters only. Name of the replica set. +} + +type CloudProviderSnapshotExportJobCustomData struct { + Key string `json:"key,omitempty"` // Custom data specified as key in the key and value pair. + Value string `json:"value,omitempty"` // Value for the key specified using CloudProviderSnapshotExportJobCustomData.key. +} + +type CloudProviderSnapshotExportJobStatus struct { + ExportedCollections int `json:"exportedCollections,omitempty"` // Returned for replica set only. Number of collections that have been exported. + TotalCollections int `json:"totalCollections,omitempty"` // Returned for replica set only. Total number of collections to export. +} + +// CloudProviderSnapshotExportJob represents one cloud provider snapshot export jobs. +type CloudProviderSnapshotExportJob struct { + ID string `json:"id,omitempty"` // Unique identifier of the export job. + Components []*CloudProviderSnapshotExportJobComponent `json:"components,omitempty"` // Returned for sharded clusters only. Export job details for each replica set in the sharded cluster. + CreatedAt string `json:"createdAt,omitempty"` // Timestamp in ISO 8601 date and time format in UTC when the export job was created. + CustomData []*CloudProviderSnapshotExportJobCustomData `json:"customData,omitempty"` // Custom data for the metadata file named .complete that Atlas uploads to the bucket when the export job finishes. + ErrMsg string `json:"errMsg,omitempty"` // Error message, only if the export job failed. + ExportBucketID string `json:"exportBucketId,omitempty"` // Unique identifier of the bucket. + ExportStatus *CloudProviderSnapshotExportJobStatus `json:"exportStatus,omitempty"` // Returned for replica set only. Status of the export job. + FinishedAt string `json:"finishedAt,omitempty"` // Timestamp in ISO 8601 date and time format in UTC when the export job completes. + Prefix string `json:"prefix,omitempty"` // Full path on the cloud provider bucket to the folder where the snapshot is exported. The path is in the following format: /exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/{SNAPSHOT-INITIATION-DATE}/{TIMESTAMP} + SnapshotID string `json:"snapshotID,omitempty"` // Unique identifier of the snapshot. + State string `json:"state,omitempty"` // Status of the export job. +} diff --git a/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go b/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go new file mode 100644 index 000000000..9ed7cdccd --- /dev/null +++ b/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go @@ -0,0 +1,259 @@ +// Copyright 2021 MongoDB Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mongodbatlas + +import ( + "fmt" + "net/http" + "testing" + + "github.com/go-test/deep" +) + +func TestCloudProviderSnapshotExportJobs_List(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + projectID := "test-project-id" + clusterName := "test-cluster-name" + + path := fmt.Sprintf("/api/atlas/v1.0/groups/%s/clusters/%s/backup/exports", projectID, clusterName) + + mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "links": [ + { + "href": "https://cloud.mongodb.com/api/atlas/v1.0/groups/{GROUP-ID}/clusters/{CLUSTER-NAME}/backup/exports/?pageNum=1&itemsPerPage=100", + "rel": "self" + } + ], + "results": [ + { + "components": [ + { + "exportId": "60675896c37241327a557130", + "replicaSetName": "atlas-xxxxxx-shard-0" + }, + { + "exportId": "60675896c37241327a557132", + "replicaSetName": "atlas-wnvwfd-shard-1" + } + ], + "createdAt": "2021-04-02T17:47:02Z", + "customData": [], + "exportBucketId": "{BUCKET-ID}", + "id": "60675896c37241327a55712f", + "prefix": "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-04-02T1742/1617385622", + "snapshotId": "{SNAPSHOT-ID}", + "state": "Queued" + }, + { + "components": [ + { + "exportId": "606758180d97065aabbe5b86", + "replicaSetName": "atlas-xxxxxx-shard-0" + }, + { + "exportId": "606758180d97065aabbe5b88", + "replicaSetName": "atlas-xxxxxx-shard-1" + } + ], + "createdAt": "2021-04-02T17:44:56Z", + "customData": [], + "exportBucketId": "{BUCKET-ID}", + "id": "606758180d97065aabbe5b85", + "prefix": "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-04-02T1742/1617385496", + "snapshotId": "{SNAPSHOT-ID}", + "state": "Successful" + } + ], + "totalCount": 2 +}`) + }) + + cloudProviderSnapshots, _, err := client.CloudProviderSnapshotExportJobs.List(ctx, projectID, clusterName, nil) + if err != nil { + t.Fatalf("CloudProviderSnapshotExportJobs.List returned error: %v", err) + } + + expected := &CloudProviderSnapshotExportJobs{ + Links: []*Link{ + { + Href: "https://cloud.mongodb.com/api/atlas/v1.0/groups/{GROUP-ID}/clusters/{CLUSTER-NAME}/backup/exports/?pageNum=1&itemsPerPage=100", + Rel: "self", + }, + }, + Results: []*CloudProviderSnapshotExportJob{ + { + Components: []*CloudProviderSnapshotExportJobComponent{ + { + ExportID: "60675896c37241327a557130", + ReplicaSetName: "atlas-xxxxxx-shard-0", + }, + { + ExportID: "60675896c37241327a557132", + ReplicaSetName: "atlas-wnvwfd-shard-1", + }, + }, + CreatedAt: "2021-04-02T17:47:02Z", + CustomData: []*CloudProviderSnapshotExportJobCustomData{}, + ExportBucketID: "{BUCKET-ID}", + ID: "60675896c37241327a55712f", + Prefix: "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-04-02T1742/1617385622", + SnapshotID: "{SNAPSHOT-ID}", + State: "Queued", + }, + { + Components: []*CloudProviderSnapshotExportJobComponent{ + { + ExportID: "606758180d97065aabbe5b86", + ReplicaSetName: "atlas-xxxxxx-shard-0", + }, + { + ExportID: "606758180d97065aabbe5b88", + ReplicaSetName: "atlas-xxxxxx-shard-1", + }, + }, + CreatedAt: "2021-04-02T17:44:56Z", + CustomData: []*CloudProviderSnapshotExportJobCustomData{}, + ExportBucketID: "{BUCKET-ID}", + ID: "606758180d97065aabbe5b85", + Prefix: "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-04-02T1742/1617385496", + SnapshotID: "{SNAPSHOT-ID}", + State: "Successful", + }, + }, + TotalCount: 2, + } + + if diff := deep.Equal(cloudProviderSnapshots, expected); diff != nil { + t.Error(diff) + } +} + +func TestCloudProviderSnapshotExportJobs_Get(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + projectID := "test-project-id" + clusterName := "test-cluster-name" + exportJobID := "job-id-test" + + path := fmt.Sprintf("/api/atlas/v1.0/groups/%s/clusters/%s/backup/exports/%s", projectID, clusterName, exportJobID) + + mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + fmt.Fprint(w, `{ + "createdAt": "2021-03-25T16:49:23Z", + "exportBucketId": "{BUCKET-ID}", + "finishedAt": "2021-03-25T17:48:20Z", + "id": "605ccba3c1c7613f423e1585", + "prefix": "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-03-25T1649+0000/1616694179", + "snapshotId": "605cbac9b498841007af7d9f", + "state": "Successful" +}`) + }) + + cloudProviderSnapshotBucket, _, err := client.CloudProviderSnapshotExportJobs.Get(ctx, projectID, clusterName, exportJobID) + if err != nil { + t.Fatalf("CloudProviderSnapshotExportJobs.Get returned error: %v", err) + } + + expected := &CloudProviderSnapshotExportJob{ + CreatedAt: "2021-03-25T16:49:23Z", + ExportBucketID: "{BUCKET-ID}", + FinishedAt: "2021-03-25T17:48:20Z", + ID: "605ccba3c1c7613f423e1585", + Prefix: "/exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/2021-03-25T1649+0000/1616694179", + SnapshotID: "605cbac9b498841007af7d9f", + State: "Successful", + } + + if diff := deep.Equal(cloudProviderSnapshotBucket, expected); diff != nil { + t.Error(diff) + } +} + +func TestCloudProviderSnapshotExportJobs_Create(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + projectID := "test-project-id" + clusterName := "test-cluster-name" + + createRequest := &CloudProviderSnapshotExportJob{ + SnapshotID: "{SNAPSHOT-ID}", + ExportBucketID: "{BUCKET-ID}", + CustomData: []*CloudProviderSnapshotExportJobCustomData{ + { + Key: "exported by", + Value: "myName", + }, + }, + } + + path := fmt.Sprintf("/api/atlas/v1.0/groups/%s/clusters/%s/backup/exports", projectID, clusterName) + + mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + + fmt.Fprint(w, `{ + "createdAt": "2021-05-04T14:43:40Z", + "customData": [ + { + "key": "exported by", + "value": "myName" + } + ], + "exportBucketId": "604f6322dc786a5341d4f7fb", + "exportStatus": { + "exportedCollections": 0, + "totalCollections": 0 + }, + "id": "60915d9cef8ca80cd31646e5", + "prefix": "exported_snapshots/KS+Sandbox/mySbx/testCluster/2021-03-27T1409/1620139419", + "snapshotId": "605f3bdf16d634087d0e15ce", + "state": "Queued" +}`) + }) + + cloudProviderSnapshot, _, err := client.CloudProviderSnapshotExportJobs.Create(ctx, projectID, clusterName, createRequest) + if err != nil { + t.Fatalf("CloudProviderSnapshotExportBuckets.Create returned error: %v", err) + } + + expected := &CloudProviderSnapshotExportJob{ + CreatedAt: "2021-05-04T14:43:40Z", + ExportBucketID: "604f6322dc786a5341d4f7fb", + CustomData: []*CloudProviderSnapshotExportJobCustomData{ + { + Key: "exported by", + Value: "myName", + }, + }, + ExportStatus: &CloudProviderSnapshotExportJobStatus{ + ExportedCollections: 0, + TotalCollections: 0, + }, + ID: "60915d9cef8ca80cd31646e5", + Prefix: "exported_snapshots/KS+Sandbox/mySbx/testCluster/2021-03-27T1409/1620139419", + SnapshotID: "605f3bdf16d634087d0e15ce", + State: "Queued", + } + + if diff := deep.Equal(cloudProviderSnapshot, expected); diff != nil { + t.Error(diff) + } +} diff --git a/mongodbatlas/mongodbatlas.go b/mongodbatlas/mongodbatlas.go index 0da837232..7884d3cfb 100644 --- a/mongodbatlas/mongodbatlas.go +++ b/mongodbatlas/mongodbatlas.go @@ -141,6 +141,7 @@ type Client struct { AccessTracking AccessTrackingService ServiceVersion ServiceVersionService CloudProviderSnapshotExportBuckets CloudProviderSnapshotExportBucketsService + CloudProviderSnapshotExportJobs CloudProviderSnapshotExportJobsService onRequestCompleted RequestCompletionCallback } @@ -282,6 +283,7 @@ func NewClient(httpClient *http.Client) *Client { c.AccessTracking = &AccessTrackingServiceOp{Client: c} c.ServiceVersion = &ServiceVersionServiceOp{Client: c} c.CloudProviderSnapshotExportBuckets = &CloudProviderSnapshotExportBucketsServiceOp{Client: c} + c.CloudProviderSnapshotExportJobs = &CloudProviderSnapshotExportJobsServiceOp{Client: c} return c } From 1f6b505fdbfb80ffa37f699ff192aa808502200d Mon Sep 17 00:00:00 2001 From: Abner Garcia Date: Mon, 14 Feb 2022 14:33:18 -0700 Subject: [PATCH 2/3] fix lint --- mongodbatlas/cloud_provider_snapshot_export_jobs.go | 2 +- mongodbatlas/cloud_provider_snapshot_export_jobs_test.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mongodbatlas/cloud_provider_snapshot_export_jobs.go b/mongodbatlas/cloud_provider_snapshot_export_jobs.go index a76b1cd01..04cc146cb 100644 --- a/mongodbatlas/cloud_provider_snapshot_export_jobs.go +++ b/mongodbatlas/cloud_provider_snapshot_export_jobs.go @@ -152,7 +152,7 @@ type CloudProviderSnapshotExportJob struct { CustomData []*CloudProviderSnapshotExportJobCustomData `json:"customData,omitempty"` // Custom data for the metadata file named .complete that Atlas uploads to the bucket when the export job finishes. ErrMsg string `json:"errMsg,omitempty"` // Error message, only if the export job failed. ExportBucketID string `json:"exportBucketId,omitempty"` // Unique identifier of the bucket. - ExportStatus *CloudProviderSnapshotExportJobStatus `json:"exportStatus,omitempty"` // Returned for replica set only. Status of the export job. + ExportStatus *CloudProviderSnapshotExportJobStatus `json:"exportStatus,omitempty"` // Returned for replica set only. Status of the export job. FinishedAt string `json:"finishedAt,omitempty"` // Timestamp in ISO 8601 date and time format in UTC when the export job completes. Prefix string `json:"prefix,omitempty"` // Full path on the cloud provider bucket to the folder where the snapshot is exported. The path is in the following format: /exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/{SNAPSHOT-INITIATION-DATE}/{TIMESTAMP} SnapshotID string `json:"snapshotID,omitempty"` // Unique identifier of the snapshot. diff --git a/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go b/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go index 9ed7cdccd..bb88a773b 100644 --- a/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go +++ b/mongodbatlas/cloud_provider_snapshot_export_jobs_test.go @@ -208,7 +208,6 @@ func TestCloudProviderSnapshotExportJobs_Create(t *testing.T) { path := fmt.Sprintf("/api/atlas/v1.0/groups/%s/clusters/%s/backup/exports", projectID, clusterName) mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `{ "createdAt": "2021-05-04T14:43:40Z", "customData": [ From 474b64bbd7688a333cf0b3f8924dba97a8fdcee4 Mon Sep 17 00:00:00 2001 From: Abner Garcia Date: Tue, 15 Feb 2022 09:53:38 -0700 Subject: [PATCH 3/3] fix issues --- .../cloud_provider_snapshot_export_jobs.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mongodbatlas/cloud_provider_snapshot_export_jobs.go b/mongodbatlas/cloud_provider_snapshot_export_jobs.go index 04cc146cb..8d0b5eaa6 100644 --- a/mongodbatlas/cloud_provider_snapshot_export_jobs.go +++ b/mongodbatlas/cloud_provider_snapshot_export_jobs.go @@ -44,6 +44,10 @@ func (c CloudProviderSnapshotExportJobsServiceOp) List(ctx context.Context, proj return nil, nil, NewArgError("projectID", "must be set") } + if clusterName == "" { + return nil, nil, NewArgError("clusterName", "must be set") + } + path := fmt.Sprintf(cloudProviderSnapshotExportJobsPath, projectID, clusterName) path, err := setListOptions(path, options) @@ -76,6 +80,9 @@ func (c CloudProviderSnapshotExportJobsServiceOp) Get(ctx context.Context, proje if projectID == "" { return nil, nil, NewArgError("projectID", "must be set") } + if clusterName == "" { + return nil, nil, NewArgError("clusterName", "must be set") + } if bucketID == "" { return nil, nil, NewArgError("bucketID", "must be set") } @@ -103,6 +110,9 @@ func (c CloudProviderSnapshotExportJobsServiceOp) Create(ctx context.Context, pr if projectID == "" { return nil, nil, NewArgError("projectID", "must be set") } + if clusterName == "" { + return nil, nil, NewArgError("clusterName", "must be set") + } path := fmt.Sprintf(cloudProviderSnapshotExportJobsPath, projectID, clusterName) @@ -130,7 +140,7 @@ type CloudProviderSnapshotExportJobs struct { } type CloudProviderSnapshotExportJobComponent struct { - ExportID string `json:"exportID,omitempty"` // Returned for sharded clusters only. Unique identifier of the export job for the replica set. + ExportID string `json:"exportId,omitempty"` // Returned for sharded clusters only. Unique identifier of the export job for the replica set. ReplicaSetName string `json:"replicaSetName,omitempty"` // Returned for sharded clusters only. Name of the replica set. } @@ -155,6 +165,6 @@ type CloudProviderSnapshotExportJob struct { ExportStatus *CloudProviderSnapshotExportJobStatus `json:"exportStatus,omitempty"` // Returned for replica set only. Status of the export job. FinishedAt string `json:"finishedAt,omitempty"` // Timestamp in ISO 8601 date and time format in UTC when the export job completes. Prefix string `json:"prefix,omitempty"` // Full path on the cloud provider bucket to the folder where the snapshot is exported. The path is in the following format: /exported_snapshots/{ORG-NAME}/{PROJECT-NAME}/{CLUSTER-NAME}/{SNAPSHOT-INITIATION-DATE}/{TIMESTAMP} - SnapshotID string `json:"snapshotID,omitempty"` // Unique identifier of the snapshot. + SnapshotID string `json:"snapshotId,omitempty"` // Unique identifier of the snapshot. State string `json:"state,omitempty"` // Status of the export job. }