package esx import ( "context" "fmt" "regexp" "esxlib/pkg/sshutil" "richat/pkg/utils" "github.com/vmware/govmomi/session/cache" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/soap" ) var diskRegexp = regexp.MustCompile("\\[(.*?)\\] (.*)") type Option func(c *Client) type Client struct { sshAuth *sshutil.Auth vim *vim25.Client props *HostProperties VirtualMachines VirtualMachines Networks Networks } type ClientRef interface { VIM() *vim25.Client hostExec(ctx context.Context, cmd string) error hostProperties() *HostProperties } func (c *Client) VIM() *vim25.Client { return c.vim } // hostExec runs a vim command using on the specific ssh host. // Workaround: if you are running the FREE license of ESX, the power management API is not available to you // IE: ServerFaultCode: Current license or ESXi version prohibits execution of the requested operation // so as an alternative you can provide the SSH auth to the server and we do it the gross way func (c *Client) hostExec(_ context.Context, cmd string) error { if c.sshAuth == nil { return fmt.Errorf("unsupported") } _, err := sshutil.CombinedOutput(sshutil.Auth{ User: c.sshAuth.User, Password: c.sshAuth.Password, Host: c.sshAuth.Host, }, cmd) if err != nil { fmt.Printf("cmd: %s err:%s\n", cmd, err.Error()) return err } fmt.Printf("cmd: %s OK\n", cmd) return nil } func (c *Client) hostProperties() *HostProperties { return c.props } func WithSSH(host, user, password string) Option { return func(c *Client) { c.sshAuth = &sshutil.Auth{ Host: host, User: user, Password: password, } } } func WithHostProperties(props *HostProperties) Option { return func(c *Client) { c.props = props } } func NewClient(ctx context.Context, url string, insecure bool, opts ...Option) (*Client, error) { // Parse URL from string u, err := soap.ParseURL(url) if err != nil { return nil, err } // Share govc's session cache s := &cache.Session{ URL: u, Insecure: insecure, } c := new(vim25.Client) err = s.Login(ctx, c, nil) if err != nil { return nil, err } client := &Client{ vim: c, props: &DefaultHostProperties, } for _, opt := range opts { opt(client) } client.VirtualMachines.ClientRef = client return client, nil } func NewClientFromConfigFile(configFile string) (*Client, error) { config := &Config{} err := utils.UnmarshalFromFile(configFile, config) if err != nil { return nil, err } return NewClientFromConfig(config) } func NewClientFromConfig(config *Config) (*Client, error) { vimURL, err := soap.ParseURL(fmt.Sprintf("https://%s:%s@%s", config.User, config.Password, config.Host)) if err != nil { return nil, err } sessionCache := &cache.Session{ URL: vimURL, Insecure: true, } c := new(vim25.Client) err = sessionCache.Login(context.Background(), c, nil) if err != nil { return nil, err } client := &Client{ vim: c, sshAuth: &sshutil.Auth{ Host: fmt.Sprintf("%s:22", config.Host), User: config.User, Password: config.Password, }, props: &config.HostDefaults, } client.VirtualMachines.ClientRef = client client.Networks.ClientRef = client return client, nil }