diff --git a/client/v3/v3_service.go b/client/v3/v3_service.go index 4761127ad..8deef2232 100644 --- a/client/v3/v3_service.go +++ b/client/v3/v3_service.go @@ -92,6 +92,9 @@ type Service interface { GetUserGroup(userUUID string) (*UserGroupIntentResponse, error) ListUserGroup(getEntitiesRequest *DSMetadata) (*UserGroupListResponse, error) ListAllUserGroup(filter string) (*UserGroupListResponse, error) + GetPermission(permissionUUID string) (*PermissionIntentResponse, error) + ListPermission(getEntitiesRequest *DSMetadata) (*PermissionListResponse, error) + ListAllPermission(filter string) (*PermissionListResponse, error) } /*CreateVM Creates a VM @@ -1827,3 +1830,83 @@ func (op Operations) ListAllUserGroup(filter string) (*UserGroupListResponse, er return resp, nil } + +/*GePermission This operation gets a Permission. + * + * @param uuid The permission uuid - string. + * @return *PermissionIntentResponse + */ +func (op Operations) GetPermission(permissionUUID string) (*PermissionIntentResponse, error) { + ctx := context.TODO() + + path := fmt.Sprintf("/permissions/%s", permissionUUID) + permission := new(PermissionIntentResponse) + + req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil) + if err != nil { + return nil, err + } + + return permission, op.client.Do(ctx, req, permission) +} + +/*ListPermission gets a list of Permissions. + * + * @param metadata allows create filters to get specific data - *DSMetadata. + * @return *PermissionListResponse + */ +func (op Operations) ListPermission(getEntitiesRequest *DSMetadata) (*PermissionListResponse, error) { + ctx := context.TODO() + path := "/permissions/list" + + PermissionList := new(PermissionListResponse) + + req, err := op.client.NewRequest(ctx, http.MethodPost, path, getEntitiesRequest) + if err != nil { + return nil, err + } + + return PermissionList, op.client.Do(ctx, req, PermissionList) +} + +// ListAllPermission ... +func (op Operations) ListAllPermission(filter string) (*PermissionListResponse, error) { + entities := make([]*PermissionIntentResponse, 0) + + resp, err := op.ListPermission(&DSMetadata{ + Filter: &filter, + Kind: utils.StringPtr("permission"), + Length: utils.Int64Ptr(itemsPerPage), + }) + + if err != nil { + return nil, err + } + + totalEntities := utils.Int64Value(resp.Metadata.TotalMatches) + remaining := totalEntities + offset := utils.Int64Value(resp.Metadata.Offset) + + if totalEntities > itemsPerPage { + for hasNext(&remaining) { + resp, err = op.ListPermission(&DSMetadata{ + Filter: &filter, + Kind: utils.StringPtr("permission"), + Length: utils.Int64Ptr(itemsPerPage), + Offset: utils.Int64Ptr(offset), + }) + + if err != nil { + return nil, err + } + + entities = append(entities, resp.Entities...) + + offset += itemsPerPage + } + + resp.Entities = entities + } + + return resp, nil +} diff --git a/client/v3/v3_structs.go b/client/v3/v3_structs.go index aea5f42cc..c0e4c3623 100644 --- a/client/v3/v3_structs.go +++ b/client/v3/v3_structs.go @@ -2245,3 +2245,46 @@ type UserGroupListResponse struct { Entities []*UserGroupIntentResponse `json:"entities,omitempty"` Metadata *ListMetadataOutput `json:"metadata,omitempty"` // All api calls that return a list will have this metadata block } + +// Response object for intentful operations on a user_group +type PermissionIntentResponse struct { + APIVersion *string `json:"api_version,omitempty"` // API Version of the Nutanix v3 API framework. + Metadata *Metadata `json:"metadata,omitempty"` // The user_group kind metadata + Spec *PermissionSpec `json:"spec,omitempty"` // Permission Input Definition. + Status *PermissionStatus `json:"status,omitempty"` // User group status definition. +} + +// Permission Input Definition. +type PermissionSpec struct { + Name *string `json:"name,omitempty"` // The name for the permission. + Description *string `json:"description,omitempty"` // The display name for the permission. + Resources *PermissionResources `json:"resources,omitempty"` // Permission Resource Definition +} + +// Permission Resource Definition +type PermissionResources struct { + Operation *string `json:"operation,omitempty"` + Kind *string `json:"kind,omitempty"` + Fields *FieldsPermission `json:"fields,omitempty"` +} + +type FieldsPermission struct { + FieldMode *string `json:"field_mode,omitempty"` + FieldNameList []*string `json:"field_name_list,omitempty"` +} + +// Permission status definition. +type PermissionStatus struct { + Name *string `json:"name,omitempty"` // The name for the permission. + Description *string `json:"description,omitempty"` // The display name for the permission. + Resources *PermissionResources `json:"resources,omitempty"` // Permission Resource Definition + MessageList []MessageResource `json:"message_list,omitempty"` + State *string `json:"state,omitempty"` // The state of the entity. +} + +// Response object for intentful operation of Permissions +type PermissionListResponse struct { + APIVersion *string `json:"api_version,omitempty"` // API Version of the Nutanix v3 API framework. + Entities []*PermissionIntentResponse `json:"entities,omitempty"` + Metadata *ListMetadataOutput `json:"metadata,omitempty"` // All api calls that return a list will have this metadata block +} diff --git a/nutanix/data_source_nutanix_permission.go b/nutanix/data_source_nutanix_permission.go new file mode 100644 index 000000000..bfa4ca0a1 --- /dev/null +++ b/nutanix/data_source_nutanix_permission.go @@ -0,0 +1,256 @@ +package nutanix + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + v3 "github.com/terraform-providers/terraform-provider-nutanix/client/v3" + "github.com/terraform-providers/terraform-provider-nutanix/utils" +) + +func dataSourceNutanixPermission() *schema.Resource { + return &schema.Resource{ + Read: dataSourceNutanixPermissionRead, + Schema: map[string]*schema.Schema{ + "permission_id": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"permission_name"}, + }, + "permission_name": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"permission_id"}, + }, + "api_version": { + Type: schema.TypeString, + Computed: true, + }, + "metadata": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "last_update_time": { + Type: schema.TypeString, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + }, + "spec_version": { + Type: schema.TypeString, + Computed: true, + }, + "spec_hash": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "categories": categoriesSchema(), + "owner_reference": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "project_reference": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "operation": { + Type: schema.TypeString, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "fields": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_mode": { + Type: schema.TypeString, + Computed: true, + }, + "field_name_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceNutanixPermissionRead(d *schema.ResourceData, meta interface{}) error { + // Get client connection + conn := meta.(*Client).API + + permissionID, iok := d.GetOk("permission_id") + permissionName, rnOk := d.GetOk("permission_name") + + if !iok && !rnOk { + return fmt.Errorf("please provide `permission_id` or `permission_name`") + } + + var err error + var resp *v3.PermissionIntentResponse + + if iok { + resp, err = conn.V3.GetPermission(permissionID.(string)) + } + if rnOk { + resp, err = findPermissionByName(conn, permissionName.(string)) + } + utils.PrintToJSON(resp, "Permission: ") + if err != nil { + return err + } + + m, c := setRSEntityMetadata(resp.Metadata) + + if err := d.Set("metadata", m); err != nil { + return err + } + if err := d.Set("categories", c); err != nil { + return err + } + if err := d.Set("project_reference", flattenReferenceValues(resp.Metadata.ProjectReference)); err != nil { + return err + } + if err := d.Set("owner_reference", flattenReferenceValues(resp.Metadata.OwnerReference)); err != nil { + return err + } + if err := d.Set("api_version", resp.APIVersion); err != nil { + return err + } + + if status := resp.Status; status != nil { + if err := d.Set("name", utils.StringValue(resp.Status.Name)); err != nil { + return err + } + if err := d.Set("description", utils.StringValue(resp.Status.Description)); err != nil { + return err + } + if err := d.Set("state", utils.StringValue(resp.Status.State)); err != nil { + return err + } + + if res := status.Resources; res != nil { + if err := d.Set("operation", utils.StringValue(res.Operation)); err != nil { + return err + } + if err := d.Set("kind", utils.StringValue(res.Kind)); err != nil { + return err + } + if err := d.Set("fields", flattenFieldsPermission(res.Fields)); err != nil { + return err + } + } + } + d.SetId(utils.StringValue(resp.Metadata.UUID)) + + return nil +} + +func flattenFieldsPermission(fieldPermissions *v3.FieldsPermission) []map[string]interface{} { + flatFieldsPermissions := make([]map[string]interface{}, 0) + n := map[string]interface{}{ + "field_mode": fieldPermissions.FieldMode, + "field_name_list": fieldPermissions.FieldNameList, + } + flatFieldsPermissions = append(flatFieldsPermissions, n) + return flatFieldsPermissions +} + +func findPermissionByName(conn *v3.Client, name string) (*v3.PermissionIntentResponse, error) { + filter := fmt.Sprintf("name==%s", name) + resp, err := conn.V3.ListAllPermission(filter) + if err != nil { + return nil, err + } + + entities := resp.Entities + + found := make([]*v3.PermissionIntentResponse, 0) + for _, v := range entities { + if *v.Spec.Name == name { + found = append(found, v) + } + } + + if len(found) > 1 { + return nil, fmt.Errorf("your query returned more than one result. Please use permission_id argument instead") + } + + if len(found) == 0 { + return nil, fmt.Errorf("permission with the given name, not found") + } + found[0].APIVersion = resp.APIVersion + return found[0], nil +} diff --git a/nutanix/data_source_nutanix_permission_test.go b/nutanix/data_source_nutanix_permission_test.go new file mode 100644 index 000000000..d6b1ae970 --- /dev/null +++ b/nutanix/data_source_nutanix_permission_test.go @@ -0,0 +1,69 @@ +package nutanix + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +const ( + PERMISSIONNAME = "Access_Console_Virtual_Machine" + PERMISSINOUUID = "16b81a55-2bca-48c6-9fab-4f82c6bb4284" +) + +func TestAccNutanixPermissionDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccPermissionDataSourceConfig(PERMISSINOUUID), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "name", PERMISSIONNAME), + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "operation", "console_access"), + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "fields.0.field_mode", "DISALLOWED"), + ), + }, + }, + }) +} + +func testAccPermissionDataSourceConfig(uuid string) string { + return fmt.Sprintf(` +data "nutanix_permission" "test" { + permission_id = "%s" +} +`, uuid) +} + +func TestAccNutanixPermissionDataSource_basicByName(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccPermissionDataSourceConfigByName(PERMISSIONNAME), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "name", PERMISSIONNAME), + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "operation", "console_access"), + resource.TestCheckResourceAttr( + "data.nutanix_permission.test", "fields.0.field_mode", "DISALLOWED"), + ), + }, + }, + }) +} + +func testAccPermissionDataSourceConfigByName(name string) string { + return fmt.Sprintf(` +data "nutanix_permission" "test" { + permission_name = "%s" +} +`, name) +} diff --git a/nutanix/data_source_nutanix_permissions.go b/nutanix/data_source_nutanix_permissions.go new file mode 100644 index 000000000..902115353 --- /dev/null +++ b/nutanix/data_source_nutanix_permissions.go @@ -0,0 +1,235 @@ +package nutanix + +import ( + "log" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-nutanix/utils" +) + +func dataSourceNutanixPermissions() *schema.Resource { + return &schema.Resource{ + Read: dataSourceNutanixPermissionsRead, + Schema: map[string]*schema.Schema{ + "api_version": { + Type: schema.TypeString, + Computed: true, + }, + "metadata": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filter": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "sort_order": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "offset": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "length": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "sort_attribute": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + }, + "entities": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "api_version": { + Type: schema.TypeString, + Computed: true, + }, + "metadata": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "last_update_time": { + Type: schema.TypeString, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + }, + "spec_version": { + Type: schema.TypeString, + Computed: true, + }, + "spec_hash": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "categories": categoriesSchema(), + "owner_reference": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "project_reference": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "operation": { + Type: schema.TypeString, + Computed: true, + }, + "kind": { + Type: schema.TypeString, + Computed: true, + }, + "fields": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_mode": { + Type: schema.TypeString, + Computed: true, + }, + "field_name_list": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceNutanixPermissionsRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Reading Permissions: %s", d.Id()) + + // Get client connection + conn := meta.(*Client).API + + resp, err := conn.V3.ListAllPermission("") + if err != nil { + return err + } + + if err := d.Set("api_version", resp.APIVersion); err != nil { + return err + } + + entities := make([]map[string]interface{}, len(resp.Entities)) + for k, v := range resp.Entities { + entity := make(map[string]interface{}) + + m, c := setRSEntityMetadata(v.Metadata) + + entity["metadata"] = m + entity["categories"] = c + entity["project_reference"] = flattenReferenceValues(v.Metadata.ProjectReference) + entity["owner_reference"] = flattenReferenceValues(v.Metadata.OwnerReference) + entity["api_version"] = utils.StringValue(v.APIVersion) + entity["state"] = utils.StringValue(v.Status.State) + entity["name"] = utils.StringValue(v.Status.Name) + entity["description"] = utils.StringValue(v.Status.Description) + entity["operation"] = utils.StringValue(v.Status.Resources.Operation) + entity["kind"] = utils.StringValue(v.Status.Resources.Kind) + entity["fields"] = flattenFieldsPermission(v.Status.Resources.Fields) + + entities[k] = entity + } + + if err := d.Set("entities", entities); err != nil { + return err + } + + d.SetId(resource.UniqueId()) + + return nil +} diff --git a/nutanix/data_source_nutanix_permissions_test.go b/nutanix/data_source_nutanix_permissions_test.go new file mode 100644 index 000000000..01a98555c --- /dev/null +++ b/nutanix/data_source_nutanix_permissions_test.go @@ -0,0 +1,30 @@ +package nutanix + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccNutanixPermissionsDataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccPermissionsDataSourceConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.nutanix_permissions.test", "entities.#"), + resource.TestCheckResourceAttr( + "data.nutanix_permissions.test", "entities.#", "485"), + ), + }, + }, + }) +} + +func testAccPermissionsDataSourceConfig() string { + return ` +data "nutanix_permissions" "test" {} +` +} diff --git a/nutanix/provider.go b/nutanix/provider.go index c55985ca6..569c10852 100644 --- a/nutanix/provider.go +++ b/nutanix/provider.go @@ -105,6 +105,8 @@ func Provider() terraform.ResourceProvider { "nutanix_users": dataSourceNutanixUsers(), "nutanix_user_group": dataSourceNutanixUserGroup(), "nutanix_user_groups": dataSourceNutanixUserGroups(), + "nutanix_permission": dataSourceNutanixPermission(), + "nutanix_permissions": dataSourceNutanixPermissions(), }, ResourcesMap: map[string]*schema.Resource{ "nutanix_virtual_machine": resourceNutanixVirtualMachine(),