// Mkdir creates directories. func (d *Helper) Mkdir(ctx context.Context, createParentDirectories bool, dirs ...string) (string, error) { upth := path.Join(dirs...) upth = path.Join(d.RootURL, upth) log.Infof("Creating directory %s", upth) if err := d.fm.MakeDirectory(ctx, upth, d.s.Datacenter, createParentDirectories); err != nil { log.Debugf("Creating %s error: %s", upth, err) if err != nil { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return "", os.ErrExist } } } return "", err } return upth, nil }
func isTaskInProgress(err error) bool { if soap.IsSoapFault(err) { switch f := soap.ToSoapFault(err).VimFault().(type) { case types.TaskInProgress: return true default: logSoapFault(f) } } if soap.IsVimFault(err) { switch f := soap.ToVimFault(err).(type) { case *types.TaskInProgress: return true default: logFault(f) } } switch err := err.(type) { case task.Error: if _, ok := err.Fault().(*types.TaskInProgress); ok { return true } logFault(err.Fault()) default: if f, ok := err.(types.HasFault); ok { logFault(f.Fault()) } else { logError(err) } } return false }
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 (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { isVM := false switch flag.t { case SearchVirtualMachines: isVM = true case SearchHosts: default: panic("unsupported type") } var ref object.Reference var err error for _, iu := range []*bool{nil, types.NewBool(true)} { ref, err = flag.searchIndex(c).FindByUuid(context.TODO(), dc, flag.byUUID, isVM, iu) if err != nil { if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() if _, ok := fault.(types.InvalidArgument); ok { continue } } return nil, err } if ref != nil { break } } return ref, nil }
func isInvalidLogin(err error) bool { if soap.IsSoapFault(err) { switch soap.ToSoapFault(err).VimFault().(type) { case types.InvalidLogin: return true } } return false }
func isNotAuthenticated(err error) bool { if soap.IsSoapFault(err) { switch soap.ToSoapFault(err).VimFault().(type) { case types.NotAuthenticated: return true } } return false }
func (cmd *mkdir) Run(ctx context.Context, f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } if cmd.isNamespace { var uuid string var ds *object.Datastore if ds, err = cmd.Datastore(); err != nil { return err } path := args[0] nm := object.NewDatastoreNamespaceManager(c) if uuid, err = nm.CreateDirectory(ctx, ds, path, ""); err != nil { return err } fmt.Println(uuid) } else { var dc *object.Datacenter var path string dc, err = cmd.Datacenter() if err != nil { return err } path, err = cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) err = m.MakeDirectory(ctx, path, dc, cmd.createParents) // ignore EEXIST if -p flag is given if err != nil && cmd.createParents { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return nil } } } } return err }
func (m *Manager) isDuplicateName(err error) bool { if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err) if _, ok := fault.VimFault().(types.DuplicateName); ok { return true } } return false }
// This creates the root directory in the datastore and sets the rooturl and // rootdir in the datastore struct so we can reuse it for other routines. This // handles vsan + vc, vsan + esx, and esx. The URI conventions are not the // same for each and this tries to create the directory and stash the relevant // result so the URI doesn't need to be recomputed for every datastore // operation. func (d *Helper) mkRootDir(ctx context.Context, rootdir string) error { if rootdir == "" { return fmt.Errorf("root directory is empty") } if path.IsAbs(rootdir) { return fmt.Errorf("root directory (%s) must not be an absolute path", rootdir) } // Handle vsan // Vsan will complain if the root dir exists. Just call it directly and // swallow the error if it's already there. if d.IsVSAN(ctx) { comps := strings.Split(rootdir, "/") nm := object.NewDatastoreNamespaceManager(d.s.Vim25()) // This returns the vmfs path (including the datastore and directory // UUIDs). Use the directory UUID in future operations because it is // the stable path which we can use regardless of vsan state. uuid, err := nm.CreateDirectory(ctx, d.ds, comps[0], "") if err != nil { if !soap.IsSoapFault(err) { return err } soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); !ok { return err } // XXX UGLY HACK until we move this into the installer. Use the // display name if the dir exists since we can't get the UUID after the // directory is created. uuid = comps[0] err = nil } rootdir = path.Join(path.Base(uuid), path.Join(comps[1:]...)) } rooturl := d.ds.Path(rootdir) // create the rest of the root dir in case of vSAN, otherwise // create the full path if _, err := mkdir(ctx, d.s, d.fm, true, rooturl); err != nil { if !os.IsExist(err) { return err } log.Infof("datastore root %s already exists", rooturl) } d.RootURL = rooturl return nil }
func isToolsUnavailable(err error) bool { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.ToolsUnavailable); ok { return ok } } return false }
// This creates the root directory in the datastore and sets the rooturl and // rootdir in the datastore struct so we can reuse it for other routines. This // handles vsan + vc, vsan + esx, and esx. The URI conventions are not the // same for each and this tries to create the directory and stash the relevant // result so the URI doesn't need to be recomputed for every datastore // operation. func (d *Helper) mkRootDir(ctx context.Context, rootdir string) error { // Handle vsan // Vsan will complain if the root dir exists. Just call it directly and // swallow the error if it's already there. if d.IsVSAN(ctx) { nm := object.NewDatastoreNamespaceManager(d.s.Vim25()) // This returns the vmfs path (including the datastore and directory // UUIDs). Use the directory UUID in future operations because it is // the stable path which we can use regardless of vsan state. uuid, err := nm.CreateDirectory(ctx, d.ds, rootdir, "") if err != nil { if !soap.IsSoapFault(err) { return err } soapFault := soap.ToSoapFault(err) _, ok := soapFault.VimFault().(types.FileAlreadyExists) if ok { // XXX UGLY HACK until we move this into the installer. Use the // display name if the dir exists since we can't get the UUID after the // directory is created. uuid = rootdir err = nil } else { return err } } // set the root url to the UUID of the dir we created d.RootURL = d.ds.Path(path.Base(uuid)) log.Infof("Created store parent directory (%s) at %s", rootdir, d.RootURL) } else { // Handle regular local datastore // check if it already exists d.RootURL = d.ds.Path(rootdir) if _, err := d.Mkdir(ctx, true); err != nil { if os.IsExist(err) { log.Debugf("%s already exists", d.RootURL) return nil } return err } } return nil }
func mkdir(ctx context.Context, sess *session.Session, fm *object.FileManager, createParentDirectories bool, path string) (string, error) { log.Infof("Creating directory %s", path) if err := fm.MakeDirectory(ctx, path, sess.Datacenter, createParentDirectories); err != nil { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { log.Debugf("File already exists: %s", path) return "", os.ErrExist } } log.Debugf("Creating %s error: %s", path, err) return "", err } return path, nil }
// Creates a folder using the specified name. // If the intermediate level folders do not exist, // and the parameter createParents is true, // all the non-existent folders are created. func makeDirectoryInDatastore(c *govmomi.Client, dc *object.Datacenter, path string, createParents bool) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() fileManager := object.NewFileManager(c.Client) err := fileManager.MakeDirectory(ctx, path, dc, createParents) if err != nil { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return ErrFileAlreadyExist } } } return err }
func (cmd *create) Run(f *flag.FlagSet) error { var ctx = context.Background() hosts, err := cmd.HostSystems(f.Args()) if err != nil { return err } object := types.ManagedObjectReference{ Type: "Datastore", Value: fmt.Sprintf("%s:%s", cmd.RemoteHost, cmd.RemotePath), } for _, host := range hosts { ds, err := host.ConfigManager().DatastoreSystem(ctx) if err != nil { return err } _, err = ds.CreateNasDatastore(ctx, cmd.HostNasVolumeSpec) if err != nil { if soap.IsSoapFault(err) { switch fault := soap.ToSoapFault(err).VimFault().(type) { case types.PlatformConfigFault: if len(fault.FaultMessage) != 0 { return errors.New(fault.FaultMessage[0].Message) } case types.DuplicateName: if cmd.Force && fault.Object == object { fmt.Fprintf(os.Stderr, "%s: '%s' already mounted\n", host.InventoryPath, cmd.LocalPath) continue } } } return fmt.Errorf("%s: %s", host.InventoryPath, err) } } return nil }
func (cmd *mkdir) Run(ctx context.Context, f *flag.FlagSet) error { m, err := cmd.FileManager() if err != nil { return err } err = m.MakeDirectory(context.TODO(), cmd.Auth(), f.Arg(0), cmd.createParents) // ignore EEXIST if -p flag is given if err != nil && cmd.createParents { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return nil } } } return err }
func (cmd *mkdir) Run(f *flag.FlagSet) error { args := f.Args() if len(args) == 0 { return errors.New("missing operand") } c, err := cmd.Client() if err != nil { return err } dc, err := cmd.Datacenter() if err != nil { return err } // TODO(PN): Accept multiple args path, err := cmd.DatastorePath(args[0]) if err != nil { return err } m := object.NewFileManager(c) err = m.MakeDirectory(context.TODO(), path, dc, cmd.createParents) // ignore EEXIST if -p flag is given if err != nil && cmd.createParents { if soap.IsSoapFault(err) { soapFault := soap.ToSoapFault(err) if _, ok := soapFault.VimFault().(types.FileAlreadyExists); ok { return nil } } } return err }
func TestServeHTTPErrors(t *testing.T) { s := New(NewServiceInstance(esx.ServiceContent, esx.RootFolder)) ts := s.NewServer() defer ts.Close() ctx := context.Background() client, err := govmomi.NewClient(ctx, ts.URL, true) if err != nil { t.Fatal(err) } // unregister type, covering the ServeHTTP UnmarshalBody error path typeFunc = func(name string) (reflect.Type, bool) { return nil, false } _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } typeFunc = types.TypeFunc() // reset // cover the does not implement method error path Map.objects[serviceInstance] = &errorNoSuchMethod{} _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // cover the xml encode error path Map.objects[serviceInstance] = &errorMarshal{} _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // cover the no such object path Map.Remove(serviceInstance) _, err = methods.GetCurrentTime(ctx, client) if err == nil { t.Error("expected error") } // verify we properly marshal the fault fault := soap.ToSoapFault(err).VimFault() f, ok := fault.(types.ManagedObjectNotFound) if !ok { t.Fatalf("fault=%#v", fault) } if f.Obj != serviceInstance.Reference() { t.Errorf("obj=%#v", f.Obj) } // cover the method not supported path res, err := http.Get(ts.URL.String()) if err != nil { log.Fatal(err) } if res.StatusCode != http.StatusMethodNotAllowed { t.Errorf("expected status %d, got %s", http.StatusMethodNotAllowed, res.Status) } // cover the ioutil.ReadAll error path s.readAll = func(io.Reader) ([]byte, error) { return nil, io.ErrShortBuffer } res, err = http.Post(ts.URL.String(), "none", nil) if err != nil { log.Fatal(err) } if res.StatusCode != http.StatusBadRequest { t.Errorf("expected status %d, got %s", http.StatusBadRequest, res.Status) } }
func (c *Container) Remove(ctx context.Context, sess *session.Session) error { defer trace.End(trace.Begin("Container.Remove")) c.Lock() defer c.Unlock() if c.vm == nil { return NotFoundError{} } // check state first if c.State == StateRunning { return RemovePowerError{fmt.Errorf("Container is powered on")} } // get existing state and set to removing // if there's a failure we'll revert to existing existingState := c.State c.State = StateRemoving // get the folder the VM is in url, err := c.vm.DSPath(ctx) if err != nil { // handle the out-of-band removal case if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() if _, ok := fault.(types.ManagedObjectNotFound); ok { containers.Remove(c.ExecConfig.ID) return NotFoundError{} } } log.Errorf("Failed to get datastore path for %s: %s", c.ExecConfig.ID, err) c.State = existingState return err } // FIXME: was expecting to find a utility function to convert to/from datastore/url given // how widely it's used but couldn't - will ask around. dsPath := fmt.Sprintf("[%s] %s", url.Host, url.Path) //removes the vm from vsphere, but detaches the disks first _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.ResultWaiter, error) { return c.vm.DeleteExceptDisks(ctx) }) if err != nil { c.State = existingState return err } // remove from datastore fm := object.NewFileManager(c.vm.Client.Client) if _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.ResultWaiter, error) { return fm.DeleteDatastoreFile(ctx, dsPath, sess.Datacenter) }); err != nil { c.State = existingState log.Debugf("Failed to delete %s, %s", dsPath, err) } //remove container from cache containers.Remove(c.ExecConfig.ID) return nil }
// Remove removes a containerVM after detaching the disks func (c *Container) Remove(ctx context.Context, sess *session.Session) error { defer trace.End(trace.Begin(c.ExecConfig.ID)) c.m.Lock() defer c.m.Unlock() if c.vm == nil { return NotFoundError{} } // check state first if c.state == StateRunning { return RemovePowerError{fmt.Errorf("Container is powered on")} } // get existing state and set to removing // if there's a failure we'll revert to existing existingState := c.updateState(StateRemoving) // get the folder the VM is in url, err := c.vm.DSPath(ctx) if err != nil { // handle the out-of-band removal case if soap.IsSoapFault(err) { fault := soap.ToSoapFault(err).VimFault() if _, ok := fault.(types.ManagedObjectNotFound); ok { Containers.Remove(c.ExecConfig.ID) return NotFoundError{} } } log.Errorf("Failed to get datastore path for %s: %s", c.ExecConfig.ID, err) c.updateState(existingState) return err } // FIXME: was expecting to find a utility function to convert to/from datastore/url given // how widely it's used but couldn't - will ask around. dsPath := fmt.Sprintf("[%s] %s", url.Host, url.Path) //removes the vm from vsphere, but detaches the disks first _, err = c.vm.WaitForResult(ctx, func(ctx context.Context) (tasks.Task, error) { return c.vm.DeleteExceptDisks(ctx) }) if err != nil { f, ok := err.(types.HasFault) if !ok { c.updateState(existingState) return err } switch f.Fault().(type) { case *types.InvalidState: log.Warnf("container VM is in invalid state, unregistering") if err := c.vm.Unregister(ctx); err != nil { log.Errorf("Error while attempting to unregister container VM: %s", err) return err } default: log.Debugf("Fault while attempting to destroy vm: %#v", f.Fault()) c.updateState(existingState) return err } } // remove from datastore fm := object.NewFileManager(c.vm.Client.Client) if _, err = tasks.WaitForResult(ctx, func(ctx context.Context) (tasks.Task, error) { return fm.DeleteDatastoreFile(ctx, dsPath, sess.Datacenter) }); err != nil { // at this phase error doesn't matter. Just log it. log.Debugf("Failed to delete %s, %s", dsPath, err) } //remove container from cache Containers.Remove(c.ExecConfig.ID) return nil }