Files
opentf/vendor/github.com/hmrc/vmware-govcd/api_vcd.go
James Bardin cfa299d2ee Update deps in unknown state and rever nomad
Nomad was manually updated, so revert that to the version in master,
remove it from vendor.json and add it to the ignore list.

Update all packages that were in an unknown state to their latest master
commits.
2017-01-19 20:10:17 -05:00

246 lines
5.9 KiB
Go

package govcd
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"os"
"sync"
"time"
)
type VCDClient struct {
OrgHREF url.URL // vCloud Director OrgRef
Org Org // Org
OrgVdc Vdc // Org vDC
Client Client // Client for the underlying VCD instance
sessionHREF url.URL // HREF for the session API
QueryHREF url.URL // HREF for the query API
Mutex sync.Mutex
}
type supportedVersions struct {
VersionInfo struct {
Version string `xml:"Version"`
LoginUrl string `xml:"LoginUrl"`
} `xml:"VersionInfo"`
}
func (c *VCDClient) vcdloginurl() error {
s := c.Client.VCDVDCHREF
s.Path += "/versions"
// No point in checking for errors here
req := c.Client.NewRequest(map[string]string{}, "GET", s, nil)
resp, err := checkResp(c.Client.Http.Do(req))
if err != nil {
return err
}
defer resp.Body.Close()
supportedVersions := new(supportedVersions)
err = decodeBody(resp, supportedVersions)
if err != nil {
return fmt.Errorf("error decoding versions response: %s", err)
}
u, err := url.Parse(supportedVersions.VersionInfo.LoginUrl)
if err != nil {
return fmt.Errorf("couldn't find a LoginUrl in versions")
}
c.sessionHREF = *u
return nil
}
func (c *VCDClient) vcdauthorize(user, pass, org string) error {
if user == "" {
user = os.Getenv("VCLOUD_USERNAME")
}
if pass == "" {
pass = os.Getenv("VCLOUD_PASSWORD")
}
if org == "" {
org = os.Getenv("VCLOUD_ORG")
}
// No point in checking for errors here
req := c.Client.NewRequest(map[string]string{}, "POST", c.sessionHREF, nil)
// Set Basic Authentication Header
req.SetBasicAuth(user+"@"+org, pass)
// Add the Accept header for vCA
req.Header.Add("Accept", "application/*+xml;version=5.5")
resp, err := checkResp(c.Client.Http.Do(req))
if err != nil {
return err
}
defer resp.Body.Close()
// Store the authentication header
c.Client.VCDToken = resp.Header.Get("x-vcloud-authorization")
c.Client.VCDAuthHeader = "x-vcloud-authorization"
session := new(session)
err = decodeBody(resp, session)
if err != nil {
fmt.Errorf("error decoding session response: %s", err)
}
org_found := false
// Loop in the session struct to find the organization and query api.
for _, s := range session.Link {
if s.Type == "application/vnd.vmware.vcloud.org+xml" && s.Rel == "down" {
u, err := url.Parse(s.HREF)
if err != nil {
return fmt.Errorf("couldn't find a Organization in current session, %v", err)
}
c.OrgHREF = *u
org_found = true
}
if s.Type == "application/vnd.vmware.vcloud.query.queryList+xml" && s.Rel == "down" {
u, err := url.Parse(s.HREF)
if err != nil {
return fmt.Errorf("couldn't find a Query API in current session, %v", err)
}
c.QueryHREF = *u
}
}
if !org_found {
return fmt.Errorf("couldn't find a Organization in current session")
}
// Loop in the session struct to find the session url.
session_found := false
for _, s := range session.Link {
if s.Rel == "remove" {
u, err := url.Parse(s.HREF)
if err != nil {
return fmt.Errorf("couldn't find a logout HREF in current session, %v", err)
}
c.sessionHREF = *u
session_found = true
}
}
if !session_found {
return fmt.Errorf("couldn't find a logout HREF in current session")
}
return nil
}
func (c *VCDClient) RetrieveOrg(vcdname string) (Org, error) {
req := c.Client.NewRequest(map[string]string{}, "GET", c.OrgHREF, nil)
req.Header.Add("Accept", "vnd.vmware.vcloud.org+xml;version=5.5")
// TODO: wrap into checkresp to parse error
resp, err := checkResp(c.Client.Http.Do(req))
if err != nil {
return Org{}, fmt.Errorf("error retreiving org: %s", err)
}
org := NewOrg(&c.Client)
if err = decodeBody(resp, org.Org); err != nil {
return Org{}, fmt.Errorf("error decoding org response: %s", err)
}
// Get the VDC ref from the Org
for _, s := range org.Org.Link {
if s.Type == "application/vnd.vmware.vcloud.vdc+xml" && s.Rel == "down" {
if vcdname != "" && s.Name != vcdname {
continue
}
u, err := url.Parse(s.HREF)
if err != nil {
return Org{}, err
}
c.Client.VCDVDCHREF = *u
}
}
if &c.Client.VCDVDCHREF == nil {
return Org{}, fmt.Errorf("error finding the organization VDC HREF")
}
return *org, nil
}
func NewVCDClient(vcdEndpoint url.URL, insecure bool) *VCDClient {
return &VCDClient{
Client: Client{
APIVersion: "5.5",
VCDVDCHREF: vcdEndpoint,
Http: http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 120 * time.Second,
},
},
},
}
}
// Authenticate is an helper function that performs a login in vCloud Director.
func (c *VCDClient) Authenticate(username, password, org, vdcname string) (Org, Vdc, error) {
// LoginUrl
err := c.vcdloginurl()
if err != nil {
return Org{}, Vdc{}, fmt.Errorf("error finding LoginUrl: %s", err)
}
// Authorize
err = c.vcdauthorize(username, password, org)
if err != nil {
return Org{}, Vdc{}, fmt.Errorf("error authorizing: %s", err)
}
// Get Org
o, err := c.RetrieveOrg(vdcname)
if err != nil {
return Org{}, Vdc{}, fmt.Errorf("error acquiring Org: %s", err)
}
vdc, err := c.Client.retrieveVDC()
if err != nil {
return Org{}, Vdc{}, fmt.Errorf("error retrieving the organization VDC")
}
return o, vdc, nil
}
// Disconnect performs a disconnection from the vCloud Director API endpoint.
func (c *VCDClient) Disconnect() error {
if c.Client.VCDToken == "" && c.Client.VCDAuthHeader == "" {
return fmt.Errorf("cannot disconnect, client is not authenticated")
}
req := c.Client.NewRequest(map[string]string{}, "DELETE", c.sessionHREF, nil)
// Add the Accept header for vCA
req.Header.Add("Accept", "application/xml;version=5.5")
// Set Authorization Header
req.Header.Add(c.Client.VCDAuthHeader, c.Client.VCDToken)
if _, err := checkResp(c.Client.Http.Do(req)); err != nil {
return fmt.Errorf("error processing session delete for vCloud Director: %s", err)
}
return nil
}