-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fastly/objectstorage): adds crud operations for access keys in o…
…bject storage
- Loading branch information
1 parent
a83e0ea
commit 951fe2d
Showing
14 changed files
with
600 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package accesskeys | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
) | ||
|
||
// CreateInput specifies the information needed for the Create() function to | ||
// perform the operation. | ||
type CreateInput struct { | ||
// Description is a description of the access key (required). | ||
Description *string `json:"description"` | ||
// Permission is the permissions the access key will have (required). | ||
Permission *string `json:"permission"` | ||
// Permission is the permissions the access key will have (required). | ||
Buckets *[]string `json:"buckets"` | ||
} | ||
|
||
// Create creates a new Object Storage Access Key. | ||
func Create(c *fastly.Client, i *CreateInput) (*AccessKey, error) { | ||
if i.Description == nil { | ||
return nil, fastly.ErrMissingDescription | ||
} | ||
|
||
if i.Permission == nil { | ||
return nil, fastly.ErrMissingPermission | ||
} | ||
|
||
if i.Buckets == nil { | ||
return nil, fastly.ErrMissingBuckets | ||
} | ||
|
||
resp, err := c.PostJSON("/resources/object-storage/access-keys", i, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
var accessKey *AccessKey | ||
if err := json.NewDecoder(resp.Body).Decode(&accessKey); err != nil { | ||
return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
} | ||
|
||
return accessKey, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package accesskeys | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
) | ||
|
||
// DeleteInput specifies the information needed for the Delete() function to | ||
// perform the operation. | ||
type DeleteInput struct { | ||
// ComputeACLID is an ACL Identifier (required). | ||
AccessKeyID *string | ||
} | ||
|
||
// DeleteAccessKey deletes an access key | ||
func Delete(c *fastly.Client, i *DeleteInput) error { | ||
if i.AccessKeyID == nil { | ||
return fastly.ErrMissingAccessKeyID | ||
} | ||
|
||
path := fastly.ToSafeURL("resources", "object-storage", "access-keys", *i.AccessKeyID) | ||
|
||
resp, err := c.Delete(path, nil) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusNoContent { | ||
return fastly.NewHTTPError(resp) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package accesskeys | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
) | ||
|
||
// GetInput specifies the information needed for the Get() function to perform | ||
// the operation. | ||
type GetInput struct { | ||
// accessKeyID is an AccessKey Identifier (required). | ||
AccessKeyID *string | ||
} | ||
|
||
// GetAccessKey finds an access key with the given ID if the user has the correct permisssions | ||
func Get(c *fastly.Client, i *GetInput) (*AccessKey, error) { | ||
if i.AccessKeyID == nil { | ||
return nil, fastly.ErrMissingAccessKeyID | ||
} | ||
|
||
path := fastly.ToSafeURL("resources", "object-storage", "access-keys", *i.AccessKeyID) | ||
|
||
resp, err := c.Get(path, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
// In the case that no matching Access Key was found, the API will return a 404 Not Found. This is not an error condition, rather a lack of results. | ||
if resp.StatusCode == http.StatusNotFound { | ||
return nil, nil | ||
} | ||
|
||
var entry *AccessKey | ||
if err := json.NewDecoder(resp.Body).Decode(&entry); err != nil { | ||
return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
} | ||
|
||
return entry, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package accesskeys | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
) | ||
|
||
// ListAccessKeys retrieves all acess keys within object storage that the token for this client has access to. | ||
func ListAccessKeys(c *fastly.Client) (*AccessKeys, error) { | ||
resp, err := c.Get("/resources/object-storage/access-keys", nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
var accessKeys *AccessKeys | ||
|
||
if err := json.NewDecoder(resp.Body).Decode(&accessKeys); err != nil { | ||
return nil, fmt.Errorf("failed to decode json response: %w", err) | ||
} | ||
|
||
return accessKeys, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package accesskeys | ||
|
||
// AccessKey is the API response structure for the create and describe operations. | ||
type AccessKey struct { | ||
// AccessKey is an AccessKey identifier. | ||
AccessKeyID string `json:"access_key"` | ||
// ComputeACLID is an ACL Identifier. | ||
Description string `json:"description"` | ||
// Permission is the permissions the key has | ||
Permission string `json:"permission"` | ||
// Buckets is the list of buckets associated with the access key | ||
Buckets []string `json:"buckets"` | ||
// CreatedAt is the timestamp associated with the creation of the access key | ||
CreatedAt string `json:"created_at"` | ||
} | ||
|
||
// AccessKeys is the API response structure for the list access keys operation. | ||
type AccessKeys struct { | ||
// Data is the list of returned cumpute ACLs. | ||
Data []AccessKey `json:"data"` | ||
// Meta is the information for total compute ACLs. | ||
Meta MetaAccessKeys `json:"meta"` | ||
} | ||
|
||
type MetaAccessKeys struct{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package accesskeys | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/fastly/go-fastly/v9/fastly" | ||
) | ||
|
||
func TestClient_AccessKey(t *testing.T) { | ||
t.Parallel() | ||
|
||
TestAccessKeyDescription := "THIS IS A TEST ACCESS KEY" | ||
TestAccessKeyPermission := "read-write-objects" | ||
TestAccessKeyBuckets := []string{"test-bucket"} | ||
|
||
var accessKeys *AccessKeys | ||
var err error | ||
|
||
// List all AccessKeys. | ||
fastly.Record(t, "list_accesskeys", func(c *fastly.Client) { | ||
accessKeys, err = ListAccessKeys(c) | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Make sure the test AccessKey we're going to create isn't among them. | ||
for _, ak := range accessKeys.Data { | ||
if ak.Description == TestAccessKeyDescription && | ||
ak.Permission == TestAccessKeyPermission && | ||
len(ak.Buckets) == len(TestAccessKeyBuckets) && | ||
ak.Buckets[0] == TestAccessKeyBuckets[0] { | ||
t.Errorf("found test AccessKey %q, aborting", ak.AccessKeyID) | ||
} | ||
} | ||
|
||
// Create a AccessKey for testing. | ||
var accessKey *AccessKey | ||
fastly.Record(t, "create_AccessKey", func(c *fastly.Client) { | ||
accessKey, err = Create(c, &CreateInput{ | ||
Description: fastly.ToPointer(TestAccessKeyDescription), | ||
Permission: fastly.ToPointer(TestAccessKeyPermission), | ||
Buckets: fastly.ToPointer(TestAccessKeyBuckets), | ||
}) | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if accessKey.Description != TestAccessKeyDescription { | ||
t.Errorf("unexpected AccessKey name: got %q, expected %q", accessKey.Description, TestAccessKeyDescription) | ||
} | ||
if accessKey.Permission != TestAccessKeyPermission { | ||
t.Errorf("unexpected AccessKey permission: got %q, expected %q", accessKey.Permission, TestAccessKeyPermission) | ||
} | ||
if len(accessKey.Buckets) != len(TestAccessKeyBuckets) { | ||
t.Errorf("unexpected AccessKey buckets length: got %q, expected %q", len(accessKey.Buckets), len(TestAccessKeyBuckets)) | ||
} | ||
if accessKey.Buckets[0] != TestAccessKeyBuckets[0] { | ||
t.Errorf("unexpected AccessKey bucket: got %q, expected %q", accessKey.Buckets[0], TestAccessKeyBuckets[0]) | ||
} | ||
|
||
// Ensure we delete the test AccessKey at the end. | ||
defer func() { | ||
fastly.Record(t, "delete_AccessKey", func(c *fastly.Client) { | ||
err = Delete(c, &DeleteInput{ | ||
AccessKeyID: fastly.ToPointer(accessKey.AccessKeyID), | ||
}) | ||
}) | ||
if err != nil { | ||
t.Errorf("error during AccessKey cleanup: %v", err) | ||
} | ||
}() | ||
|
||
// Get the test AccessKey. | ||
var ac *AccessKey | ||
fastly.Record(t, "get_AccessKey", func(c *fastly.Client) { | ||
ac, err = Get(c, &GetInput{ | ||
AccessKeyID: fastly.ToPointer(accessKey.AccessKeyID), | ||
}) | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if ac.Description != accessKey.Description { | ||
t.Errorf("unexpected AccessKey Description: got %q, expected %q", ac.Description, accessKey.Description) | ||
} | ||
if ac.Permission != accessKey.Permission { | ||
t.Errorf("unexpected AccessKey Permissions: got %q, expected %q", ac.Permission, accessKey.Permission) | ||
} | ||
if len(ac.Buckets) != len(accessKey.Buckets) { | ||
t.Errorf("unexpected AccessKey Buckets length: got %q, expected %q", len(ac.Buckets), len(accessKey.Buckets)) | ||
} | ||
if ac.Buckets[0] != accessKey.Buckets[0] { | ||
t.Errorf("unexpected AccessKey Buckets contents: got %q, expected %q", ac.Buckets[0], accessKey.Buckets[0]) | ||
} | ||
|
||
// List all entries of the test AccessKey and compare it to the input. | ||
var actualAccessKeys *AccessKeys | ||
fastly.Record(t, "list_accesskeys_with_new", func(c *fastly.Client) { | ||
actualAccessKeys, err = ListAccessKeys(c) | ||
}) | ||
if err != nil { | ||
t.Errorf("error fetching list of AccessKey entries: %v", err) | ||
} | ||
|
||
actualNumberOfAccessKeyEntries := len(actualAccessKeys.Data) | ||
expectedNumberOfAccessKeyEntries := len(accessKeys.Data) | ||
// This checks the original number of access keys fetched in the creation check vs the number fetched after adding the test key | ||
if actualNumberOfAccessKeyEntries != expectedNumberOfAccessKeyEntries+1 { | ||
t.Errorf("incorrect number of AccessKeys returned, expected: %d, got %d", expectedNumberOfAccessKeyEntries, actualNumberOfAccessKeyEntries) | ||
} | ||
|
||
// Make sure the test AccessKey we've created is among them. | ||
var newKeyPresent = false | ||
for _, rak := range actualAccessKeys.Data { | ||
if rak.Description == TestAccessKeyDescription && | ||
rak.Permission == TestAccessKeyPermission && | ||
len(rak.Buckets) == len(TestAccessKeyBuckets) && | ||
rak.Buckets[0] == TestAccessKeyBuckets[0] { | ||
newKeyPresent = true | ||
} | ||
} | ||
if !newKeyPresent { | ||
t.Errorf("missing test AccessKey %q, aborting", accessKey.AccessKeyID) | ||
} | ||
} | ||
|
||
// func TestClient_Create_validation(t *testing.T) { | ||
// _, err := Create(fastly.TestClient, &CreateInput{ | ||
// Name: nil, | ||
// }) | ||
// if err != fastly.ErrMissingName { | ||
// t.Errorf("expected ErrMissingName: got %s", err) | ||
// } | ||
// } | ||
|
||
// func TestClient_Describe_validation(t *testing.T) { | ||
// _, err := Describe(fastly.TestClient, &DescribeInput{ | ||
// AccessKeyID: nil, | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyID { | ||
// t.Errorf("expected ErrMissingAccessKeyID: got %s", err) | ||
// } | ||
// } | ||
|
||
// func TestClient_Delete_validation(t *testing.T) { | ||
// err := Delete(fastly.TestClient, &DeleteInput{ | ||
// AccessKeyID: nil, | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyID { | ||
// t.Errorf("expected ErrMissingAccessKeyID: got %s", err) | ||
// } | ||
// } | ||
|
||
// func TestClient_Lookup_validation(t *testing.T) { | ||
// var err error | ||
// _, err = Lookup(fastly.TestClient, &LookupInput{ | ||
// AccessKeyID: nil, | ||
// AccessKeyIP: fastly.ToPointer("1.2.3.4"), | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyID { | ||
// t.Errorf("expected ErrMissingAccessKeyID: got %s", err) | ||
// } | ||
|
||
// _, err = Lookup(fastly.TestClient, &LookupInput{ | ||
// AccessKeyID: fastly.ToPointer("foo"), | ||
// AccessKeyIP: nil, | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyIP { | ||
// t.Errorf("expected ErrMissingAccessKeyIP: got %s", err) | ||
// } | ||
// } | ||
|
||
// func TestClient_ListEntries_validation(t *testing.T) { | ||
// _, err := ListEntries(fastly.TestClient, &ListEntriesInput{ | ||
// AccessKeyID: nil, | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyID { | ||
// t.Errorf("expected ErrMissingAccessKeyID: got %s", err) | ||
// } | ||
// } | ||
|
||
// func TestClient_Update_validation(t *testing.T) { | ||
// err := Update(fastly.TestClient, &UpdateInput{ | ||
// AccessKeyID: nil, | ||
// }) | ||
// if err != fastly.ErrMissingAccessKeyID { | ||
// t.Errorf("expected ErrMissingAccessKeyID: got %s", err) | ||
// } | ||
// } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Package accesskeys contains subpackages which offer various operations to | ||
// configure access keys. | ||
package accesskeys |
Oops, something went wrong.