Skip to content

Commit ac813a4

Browse files
machacekondramnecas
authored andcommitted
Add support to fetch nested attributes
This PR add support to fetch nested attributes. The first nested attirbute supported is: /providers/vsphere/1/hosts/{hostid}?advancedOption=DataMover.HardwareAcceleratedMove Issue: https://issues.redhat.com/browse/ECOPROJECT-2736 Signed-off-by: Ondra Machacek <[email protected]>
1 parent c0f8af3 commit ac813a4

File tree

10 files changed

+108
-14
lines changed

10 files changed

+108
-14
lines changed

pkg/controller/provider/container/openstack/collector.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package openstack
22

33
import (
44
"context"
5+
"fmt"
56
liburl "net/url"
67
libpath "path"
78
"time"
@@ -118,6 +119,11 @@ func (r *Collector) Version() (_, _, _, _ string, err error) {
118119
return
119120
}
120121

122+
// Follow link
123+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
124+
return fmt.Errorf("not implemented")
125+
}
126+
121127
// Start the collector.
122128
func (r *Collector) Start() error {
123129
ctx := Context{

pkg/controller/provider/container/ova/collector.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ova
22

33
import (
44
"context"
5+
"fmt"
56
liburl "net/url"
67
libpath "path"
78
"time"
@@ -122,6 +123,11 @@ func (r *Collector) Version() (_, _, _, _ string, err error) {
122123
return
123124
}
124125

126+
// Follow link
127+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
128+
return fmt.Errorf("not implemented")
129+
}
130+
125131
// Start the collector.
126132
func (r *Collector) Start() error {
127133
ctx := Context{

pkg/controller/provider/container/ovirt/collector.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ func (r *Collector) HasParity() bool {
128128
return r.parity
129129
}
130130

131+
// Follow link
132+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
133+
return fmt.Errorf("not implemented")
134+
}
135+
131136
// Test connect/logout.
132137
func (r *Collector) Test() (status int, err error) {
133138
_, status, err = r.client.system()

pkg/controller/provider/container/vsphere/collector.go

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package vsphere
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
liburl "net/url"
78
"path"
@@ -85,6 +86,7 @@ const (
8586
fThumbprint = "summary.config.sslThumbprint"
8687
fMgtServerIp = "summary.managementServerIp"
8788
fScsiLun = "config.storageDevice.scsiLun"
89+
fAdvancedOption = "configManager.advancedOption"
8890
// Network
8991
fTag = "tag"
9092
fSummary = "summary"
@@ -315,6 +317,24 @@ func (r *Collector) HasParity() bool {
315317
return r.parity
316318
}
317319

320+
// Follow
321+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
322+
ref, ok := moRef.(types.ManagedObjectReference)
323+
if !ok {
324+
return fmt.Errorf("reference must be of type ManagedObjectReference")
325+
}
326+
327+
ctx := context.Background()
328+
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
329+
defer cancel()
330+
client, err := r.buildClient(ctx)
331+
if err != nil {
332+
return err
333+
}
334+
defer client.CloseIdleConnections()
335+
return client.RetrieveOne(ctx, ref, p, dst)
336+
}
337+
318338
// Test connect/logout.
319339
func (r *Collector) Test() (status int, err error) {
320340
ctx := context.Background()
@@ -531,35 +551,39 @@ func (r *Collector) watch() (list []*libmodel.Watch) {
531551
// Build the client.
532552
func (r *Collector) connect(ctx context.Context) (status int, err error) {
533553
r.close()
534-
url, err := liburl.Parse(r.url)
554+
r.client, err = r.buildClient(ctx)
535555
if err != nil {
536-
err = liberr.Wrap(err)
556+
if strings.Contains(err.Error(), "incorrect") && strings.Contains(err.Error(), "password") {
557+
return http.StatusUnauthorized, err
558+
}
537559
return
538560
}
561+
562+
return http.StatusOK, nil
563+
}
564+
565+
// Build the client.
566+
func (r *Collector) buildClient(ctx context.Context) (*govmomi.Client, error) {
567+
url, err := liburl.Parse(r.url)
568+
if err != nil {
569+
return nil, liberr.Wrap(err)
570+
}
539571
url.User = liburl.UserPassword(
540572
r.user(),
541573
r.password())
542574
soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag())
543575
soapClient.SetThumbprint(url.Host, r.thumbprint())
544576
vimClient, err := vim25.NewClient(ctx, soapClient)
545577
if err != nil {
546-
err = liberr.Wrap(err)
547-
return
578+
return nil, liberr.Wrap(err)
548579
}
549-
r.client = &govmomi.Client{
580+
client := &govmomi.Client{
550581
SessionManager: session.NewManager(vimClient),
551582
Client: vimClient,
552583
}
553-
err = r.client.Login(ctx, url.User)
554-
if err != nil {
555-
err = liberr.Wrap(err)
556-
if strings.Contains(err.Error(), "incorrect") && strings.Contains(err.Error(), "password") {
557-
return http.StatusUnauthorized, err
558-
}
559-
return
560-
}
584+
err = client.Login(ctx, url.User)
585+
return client, err
561586

562-
return http.StatusOK, nil
563587
}
564588

565589
// Close connections.
@@ -702,6 +726,7 @@ func (r *Collector) propertySpec() []types.PropertySpec {
702726
fPNIC,
703727
fVNIC,
704728
fScsiLun,
729+
fAdvancedOption,
705730
},
706731
},
707732
{ // Network

pkg/controller/provider/container/vsphere/model.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ func (v *HostAdapter) Apply(u types.ObjectUpdate) {
382382
v.model.HostScsiDisks = append(v.model.HostScsiDisks, hostScsiDisk)
383383
}
384384
}
385+
case fAdvancedOption:
386+
v.model.AdvancedOptions = v.Ref(p.Val)
385387
}
386388
}
387389
}

pkg/controller/provider/model/vsphere/model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ type Host struct {
140140
Networks []Ref `sql:""`
141141
Datastores []Ref `sql:""`
142142
HostScsiDisks []HostScsiDisk `sql:""`
143+
AdvancedOptions Ref `sql:""`
143144
}
144145

145146
type HostScsiDisk struct {

pkg/controller/provider/web/vsphere/host.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ package vsphere
22

33
import (
44
"errors"
5+
"fmt"
56
"net/http"
67
"sort"
78
"strings"
89

910
"github.com/gin-gonic/gin"
1011
api "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1"
1112
model "github.com/konveyor/forklift-controller/pkg/controller/provider/model/vsphere"
13+
"github.com/vmware/govmomi/vim25/types"
14+
1215
"github.com/konveyor/forklift-controller/pkg/controller/provider/web/base"
1316
libmodel "github.com/konveyor/forklift-controller/pkg/lib/inventory/model"
17+
18+
"github.com/vmware/govmomi/vim25/mo"
1419
)
1520

1621
// Routes
@@ -124,13 +129,39 @@ func (h HostHandler) Get(ctx *gin.Context) {
124129
ctx.Status(http.StatusInternalServerError)
125130
return
126131
}
132+
133+
// Parse advancedOption query parameter
134+
h.parseAdvancedOptions(ctx, r, m)
135+
127136
r.Link(h.Provider)
128137
r.Path = pb.Path(m)
129138
content := r.Content(h.Detail)
130139

131140
ctx.JSON(http.StatusOK, content)
132141
}
133142

143+
func (h *HostHandler) parseAdvancedOptions(ctx *gin.Context, r *Host, m *model.Host) {
144+
// Check the advanced option is passed
145+
advancedOption := ctx.Query("advancedOption")
146+
if advancedOption == "" {
147+
return
148+
}
149+
150+
// Get settings of option manager
151+
optManagers := mo.OptionManager{}
152+
moRef := types.ManagedObjectReference{Type: m.AdvancedOptions.Kind, Value: m.AdvancedOptions.ID}
153+
if err := h.Collector.Follow(moRef, []string{"setting"}, &optManagers); err != nil {
154+
return
155+
}
156+
157+
// Find the option we are interested in:
158+
for _, option := range optManagers.Setting {
159+
if option.GetOptionValue().Key == advancedOption {
160+
r.AdvancedOptions = []AdvancedOptions{{Key: advancedOption, Value: fmt.Sprintf("%v", option.GetOptionValue().Value)}}
161+
}
162+
}
163+
}
164+
134165
// Watch.
135166
func (h *HostHandler) watch(ctx *gin.Context) {
136167
db := h.Collector.DB()
@@ -219,6 +250,12 @@ type Host struct {
219250
VMs []model.Ref `json:"vms"`
220251
NetworkAdapters []NetworkAdapter `json:"networkAdapters"`
221252
HostScsiDisks []model.HostScsiDisk `json:"hostScsiDisks"`
253+
AdvancedOptions []AdvancedOptions `json:"advancedOptions"`
254+
}
255+
256+
type AdvancedOptions struct {
257+
Key string `json:"key"`
258+
Value string `json:"value"`
222259
}
223260

224261
// Build the resource using the model.

pkg/lib/cmd/inventory/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ func (r *Collector) Name() string {
181181
return "tester"
182182
}
183183

184+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
185+
return nil
186+
}
187+
184188
func (r *Collector) Owner() meta.Object {
185189
return &meta.ObjectMeta{
186190
UID: "TEST",

pkg/lib/inventory/container/container.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ type Collector interface {
146146
// Return the status code of the connection
147147
// 0 = Ignore
148148
Test() (int, error)
149+
// Follow the link
150+
Follow(moRef interface{}, p []string, dst interface{}) error
149151
// Reset
150152
Reset()
151153
// Get the system version - currently, ovirt-only

pkg/lib/inventory/container/ocp/collector.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ocp
22

33
import (
44
"context"
5+
"fmt"
56
"path"
67
"time"
78

@@ -112,6 +113,11 @@ func (r *Collector) HasParity() bool {
112113
return r.parity
113114
}
114115

116+
// Follow link
117+
func (r *Collector) Follow(moRef interface{}, p []string, dst interface{}) error {
118+
return fmt.Errorf("not implemented")
119+
}
120+
115121
// Update the versionThreshold
116122
func (r *Collector) UpdateThreshold(m libmodel.Model) {
117123
if m, cast := m.(interface{ ResourceVersion() uint64 }); cast {

0 commit comments

Comments
 (0)