// Returns a client which communicates with vCenter. // This client can used to perform further vCenter operations. func vSphereLogin(vs *VSphere, ctx context.Context) error { var err error clientLock.Lock() defer clientLock.Unlock() if vs.client == nil { vs.client, err = newClient(vs.cfg, ctx) if err != nil { return err } return nil } m := session.NewManager(vs.client.Client) // retrieve client's current session u, err := m.UserSession(ctx) if err == nil && u == nil { // current session is valid return nil } glog.Warningf("Creating new client session since the existing session is not valid or not authenticated") vs.client.Logout(ctx) vs.client, err = newClient(vs.cfg, ctx) if err != nil { return err } return nil }
func (flag *ClientFlag) loadClient() (*vim25.Client, error) { c := new(vim25.Client) ok, err := flag.restoreClient(c) if err != nil { return nil, err } if !ok || !c.Valid() { return nil, nil } // Add retry functionality before making any calls c.RoundTripper = attachRetries(c.RoundTripper) m := session.NewManager(c) u, err := m.UserSession(context.TODO()) if err != nil { return nil, err } // If the session is nil, the client is not authenticated if u == nil { return nil, nil } return c, nil }
// Returns a client which communicates with vCenter. // This client can used to perform further vCenter operations. func vSphereLogin(ctx context.Context, vs *VSphere) error { var err error clientLock.Lock() defer clientLock.Unlock() if vs.client == nil { vs.client, err = newClient(ctx, vs.cfg) if err != nil { return err } return nil } m := session.NewManager(vs.client.Client) // retrieve client's current session u, err := m.UserSession(ctx) if err != nil { glog.Errorf("Error while obtaining user session. err: %q", err) return err } if u != nil { return nil } glog.Warningf("Creating new client session since the existing session is not valid or not authenticated") vs.client.Logout(ctx) vs.client, err = newClient(ctx, vs.cfg) if err != nil { return err } return nil }
func (flag *ClientFlag) newClient() (*vim25.Client, error) { sc := soap.NewClient(flag.url, flag.insecure) // Add retry functionality before making any calls rt := attachRetries(sc) c, err := vim25.NewClient(context.TODO(), rt) if err != nil { return nil, err } // Set client, since we didn't pass it in the constructor c.Client = sc m := session.NewManager(c) err = m.Login(context.TODO(), flag.url.User) if err != nil { return nil, err } err = flag.saveClient(c) if err != nil { return nil, err } return c, nil }
func (flag *ClientFlag) loadClient() (*vim25.Client, error) { c := new(vim25.Client) ok, err := flag.restoreClient(c) if err != nil { return nil, err } if !ok || !c.Valid() { return nil, nil } // Add retry functionality before making any calls c.RoundTripper = attachRetries(c.RoundTripper) m := session.NewManager(c) u, err := m.UserSession(context.TODO()) if err != nil { if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() // If the PropertyCollector is not found, the saved session for this URL is not valid if _, ok := fault.(types.ManagedObjectNotFound); ok { return nil, nil } } return nil, err } // If the session is nil, the client is not authenticated if u == nil { return nil, nil } return c, nil }
func (cmd *rm) Run(ctx context.Context, f *flag.FlagSet) error { c, err := cmd.Client() if err != nil { return err } return session.NewManager(c).TerminateSession(ctx, f.Args()) }
func (flag *ClientFlag) newClient() (*vim25.Client, error) { ctx := context.TODO() sc := soap.NewClient(flag.url, flag.insecure) isTunnel := false if flag.cert != "" { isTunnel = true cert, err := tls.LoadX509KeyPair(flag.cert, flag.key) if err != nil { return nil, err } sc.SetCertificate(cert) } rt, err := flag.configure(sc) if err != nil { return nil, err } c, err := vim25.NewClient(ctx, rt) if err != nil { return nil, err } // Set client, since we didn't pass it in the constructor c.Client = sc m := session.NewManager(c) u := flag.url.User if u.Username() == "" { // Assume we are running on an ESX or Workstation host if no username is provided u, err = flag.localTicket(ctx, m) if err != nil { return nil, err } } if isTunnel { err = m.LoginExtensionByCertificate(ctx, u.Username(), "") if err != nil { return nil, err } } else { err = m.Login(ctx, u) if err != nil { return nil, err } } err = flag.saveClient(c) if err != nil { return nil, err } return c, nil }
func (flag *ClientFlag) newClient() (*vim25.Client, error) { sc := soap.NewClient(flag.url, flag.insecure) isTunnel := false if flag.cert != "" { isTunnel = true cert, err := tls.LoadX509KeyPair(flag.cert, flag.key) if err != nil { return nil, err } sc.SetCertificate(cert) } // Set namespace and version sc.Namespace = flag.vimNamespace sc.Version = flag.vimVersion // Add retry functionality before making any calls rt := attachRetries(sc) c, err := vim25.NewClient(context.TODO(), rt) if err != nil { return nil, err } // Set client, since we didn't pass it in the constructor c.Client = sc m := session.NewManager(c) u := flag.url.User if u.Username() == "" { // Assume we are running on an ESX or Workstation host if no username is provided u, err = flag.localTicket(context.TODO(), m) if err != nil { return nil, err } } if isTunnel { err = m.LoginExtensionByCertificate(context.TODO(), u.Username(), "") if err != nil { return nil, err } } else { err = m.Login(context.TODO(), u) if err != nil { return nil, err } } err = flag.saveClient(c) if err != nil { return nil, err } return c, nil }
func (flag *ClientFlag) Logout(ctx context.Context) error { if flag.persist || flag.client == nil { return nil } m := session.NewManager(flag.client) return m.Logout(ctx) }
// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL // that can be used along with the ticket cookie to access the given path. func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) { // We are uploading to an ESX host u := &url.URL{ Scheme: d.c.URL().Scheme, Host: d.c.URL().Host, Path: fmt.Sprintf("/folder/%s", path), RawQuery: url.Values{ "dsName": []string{d.Name()}, }.Encode(), } // If connected to VC, the ticket request must be for an ESX host. if d.c.IsVC() { hosts, err := d.AttachedHosts(ctx) if err != nil { return nil, nil, err } if len(hosts) == 0 { return nil, nil, fmt.Errorf("no hosts attached to datastore %#v", d.Reference()) } // Pick a random attached host host := hosts[rand.Intn(len(hosts))] name, err := host.ObjectName(ctx) if err != nil { return nil, nil, err } u.Host = name } spec := types.SessionManagerHttpServiceRequestSpec{ Url: u.String(), // See SessionManagerHttpServiceRequestSpecMethod enum Method: fmt.Sprintf("http%s%s", method[0:1], strings.ToLower(method[1:])), } sm := session.NewManager(d.Client()) ticket, err := sm.AcquireGenericServiceTicket(ctx, &spec) if err != nil { return nil, nil, err } cookie := &http.Cookie{ Name: "vmware_cgi_ticket", Value: ticket.Id, } if d.useServiceTicketHostName(ticket.HostName) { u.Host = ticket.HostName } return u, cookie, nil }
func (flag *ClientFlag) newClient() (*vim25.Client, error) { sc := soap.NewClient(flag.url, flag.insecure) isTunnel := false if flag.cert != "" { isTunnel = true cert, err := tls.LoadX509KeyPair(flag.cert, flag.key) if err != nil { return nil, err } sc.SetCertificate(cert) } // Add retry functionality before making any calls rt := attachRetries(sc) c, err := vim25.NewClient(context.TODO(), rt) if err != nil { return nil, err } // Set client, since we didn't pass it in the constructor c.Client = sc m := session.NewManager(c) u := flag.url.User if isTunnel { err = m.LoginExtensionByCertificate(context.TODO(), u.Username(), "") if err != nil { return nil, err } } else { err = m.Login(context.TODO(), u) if err != nil { return nil, err } } err = flag.saveClient(c) if err != nil { return nil, err } return c, nil }
// NewClient creates a new client from a URL. The client authenticates with the // server with username/password before returning if the URL contains user information. func NewClient(ctx context.Context, u *url.URL, insecure bool) (*Client, error) { soapClient := soap.NewClient(u, insecure) vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil { return nil, err } c := &Client{ Client: vimClient, SessionManager: session.NewManager(vimClient), } // Only login if the URL contains user information. if u.User != nil { err = c.Login(ctx, u.User) if err != nil { return nil, err } } return c, nil }
// NewClientWithCertificate creates a new client from a URL. The client authenticates with the // server with the certificate before returning if the URL contains user information. func NewClientWithCertificate(ctx context.Context, u *url.URL, insecure bool, cert tls.Certificate) (*Client, error) { soapClient := soap.NewClient(u, insecure) soapClient.SetCertificate(cert) vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil { return nil, err } c := &Client{ Client: vimClient, SessionManager: session.NewManager(vimClient), } if u.User != nil { err = c.LoginExtensionByCertificate(ctx, u.User.Username(), "") if err != nil { return nil, err } } return c, nil }
// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL // that can be used along with the ticket cookie to access the given path. An host is chosen at random unless the // the given Context was created with a specific host via the HostContext method. func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) { u := d.NewURL(path) host, ok := ctx.Value(datastoreServiceTicketHostKey{}).(*HostSystem) if !ok { if !d.useServiceTicket() { return u, nil, nil } hosts, err := d.AttachedHosts(ctx) if err != nil { return nil, nil, err } if len(hosts) == 0 { // Fallback to letting vCenter choose a host return u, nil, nil } // Pick a random attached host host = hosts[rand.Intn(len(hosts))] } ips, err := host.ManagementIPs(ctx) if err != nil { return nil, nil, err } if len(ips) > 0 { // prefer a ManagementIP u.Host = ips[0].String() } else { // fallback to inventory name u.Host, err = host.ObjectName(ctx) if err != nil { return nil, nil, err } } // VC datacenter path will not be valid against ESX q := u.Query() delete(q, "dcPath") u.RawQuery = q.Encode() spec := types.SessionManagerHttpServiceRequestSpec{ Url: u.String(), // See SessionManagerHttpServiceRequestSpecMethod enum Method: fmt.Sprintf("http%s%s", method[0:1], strings.ToLower(method[1:])), } sm := session.NewManager(d.Client()) ticket, err := sm.AcquireGenericServiceTicket(ctx, &spec) if err != nil { return nil, nil, err } cookie := &http.Cookie{ Name: "vmware_cgi_ticket", Value: ticket.Id, } if d.useServiceTicketHostName(ticket.HostName) { u.Host = ticket.HostName } d.Client().SetThumbprint(u.Host, ticket.SslThumbprint) return u, cookie, nil }
// Connect establishes the connection for the session but nothing more func (s *Session) Connect(ctx context.Context) (*Session, error) { soapURL, err := soap.ParseURL(s.Service) if soapURL == nil || err != nil { return nil, errors.Errorf("SDK URL (%s) could not be parsed: %s", s.Service, err) } // LoginExtensionByCertificate proxies connections to a virtual host (sdkTunnel:8089) and // Go's http.Transport.DialTLS isn't called when using a proxy. Even if using a known CA, // "sdkTunnel" does not pass Go's tls.VerifyHostname check. // We are moving away from LoginExtensionByCertificate anyhow, so disable thumbprint checks for now. if s.HasCertificate() { s.Insecure = true } // Update the service URL with expanded defaults s.Service = soapURL.String() soapClient := soap.NewClient(soapURL, s.Insecure) var login func(context.Context) error if s.HasCertificate() { cert, err2 := tls.X509KeyPair([]byte(s.ExtensionCert), []byte(s.ExtensionKey)) if err2 != nil { return nil, errors.Errorf("Unable to load X509 key pair(%s,%s): %s", s.ExtensionCert, s.ExtensionKey, err2) } soapClient.SetCertificate(cert) log.Debugf("Logging in via extension %s certificate", s.ExtensionName) login = func(ctx context.Context) error { return s.LoginExtensionByCertificate(ctx, s.ExtensionName, "") } } else { log.Debugf("Logging in via username/password") login = func(ctx context.Context) error { return s.Client.Login(ctx, soapURL.User) } } soapClient.SetThumbprint(soapURL.Host, s.Thumbprint) // TODO: option to set http.Client.Transport.TLSClientConfig.RootCAs vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.Host, err) } if s.Keepalive != 0 { vimClient.RoundTripper = session.KeepAliveHandler(soapClient, s.Keepalive, func(roundTripper soap.RoundTripper) error { _, err := methods.GetCurrentTime(context.Background(), roundTripper) if err == nil { return nil } log.Warnf("session keepalive error: %s", err) if isNotAuthenticated(err) { if err = login(ctx); err != nil { log.Errorf("session keepalive failed to re-authenticate: %s", err) } else { log.Info("session keepalive re-authenticated") } } return nil }) } // TODO: get rid of govmomi.Client usage, only provides a few helpers we don't need. s.Client = &govmomi.Client{ Client: vimClient, SessionManager: session.NewManager(vimClient), } err = login(ctx) if err != nil { return nil, errors.Errorf("Failed to log in to %s: %s", soapURL.Host, err) } s.Finder = find.NewFinder(s.Vim25(), false) // log high-level environment information s.logEnvironmentInfo() return s, nil }