mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-03-15 07:00:14 -04:00
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.
246 lines
5.9 KiB
Go
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
|
|
}
|