-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add checkout status endpoint * only return the available field if its checked in * order imports
- Loading branch information
1 parent
9ab3699
commit 79bda87
Showing
3 changed files
with
101 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 |
---|---|---|
|
@@ -16,6 +16,7 @@ func TestCheckOuts(t *testing.T) { | |
// Exercise all reserve endpoints. | ||
t.Run("write reserve", WriteReserve) | ||
t.Run("read reserve", ReadReserve) | ||
t.Run("read reserve status", ReadReserveStatus) | ||
t.Run("write conflicting reserve", WriteReserveWithConflictingServiceAccounts) | ||
t.Run("list reserves", ListReserves) | ||
t.Run("delete reserve", DeleteReserve) | ||
|
@@ -100,6 +101,28 @@ func ReadReserve(t *testing.T) { | |
} | ||
} | ||
|
||
func ReadReserveStatus(t *testing.T) { | ||
req := &logical.Request{ | ||
Operation: logical.ReadOperation, | ||
Path: libraryPrefix + "test-reserve/status", | ||
Storage: testStorage, | ||
} | ||
resp, err := testBackend.HandleRequest(ctx, req) | ||
if err != nil || (resp != nil && resp.IsError()) { | ||
t.Fatal(err) | ||
} | ||
if resp == nil { | ||
t.Fatal("expected a response") | ||
} | ||
if len(resp.Data) != 2 { | ||
t.Fatal("length should be 2 because there are two service accounts in this reserve") | ||
} | ||
testerStatus := resp.Data["[email protected]"].(map[string]interface{}) | ||
if !testerStatus["available"].(bool) { | ||
t.Fatal("should be available for checkout") | ||
} | ||
} | ||
|
||
func WriteReserveWithConflictingServiceAccounts(t *testing.T) { | ||
req := &logical.Request{ | ||
Operation: logical.CreateOperation, | ||
|
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,77 @@ | ||
package plugin | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/hashicorp/vault/sdk/framework" | ||
"github.com/hashicorp/vault/sdk/logical" | ||
) | ||
|
||
func (b *backend) pathReserveStatus() *framework.Path { | ||
return &framework.Path{ | ||
Pattern: libraryPrefix + framework.GenericNameRegex("name") + "/status$", | ||
Fields: map[string]*framework.FieldSchema{ | ||
"name": { | ||
Type: framework.TypeLowerCaseString, | ||
Description: "Name of the reserve", | ||
Required: true, | ||
}, | ||
}, | ||
Operations: map[logical.Operation]framework.OperationHandler{ | ||
logical.ReadOperation: &framework.PathOperation{ | ||
Callback: b.operationReserveStatus, | ||
Summary: "Check the status of the service accounts in a library reserve.", | ||
}, | ||
}, | ||
HelpSynopsis: `Check the status of the service accounts in a library.`, | ||
} | ||
} | ||
|
||
func (b *backend) operationReserveStatus(ctx context.Context, req *logical.Request, fieldData *framework.FieldData) (*logical.Response, error) { | ||
reserveName := fieldData.Get("name").(string) | ||
reserve, err := readReserve(ctx, req.Storage, reserveName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if reserve == nil { | ||
return logical.ErrorResponse(`"%s" doesn't exist`, reserveName), nil | ||
} | ||
respData := make(map[string]interface{}) | ||
for _, serviceAccountName := range reserve.ServiceAccountNames { | ||
checkOut, err := b.checkOutHandler.Status(ctx, req.Storage, serviceAccountName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if checkOut == nil { | ||
// This should never happen because for every service account, it should have | ||
// been checked in when it was first created. | ||
b.Logger().Warn(fmt.Sprintf("%s should have been checked in, but wasn't, checking it in now", serviceAccountName)) | ||
if err := b.checkOutHandler.CheckIn(ctx, req.Storage, serviceAccountName); err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
status := map[string]interface{}{ | ||
"available": checkOut.IsAvailable, | ||
} | ||
if checkOut.IsAvailable { | ||
// We only omit all other fields if the checkout is currently available, | ||
// because they're only relevant to accounts that aren't checked out. | ||
respData[serviceAccountName] = status | ||
continue | ||
} | ||
status["lending_period"] = int64(checkOut.LendingPeriod.Seconds()) | ||
status["due"] = checkOut.Due.Format(time.RFC3339Nano) | ||
if checkOut.BorrowerClientToken != "" { | ||
status["borrower_client_token"] = checkOut.BorrowerClientToken | ||
} else { | ||
status["borrower_entity_id"] = checkOut.BorrowerEntityID | ||
} | ||
respData[serviceAccountName] = status | ||
} | ||
return &logical.Response{ | ||
Data: respData, | ||
}, nil | ||
} |