Skip to content

Commit

Permalink
Merge pull request nutanix#116 from terraform-providers/fix-#70
Browse files Browse the repository at this point in the history
Fix nutanix#70: Added Host datasources
  • Loading branch information
PacoDw authored Apr 27, 2020
2 parents d439c69 + e8415f4 commit 71adf36
Show file tree
Hide file tree
Showing 14 changed files with 1,697 additions and 14 deletions.
73 changes: 73 additions & 0 deletions client/v3/v3_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ type Service interface {
ListAllImage() (*ImageListIntentResponse, error)
ListAllCluster() (*ClusterListIntentResponse, error)
GetTask(taskUUID string) (*TasksResponse, error)
GetHost(taskUUID string) (*HostResponse, error)
ListHost(getEntitiesRequest *DSMetadata) (*HostListResponse, error)
ListAllHost() (*HostListResponse, error)
}

/*CreateVM Creates a VM
Expand Down Expand Up @@ -1067,3 +1070,73 @@ func (op Operations) GetTask(taskUUID string) (*TasksResponse, error) {

return tasksTesponse, op.client.Do(ctx, req, tasksTesponse)
}

//GetHost ...
func (op Operations) GetHost(hostUUID string) (*HostResponse, error) {
ctx := context.TODO()

path := fmt.Sprintf("/hosts/%s", hostUUID)
host := new(HostResponse)

req, err := op.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, err
}

return host, op.client.Do(ctx, req, host)
}

//ListHost ...
func (op Operations) ListHost(getEntitiesRequest *DSMetadata) (*HostListResponse, error) {
ctx := context.TODO()
path := "/hosts/list"

hostList := new(HostListResponse)

req, err := op.client.NewRequest(ctx, http.MethodPost, path, getEntitiesRequest)
if err != nil {
return nil, err
}

return hostList, op.client.Do(ctx, req, hostList)
}

// ListAllHost ...
func (op Operations) ListAllHost() (*HostListResponse, error) {
entities := make([]*HostResponse, 0)

resp, err := op.ListHost(&DSMetadata{
Kind: utils.StringPtr("host"),
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.ListHost(&DSMetadata{
Kind: utils.StringPtr("cluster"),
Length: utils.Int64Ptr(itemsPerPage),
Offset: utils.Int64Ptr(offset),
})

if err != nil {
return nil, err
}

entities = append(entities, resp.Entities...)

offset += itemsPerPage
log.Printf("[Debug] total=%d, remaining=%d, offset=%d len(entities)=%d\n", totalEntities, remaining, offset, len(entities))
}

resp.Entities = entities
}

return resp, nil
}
122 changes: 122 additions & 0 deletions client/v3/v3_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2797,3 +2797,125 @@ func testHTTPMethod(t *testing.T, r *http.Request, expected string) {
t.Errorf("Request method = %v, expected %v", r.Method, expected)
}
}

func TestOperations_GetHost(t *testing.T) {
mux, c, server := setup()

defer server.Close()

mux.HandleFunc("/api/nutanix/v3/hosts/cfde831a-4e87-4a75-960f-89b0148aa2cc", func(w http.ResponseWriter, r *http.Request) {
testHTTPMethod(t, r, http.MethodGet)
fmt.Fprint(w, `{"metadata": {"kind":"host","uuid":"cfde831a-4e87-4a75-960f-89b0148aa2cc"}}`)
})

hostResponse := &HostResponse{}
hostResponse.Metadata = &Metadata{
UUID: utils.StringPtr("cfde831a-4e87-4a75-960f-89b0148aa2cc"),
Kind: utils.StringPtr("host"),
}

type fields struct {
client *client.Client
}

type args struct {
UUID string
}

tests := []struct {
name string
fields fields
args args
want *HostResponse
wantErr bool
}{
{
"Test GetHost OK",
fields{c},
args{"cfde831a-4e87-4a75-960f-89b0148aa2cc"},
hostResponse,
false,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
op := Operations{
client: tt.fields.client,
}
got, err := op.GetHost(tt.args.UUID)
if (err != nil) != tt.wantErr {
t.Errorf("Operations.GetHost() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Operations.GetHost() = %v, want %v", got, tt.want)
}
})
}
}

func TestOperations_ListHost(t *testing.T) {
mux, c, server := setup()

defer server.Close()

mux.HandleFunc("/api/nutanix/v3/hosts/list", func(w http.ResponseWriter, r *http.Request) {
testHTTPMethod(t, r, http.MethodPost)
fmt.Fprint(w, `{"entities":[{"metadata": {"kind":"host","uuid":"cfde831a-4e87-4a75-960f-89b0148aa2cc"}}]}`)
})

hostList := &HostListResponse{}
hostList.Entities = make([]*HostResponse, 1)
hostList.Entities[0] = &HostResponse{}
hostList.Entities[0].Metadata = &Metadata{
UUID: utils.StringPtr("cfde831a-4e87-4a75-960f-89b0148aa2cc"),
Kind: utils.StringPtr("host"),
}

input := &DSMetadata{
Length: utils.Int64Ptr(1.0),
}

type fields struct {
client *client.Client
}

type args struct {
getEntitiesRequest *DSMetadata
}

tests := []struct {
name string
fields fields
args args
want *HostListResponse
wantErr bool
}{
{
"Test ListSubnet OK",
fields{c},
args{input},
hostList,
false,
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
op := Operations{
client: tt.fields.client,
}
got, err := op.ListHost(tt.args.getEntitiesRequest)
if (err != nil) != tt.wantErr {
t.Errorf("Operations.ListHost() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Operations.ListHost() = %v, want %v", got, tt.want)
}
})
}
}
139 changes: 139 additions & 0 deletions client/v3/v3_structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1795,3 +1795,142 @@ type DeleteStatus struct {
State string `json:"state"`
ExecutionContext *ExecutionContext `json:"execution_context"`
}

/* Host Resource */

// DomainCredencial represents the way to login server
type DomainCredencial struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}

// WindowsDomain means Hyper-V node domain
type WindowsDomain struct {
Name string `json:"name,omitempty"`
NameServerIP string `json:"name_server_ip,omitempty"`
OrganizationUnitPath string `json:"organization_unit_path,omitempty"`
NamePrefix string `json:"name_prefix,omitempty"`
DomainName string `json:"domain_name,omitempty"`
DomainCredencial *DomainCredencial `json:"domain_credencial,omitempty"`
}

// OplogUsage represents oplog disk usage
type OplogUsage struct {
OplogDiskPct *float64 `json:"oplog_disk_pct,omitempty"`
OplogDiskSize *int64 `json:"oplog_disk_size,omitempty"`
}

// ControllerVM means Hyper-V node domain
type ControllerVM struct {
IP string `json:"ip,omitempty"`
NatIP string `json:"nat_ip,omitempty"`
NatPort *int64 `json:"nat_port,omitempty"`
OplogUsage *OplogUsage `json:"oplog_usage,omitempty"`
}

// FailoverCluster means Hiper-V failover cluster
type FailoverCluster struct {
IP string `json:"ip,omitempty"`
Name string `json:"name,omitempty"`
DomainCredencial *DomainCredencial `json:"domain_credencial,omitempty"`
}

// IPMI means Host IPMI Information
type IPMI struct {
IP string `json:"ip,omitempty"`
}

// ReferenceValues references to a kind
type ReferenceValues struct {
Kind string `json:"kind,omitempty"`
UUID string `json:"uuid,omitempty"`
Name string `json:"name,omitempty"`
}

// GPU represnts list of GPUs on the host
type GPU struct {
Status string `json:"status,omitempty"`
Vendor string `json:"vendor,omitempty"`
NumVirtualDisplayHeads *int64 `json:"num_virtual_display_heads,omitempty"`
Assignable bool `json:"assignable,omitempty"`
LicenseList []*string `json:"license_list,omitempty"`
NumVgpusAllocated *int64 `json:"num_vgpus_allocated,omitempty"`
PciAddress string `json:"pci_address,omitempty"`
Name string `json:"name,omitempty"`
FrameBufferSizeMib *int64 `json:"frame_buffer_size_mib,omitempty"`
Index *int64 `json:"index,omitempty"`
UUID string `json:"uuid,omitempty"`
NumaNode *int64 `json:"numa_node,omitempty"`
MaxResoution string `json:"max_resolution,omitempty"`
ConsumerReference *ReferenceValues `json:"consumer_reference,omitempty"`
Mode string `json:"mode,omitempty"`
Fraction *int64 `json:"fraction,omitempty"`
GuestDriverVersion string `json:"guest_driver_version,omitempty"`
DeviceID *int64 `json:"device_id,omitempty"`
}

// Hypervisor Full name of hypervisor running on Host
type Hypervisor struct {
NumVms *int64 `json:"num_vms,omitempty"`
IP string `json:"ip,omitempty"`
HypervisorFullName string `json:"hypervisor_full_name,omitempty"`
}

// Block represents Host block config info.
type Block struct {
BlockSerialNumber string `json:"block_serial_number,omitempty"`
BlockModel string `json:"block_model,omitempty"`
}

// HostResources represents the host resources
type HostResources struct {
GPUDriverVersion string `json:"gpu_driver_version,omitempty"`
FailoverCluster *FailoverCluster `json:"failover_cluster,omitempty"`
IPMI *IPMI `json:"ipmi,omitempty"`
CPUModel string `json:"cpu_model,omitempty"`
HostNicsIDList []*string `json:"host_nics_id_list,omitempty"`
NumCPUSockets *int64 `json:"num_cpu_sockets,omitempty"`
WindowsDomain *WindowsDomain `json:"windows_domain,omitempty"`
GPUList []*GPU `json:"gpu_list,omitempty"`
SerialNumber string `json:"serial_number,omitempty"`
CPUCapacityHZ *int64 `json:"cpu_capacity_hz,omitempty"`
MemoryVapacityMib *int64 `json:"memory_capacity_mib,omitempty"`
HostDisksReferenceList []*ReferenceValues `json:"host_disks_reference_list,omitempty"`
MonitoringState string `json:"monitoring_state,omitempty"`
Hypervisor *Hypervisor `json:"hypervisor,omitempty"`
HostType string `json:"host_type,omitempty"`
NumCPUCores *int64 `json:"num_cpu_cores,omitempty"`
RackableUnitReference *ReferenceValues `json:"rackable_unit_reference,omitempty"`
ControllerVM *ControllerVM `json:"controller_vm,omitempty"`
Block *Block `json:"block,omitempty"`
}

// HostSpec Represents volume group input spec.
type HostSpec struct {
Name string `json:"name,omitempty"`
Resources *HostResources `json:"resources,omitempty"`
}

// HostStatus Volume group configuration.
type HostStatus struct {
State string `json:"state,omitempty"`
MessageList []*MessageResource `json:"message_list,omitempty"`
Name string `json:"name,omitempty"`
Resources *HostResources `json:"resources,omitempty"`
ClusterReference *ReferenceValues `json:"cluster_reference,omitempty"`
}

// HostResponse Response object for intentful operations on a Host
type HostResponse struct {
APIVersion string `json:"api_version,omitempty"`
Metadata *Metadata `json:"metadata,omitempty"`
Spec *HostSpec `json:"spec,omitempty"`
Status *HostStatus `json:"status,omitempty"`
}

// HostListResponse Response object for intentful operation of Host
type HostListResponse struct {
APIVersion string `json:"api_version,omitempty"`
Entities []*HostResponse `json:"entities,omitempty"`
Metadata *ListMetadataOutput `json:"metadata,omitempty"`
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/hashicorp/terraform v0.12.3
github.com/mitchellh/gox v1.0.1
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1
)

go 1.13
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,8 @@ github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down
Loading

0 comments on commit 71adf36

Please sign in to comment.