Skip to content

Commit

Permalink
Refactor + more RDE Type behavior methods. Tests pass
Browse files Browse the repository at this point in the history
Signed-off-by: abarreiro <abarreiro@vmware.com>
  • Loading branch information
abarreiro committed Jun 30, 2023
1 parent ffd4f1e commit 1b33343
Show file tree
Hide file tree
Showing 6 changed files with 398 additions and 361 deletions.
94 changes: 94 additions & 0 deletions govcd/defined_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,100 @@ func (rdeType *DefinedEntityType) Delete() error {
return nil
}

// GetAllBehaviors retrieves all the Behaviors of the receiver RDE Type. Query parameters can be supplied to modify pagination.
func (rdeType *DefinedEntityType) GetAllBehaviors(queryParameters url.Values) ([]*types.Behavior, error) {
if rdeType.DefinedEntityType.ID == "" {
return nil, fmt.Errorf("ID of the receiver Defined Entity Type is empty")
}
return getAllBehaviors(rdeType.client, rdeType.DefinedEntityType.ID, types.OpenApiEndpointRdeTypeBehaviors, queryParameters)
}

// GetBehaviorById retrieves a unique Behavior that belongs to the receiver RDE Type and is determined by the
// input ID.
func (rdeType *DefinedEntityType) GetBehaviorById(id string) (*types.Behavior, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeTypeBehaviors
apiVersion, err := rdeType.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := rdeType.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, rdeType.DefinedEntityType.ID), id)
if err != nil {
return nil, err
}

response := types.Behavior{}
err = rdeType.client.OpenApiGetItem(apiVersion, urlRef, nil, &response, nil)
if err != nil {
return nil, err
}

return &response, nil
}

// GetBehaviorByName retrieves a unique Behavior that belongs to the receiver RDE Type and is named after
// the input.
func (rdeType *DefinedEntityType) GetBehaviorByName(name string) (*types.Behavior, error) {
behaviors, err := rdeType.GetAllBehaviors(nil)
if err != nil {
return nil, fmt.Errorf("could not get the Behaviors of the RDE Type with ID '%s': %s", rdeType.DefinedEntityType.ID, err)
}
for _, b := range behaviors {
if b.Name == name {
return b, nil
}
}
return nil, fmt.Errorf("could not find any Behavior with name '%s' in RDE Type with ID '%s': %s", name, rdeType.DefinedEntityType.ID, ErrorEntityNotFound)
}

// AddBehaviorAccessControl adds a new Behavior to the receiver DefinedInterface.
// Only allowed if the Interface is not in use.
func (det *DefinedEntityType) AddBehaviorAccessControl(ac types.BehaviorAccess) error {
if det.DefinedEntityType.ID == "" {
return fmt.Errorf("ID of the receiver Defined Entity Type is empty")
}

endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeTypeBehaviorAccessControls
apiVersion, err := det.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return err
}

urlRef, err := det.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, det.DefinedEntityType.ID))
if err != nil {
return err
}

err = det.client.OpenApiPostItem(apiVersion, urlRef, nil, ac, nil, nil)
if err != nil {
return err
}

return nil
}

// GetAllBehaviorsAccessControls gets all the Behaviors Access Controls from the receiver DefinedEntityType. Query parameters can be supplied to modify pagination.
func (det *DefinedEntityType) GetAllBehaviorsAccessControls(queryParameters url.Values) ([]*types.BehaviorAccess, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeTypeBehaviorAccessControls
apiVersion, err := det.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := det.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, det.DefinedEntityType.ID))
if err != nil {
return nil, err
}

typeResponses := []*types.BehaviorAccess{{}}
err = det.client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil)
if err != nil {
return nil, err
}

return typeResponses, nil
}

// GetAllRdes gets all the RDE instances of the given vendor, nss and version.
func (vcdClient *VCDClient) GetAllRdes(vendor, nss, version string, queryParameters url.Values) ([]*DefinedEntity, error) {
return getAllRdes(&vcdClient.Client, vendor, nss, version, queryParameters)
Expand Down
67 changes: 67 additions & 0 deletions govcd/defined_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,70 @@ func loadRdeTypeSchemaFromTestResources() (map[string]interface{}, error) {

return unmarshaledJson, nil
}

// Test_RdeTypeBehavior tests the CRUD methods of RDE Types to create Behaviors, as a System administrator and tenant user.
// This test can be run with GOVCD_SKIP_VAPP_CREATION option enabled.
func (vcd *TestVCD) Test_RdeTypeBehavior(check *C) {
if vcd.skipAdminTests {
check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName()))
}
skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeTypeBehaviors)

// Create a new RDE Type from scratch
unmarshaledRdeTypeSchema, err := loadRdeTypeSchemaFromTestResources()
check.Assert(err, IsNil)
check.Assert(true, Equals, len(unmarshaledRdeTypeSchema) > 0)
sanizitedTestName := strings.NewReplacer("_", "", ".", "").Replace(check.TestName())
rdeType, err := vcd.client.CreateRdeType(&types.DefinedEntityType{
Name: sanizitedTestName,
Description: "Created by " + check.TestName(),
Nss: "nss",
Version: "1.0.0",
Vendor: "vmware",
Schema: unmarshaledRdeTypeSchema,
Interfaces: []string{"urn:vcloud:interface:vmware:k8s:1.0.0"},
})
check.Assert(err, IsNil)
AddToCleanupListOpenApi(rdeType.DefinedEntityType.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntityTypes+rdeType.DefinedEntityType.ID)

// Get all the behaviors of the RDE Type. As it referenced the K8s Interface, it inherits its Behaviors, so it
// has one Behavior without anyone creating it.
allBehaviors, err := rdeType.GetAllBehaviors(nil)
check.Assert(err, IsNil)
check.Assert(len(allBehaviors), Equals, 1)
check.Assert(allBehaviors[0].Name, Equals, "createKubeConfig")
check.Assert(len(allBehaviors[0].Execution), Equals, 2)
check.Assert(allBehaviors[0].Execution["id"], Equals, "CreateKubeConfigActivity")
check.Assert(allBehaviors[0].Execution["type"], Equals, "Activity")

// Error getting non-existing Behaviors
_, err = rdeType.GetBehaviorById("urn:vcloud:behavior-type:notexist:notexist:notexist:9.9.9")
check.Assert(err, NotNil)
check.Assert(strings.Contains(err.Error(), "RDE_INVALID_BEHAVIOR_SCOPE"), Equals, true)

_, err = rdeType.GetBehaviorByName("DoesNotExist")
check.Assert(err, NotNil)
check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true)

// Getting behaviors correctly
retrievedBehavior, err := rdeType.GetBehaviorById(allBehaviors[0].ID)
check.Assert(err, IsNil)
check.Assert(retrievedBehavior, NotNil)
check.Assert(retrievedBehavior.Name, Equals, allBehaviors[0].Name)
check.Assert(retrievedBehavior.Description, Equals, allBehaviors[0].Description)
check.Assert(retrievedBehavior.Execution, DeepEquals, allBehaviors[0].Execution)

retrievedBehavior2, err := rdeType.GetBehaviorByName(allBehaviors[0].Name)
check.Assert(err, IsNil)
check.Assert(retrievedBehavior, NotNil)
check.Assert(retrievedBehavior, DeepEquals, retrievedBehavior2)

allAccCtrl, err := rdeType.GetAllBehaviorsAccessControls(nil)
check.Assert(err, IsNil)
check.Assert(len(allAccCtrl), Equals, 0)

// TODO: Test rdeType.AddBehaviorAccessControl()

err = rdeType.Delete()
check.Assert(err, IsNil)
}
147 changes: 147 additions & 0 deletions govcd/defined_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,153 @@ func (di *DefinedInterface) Delete() error {
return nil
}

// AddBehavior adds a new Behavior to the receiver DefinedInterface.
// Only allowed if the Interface is not in use.
func (di *DefinedInterface) AddBehavior(behavior types.Behavior) (*types.Behavior, error) {
if di.DefinedInterface.ID == "" {
return nil, fmt.Errorf("ID of the receiver Defined Interface is empty")
}

endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeInterfaceBehaviors
apiVersion, err := di.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := di.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, di.DefinedInterface.ID))
if err != nil {
return nil, err
}

result := &types.Behavior{}
err = di.client.OpenApiPostItem(apiVersion, urlRef, nil, behavior, result, nil)
if err != nil {
return nil, err
}

return result, nil
}

// GetAllBehaviors retrieves all the Behaviors of the receiver Defined Interface. Query parameters can be supplied to modify pagination.
func (di *DefinedInterface) GetAllBehaviors(queryParameters url.Values) ([]*types.Behavior, error) {
if di.DefinedInterface.ID == "" {
return nil, fmt.Errorf("ID of the receiver Defined Interface is empty")
}
return getAllBehaviors(di.client, di.DefinedInterface.ID, types.OpenApiEndpointRdeInterfaceBehaviors, queryParameters)
}

// getAllBehaviors gets all the Behaviors from the object referenced by the input Object ID with the given OpenAPI endpoint.
func getAllBehaviors(client *Client, objectId, openApiEndpoint string, queryParameters url.Values) ([]*types.Behavior, error) {
endpoint := types.OpenApiPathVersion1_0_0 + openApiEndpoint
apiVersion, err := client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, objectId))
if err != nil {
return nil, err
}

typeResponses := []*types.Behavior{{}}
err = client.OpenApiGetAllItems(apiVersion, urlRef, queryParameters, &typeResponses, nil)
if err != nil {
return nil, err
}

return typeResponses, nil
}

// GetBehaviorById retrieves a unique Behavior that belongs to the receiver Defined Interface and is determined by the
// input ID.
func (di *DefinedInterface) GetBehaviorById(id string) (*types.Behavior, error) {
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeInterfaceBehaviors
apiVersion, err := di.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := di.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, di.DefinedInterface.ID), id)
if err != nil {
return nil, err
}

response := types.Behavior{}
err = di.client.OpenApiGetItem(apiVersion, urlRef, nil, &response, nil)
if err != nil {
return nil, err
}

return &response, nil
}

// GetBehaviorByName retrieves a unique Behavior that belongs to the receiver Defined Interface and is named after
// the input.
func (di *DefinedInterface) GetBehaviorByName(name string) (*types.Behavior, error) {
behaviors, err := di.GetAllBehaviors(nil)
if err != nil {
return nil, fmt.Errorf("could not get the Behaviors of the Defined Interface with ID '%s': %s", di.DefinedInterface.ID, err)
}
for _, b := range behaviors {
if b.Name == name {
return b, nil
}
}
return nil, fmt.Errorf("could not find any Behavior with name '%s' in Defined Interface with ID '%s': %s", name, di.DefinedInterface.ID, ErrorEntityNotFound)
}

// UpdateBehavior updates a Behavior specified by the input.
func (di *DefinedInterface) UpdateBehavior(behavior types.Behavior) (*types.Behavior, error) {
if di.DefinedInterface.ID == "" {
return nil, fmt.Errorf("ID of the receiver Defined Interface is empty")
}
if behavior.ID == "" {
return nil, fmt.Errorf("ID of the Behavior to update is empty")
}

endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeInterfaceBehaviors
apiVersion, err := di.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return nil, err
}

urlRef, err := di.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, di.DefinedInterface.ID), behavior.ID)
if err != nil {
return nil, err
}
response := types.Behavior{}
err = di.client.OpenApiPutItem(apiVersion, urlRef, nil, behavior, &response, nil)
if err != nil {
return nil, err
}

return &response, nil
}

// DeleteBehavior removes a Behavior specified by its ID from the receiver Defined Interface.
func (di *DefinedInterface) DeleteBehavior(behaviorId string) error {
if di.DefinedInterface.ID == "" {
return fmt.Errorf("ID of the receiver Defined Interface is empty")
}

endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeInterfaceBehaviors
apiVersion, err := di.client.getOpenApiHighestElevatedVersion(endpoint)
if err != nil {
return err
}

urlRef, err := di.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, di.DefinedInterface.ID), behaviorId)
if err != nil {
return err
}
err = di.client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil)
if err != nil {
return err
}

return nil
}

// amendRdeApiError fixes a wrong type of error returned by VCD API <= v36.0 on GET operations
// when the defined interface does not exist.
func amendRdeApiError(client *Client, err error) error {
Expand Down
Loading

0 comments on commit 1b33343

Please sign in to comment.