diff --git a/govcd/filter_interface.go b/govcd/filter_interface.go index 655a9695b..e3ba84966 100644 --- a/govcd/filter_interface.go +++ b/govcd/filter_interface.go @@ -37,6 +37,7 @@ type ( QueryOrgVdc types.QueryResultOrgVdcRecordType QueryTask types.QueryResultTaskRecordType QueryAdminTask types.QueryResultTaskRecordType + QueryOrg types.QueryResultOrgRecordType ) // getMetadataValue is a generic metadata lookup for all query items @@ -230,6 +231,20 @@ func (vm QueryVm) GetMetadataValue(key string) string { return getMetadataValue(vm.MetaData, key) } +// -------------------------------------------------------------- +// Organization +// -------------------------------------------------------------- +func (org QueryOrg) GetHref() string { return org.HREF } +func (org QueryOrg) GetName() string { return org.Name } +func (org QueryOrg) GetType() string { return "organization" } +func (org QueryOrg) GetDate() string { return "" } +func (org QueryOrg) GetIp() string { return "" } +func (org QueryOrg) GetParentId() string { return "" } +func (org QueryOrg) GetParentName() string { return "" } +func (org QueryOrg) GetMetadataValue(key string) string { + return getMetadataValue(org.Metadata, key) +} + // -------------------------------------------------------------- // result conversion // -------------------------------------------------------------- @@ -273,6 +288,10 @@ func resultToQueryItems(queryType string, results Results) ([]QueryItem, error) for i, item := range results.Results.OrgVdcNetworkRecord { items[i] = QueryOrgVdcNetwork(*item) } + case types.QtOrg: + for i, item := range results.Results.OrgRecord { + items[i] = QueryOrg(*item) + } case types.QtCatalog: for i, item := range results.Results.CatalogRecord { items[i] = QueryCatalog(*item) diff --git a/govcd/org.go b/govcd/org.go index c87bde837..56d18d74c 100644 --- a/govcd/org.go +++ b/govcd/org.go @@ -381,6 +381,99 @@ func (org *Org) GetTaskList() (*types.TasksList, error) { return nil, fmt.Errorf("link not found") } +// QueryAllOrgs returns all Org VDCs using query endpoint +func (vcdclient *VCDClient) QueryAllOrgs() ([]*types.QueryResultOrgRecordType, error) { + return vcdclient.Client.queryOrgList(nil) +} + +// queryOrgList performs an `orgVdc` or `adminOrgVdc` (for System user) and optionally applies filterFields +func (client *Client) queryOrgList(filterFields map[string]string) ([]*types.QueryResultOrgRecordType, error) { + util.Logger.Printf("[DEBUG] queryOrgList with filter %#v", filterFields) + queryType := client.GetQueryType(types.QtOrg) + + filter := map[string]string{ + "type": queryType, + } + + // When a map of filters with non empty keys and values is supplied - apply it + if filterFields != nil { + filterSlice := make([]string, 0) + + for filterFieldName, filterFieldValue := range filterFields { + // Do not inject 'org' filter for System user as API returns an error + if !client.IsSysAdmin && filterFieldName == "org" { + continue + } + + if filterFieldName != "" && filterFieldValue != "" { + filterText := fmt.Sprintf("%s==%s", filterFieldName, url.QueryEscape(filterFieldValue)) + filterSlice = append(filterSlice, filterText) + } + } + + if len(filterSlice) > 0 { + filter["filter"] = strings.Join(filterSlice, ";") + filter["filterEncoded"] = "true" + } + } + + results, err := client.cumulativeQuery(queryType, nil, filter) + if err != nil { + return nil, fmt.Errorf("error querying Orgs %s", err) + } + + return results.Results.OrgRecord, nil +} + +// QueryOrgByName retrieves an Org +func (vcdclient *VCDClient) QueryOrgByName(name string) (*types.QueryResultOrgRecordType, error) { + return vcdclient.Client.queryOrgByName(name) +} + +// queryOrgByName returns a single QueryResultOrgRecordType +func (client *Client) queryOrgByName(orgName string) (*types.QueryResultOrgRecordType, error) { + filterMap := map[string]string{ + "name": orgName, + } + allOrgs, err := client.queryOrgList(filterMap) + if err != nil { + return nil, err + } + + if allOrgs == nil || len(allOrgs) < 1 { + return nil, ErrorEntityNotFound + } + + if len(allOrgs) > 1 { + return nil, fmt.Errorf("found more than 1 Org with Name '%s'", orgName) + } + + return allOrgs[0], nil +} + +// QueryOrgByID retrieves an Org +func (vcdclient *VCDClient) QueryOrgByID(id string) (*types.QueryResultOrgRecordType, error) { + return vcdclient.Client.queryOrgByID(id) +} + +// queryOrgByID returns a single QueryResultOrgRecordType +func (client *Client) queryOrgByID(orgId string) (*types.QueryResultOrgRecordType, error) { + filterMap := map[string]string{ + "id": orgId, + } + allOrgs, err := client.queryOrgList(filterMap) + + if err != nil { + return nil, err + } + + if len(allOrgs) < 1 { + return nil, ErrorEntityNotFound + } + + return allOrgs[0], nil +} + // queryOrgVdcByName returns a single QueryResultOrgVdcRecordType func (org *Org) queryOrgVdcByName(vdcName string) (*types.QueryResultOrgVdcRecordType, error) { filterFields := map[string]string{ diff --git a/govcd/query_metadata.go b/govcd/query_metadata.go index 0232df522..9ffc5ebd2 100644 --- a/govcd/query_metadata.go +++ b/govcd/query_metadata.go @@ -78,6 +78,8 @@ func queryFieldsOnDemand(queryType string) ([]string, error) { "cpuOverheadMhz", "isVCEnabled", "memoryReservedMB", "cpuReservedMhz", "storageOverheadMB", "memoryOverheadMB", "vc"} taskFields = []string{"href", "id", "type", "org", "orgName", "name", "operationFull", "message", "startDate", "endDate", "status", "progress", "ownerName", "object", "objectType", "objectName", "serviceNamespace"} + orgFields = []string{"href", "id", "type", "name", "displayName", "isEnabled", "isReadOnly", "canPublishCatalogs", + "deployedVMQuota", "storedVMQuota", "numberOfCatalogs", "numberOfVdcs", "numberOfVApps", "numberOfGroups", "numberOfDisks"} fieldsOnDemand = map[string][]string{ types.QtVappTemplate: vappTemplatefields, types.QtAdminVappTemplate: vappTemplatefields, @@ -97,6 +99,7 @@ func queryFieldsOnDemand(queryType string) ([]string, error) { types.QtAdminOrgVdc: orgVdcFields, types.QtTask: taskFields, types.QtAdminTask: taskFields, + types.QtOrg: orgFields, } ) @@ -212,6 +215,7 @@ func (client *Client) cumulativeQueryWithHeaders(queryType string, params, notEn types.QtResourcePool, types.QtNetworkPool, types.QtProviderVdcStorageProfile, + types.QtOrg, } // Make sure the query type is supported // We need to check early, as queries that would return less than 25 items (default page size) would succeed, diff --git a/govcd/system_test.go b/govcd/system_test.go index 6e6597af3..e88f07dec 100644 --- a/govcd/system_test.go +++ b/govcd/system_test.go @@ -757,3 +757,83 @@ func (vcd *TestVCD) TestQueryAllVdcs(check *C) { check.Assert(contains(knownVdcName, foundVdcNames), Equals, true) } } + +// Test retrieval of all Orgs +func (vcd *TestVCD) Test_QueryAllOrgs(check *C) { + vcd.skipIfNotSysAdmin(check) + if vcd.config.VCD.Org == "" { + check.Skip("Test_QueryOrgByName: Org Name not given") + return + } + + orgs, err := vcd.client.QueryAllOrgs() + check.Assert(err, IsNil) + check.Assert(orgs, NotNil) + + if vcd.config.VCD.Org != "" { + foundOrg := false + for _, org := range orgs { + if org.Name == vcd.config.VCD.Org { + foundOrg = true + } + } + check.Assert(foundOrg, Equals, true) + } +} + +// Tests Org retrieval by name, by ID, and by a combination of name and ID +func (vcd *TestVCD) Test_QueryOrgByName(check *C) { + vcd.skipIfNotSysAdmin(check) + if vcd.config.VCD.Org == "" { + check.Skip("Test_QueryOrgByName: Org Name not given") + return + } + + org, err := vcd.client.QueryOrgByName(vcd.config.VCD.Org) + check.Assert(err, IsNil) + + orgFound := false + if vcd.config.VCD.Org == org.Name { + orgFound = true + } + + if testVerbose { + fmt.Printf("Org %s\n", org.Name) + fmt.Printf("\t href %s\n", org.HREF) + fmt.Printf("\t enabled %v\n", org.IsEnabled) + fmt.Println("") + } + + check.Assert(orgFound, Equals, true) +} + +// Tests Org retrieval by name, by ID, and by a combination of name and ID +func (vcd *TestVCD) Test_QueryOrgById(check *C) { + vcd.skipIfNotSysAdmin(check) + if vcd.config.VCD.Org == "" { + check.Skip("Test_QueryOrgByName: Org Name not given") + return + } + + namedOrg, err := vcd.client.GetOrgByName(vcd.config.VCD.Org) + check.Assert(err, IsNil) + + orgFound := false + if vcd.config.VCD.Org == namedOrg.Org.Name { + + idOrg, err := vcd.client.QueryOrgByID(namedOrg.Org.ID) + check.Assert(err, IsNil) + + if idOrg.HREF == namedOrg.Org.HREF { + orgFound = true + } + + if testVerbose { + fmt.Printf("Org %s\n", namedOrg.Org.Name) + fmt.Printf("\t Org HREF (by Name): %s\n", namedOrg.Org.HREF) + fmt.Printf("\t Org HREF (by ID): %s\n", idOrg.HREF) + fmt.Println("") + } + } + check.Assert(orgFound, Equals, true) +} diff --git a/types/v56/constants.go b/types/v56/constants.go index 8e8b8479e..88a7ec92b 100644 --- a/types/v56/constants.go +++ b/types/v56/constants.go @@ -258,6 +258,7 @@ const ( QtVappTemplate = "vAppTemplate" // vApp template QtAdminVappTemplate = "adminVAppTemplate" // vApp template as admin QtEdgeGateway = "edgeGateway" // edge gateway + QtOrg = "organization" // Organization QtOrgVdcNetwork = "orgVdcNetwork" // Org VDC network QtCatalog = "catalog" // catalog QtAdminCatalog = "adminCatalog" // catalog as admin @@ -283,6 +284,7 @@ const ( // AdminQueryTypes returns the corresponding "admin" query type for each regular type var AdminQueryTypes = map[string]string{ QtEdgeGateway: QtEdgeGateway, // EdgeGateway query type is the same for admin and regular users + QtOrg: QtOrg, // Organisation query is admin per default QtOrgVdcNetwork: QtOrgVdcNetwork, // Org VDC Network query type is the same for admin and regular users QtVappTemplate: QtAdminVappTemplate, QtCatalog: QtAdminCatalog, diff --git a/types/v56/types.go b/types/v56/types.go index 4d31b8bb5..3bd4bd8fe 100644 --- a/types/v56/types.go +++ b/types/v56/types.go @@ -2369,6 +2369,7 @@ type QueryResultRecordsType struct { VmGroupsRecord []*QueryResultVmGroupsRecordType `xml:"VmGroupsRecord"` // A record representing a VM Group TaskRecord []*QueryResultTaskRecordType `xml:"TaskRecord"` // A record representing a Task AdminTaskRecord []*QueryResultTaskRecordType `xml:"AdminTaskRecord"` // A record representing an Admin Task + OrgRecord []*QueryResultOrgRecordType `xml:"OrgRecord"` // A record representing an Organisation } // QueryResultVmGroupsRecordType represent a VM Groups record @@ -3357,6 +3358,27 @@ type QueryResultTaskRecordType struct { Metadata *Metadata `xml:"Metadata,omitempty"` } +// QueryResultOrgVdcRecordType represents an Organisation record +type QueryResultOrgRecordType struct { + HREF string `xml:"href,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + ID string `xml:"id,attr,omitempty"` + Name string `xml:"name,attr"` + DisplayName string `xml:"displayName,attr,omitempty"` + IsEnabled bool `xml:"isEnabled,attr,omitempty"` + IsReadOnly bool `xml:"isReadOnly,attr,omitempty"` + CanPublishCatalogs bool `xml:"canPublishCatalogs,attr,omitempty"` + DeployedVMQuota *int `xml:"deployedVMQuota,attr,omitempty"` + StoredVMQuota *int `xml:"storedVMQuota,attr,omitempty"` + NumberOfCatalogs *int `xml:"numberOfCatalogs,attr,omitempty"` + NumberOfVdcs *int `xml:"numberOfVdcs,attr,omitempty"` + NumberOfVApps *int `xml:"numberOfVApps,attr,omitempty"` + NumberOfGroups *int `xml:"numberOfGroups,attr,omitempty"` + NumberOfDisks *int `xml:"numberOfDisks,attr,omitempty"` + Link *LinkList `xml:"Link,omitempty"` + Metadata *Metadata `xml:"Metadata,omitempty"` +} + // ProviderVdcCreation contains the data needed to create a provider VDC. // Note that this is a subset of the full structure of a provider VDC. type ProviderVdcCreation struct {