func (s *modelconfigSuite) assertBlocked(c *gc.C, err error, msg string) { c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err)) c.Assert(errors.Cause(err), jc.DeepEquals, ¶ms.Error{ Message: msg, Code: "operation is blocked", }) }
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed // in a user-friendly manner with readable and digestable error message. func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error { if destroyErr == nil { return nil } if params.IsCodeOperationBlocked(destroyErr) { logger.Errorf(`there are blocks preventing controller destruction To remove all blocks in the controller, please run: juju controller remove-blocks `) if api != nil { envs, err := api.ListBlockedEnvironments() var bytes []byte if err == nil { bytes, err = formatTabularBlockedEnvironments(envs) } if err != nil { logger.Errorf("Unable to list blocked environments: %s", err) return cmd.ErrSilent } ctx.Infof(string(bytes)) } return cmd.ErrSilent } logger.Errorf(stdFailureMsg, c.EnvName()) return destroyErr }
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed // in a user-friendly manner with readable and digestable error message. func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error { if destroyErr == nil { return nil } if params.IsCodeOperationBlocked(destroyErr) { logger.Errorf(destroyControllerBlockedMsg) if api != nil { models, err := api.ListBlockedModels() out := &bytes.Buffer{} if err == nil { var info interface{} info, err = block.FormatModelBlockInfo(models) if err != nil { return errors.Trace(err) } err = block.FormatTabularBlockedModels(out, info) } if err != nil { logger.Errorf("Unable to list models: %s", err) return cmd.ErrSilent } ctx.Infof(out.String()) } return cmd.ErrSilent } if params.IsCodeHasHostedModels(destroyErr) { return destroyErr } logger.Errorf(stdFailureMsg, c.ControllerName()) return destroyErr }
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed // in a user-friendly manner with readable and digestable error message. func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error { if destroyErr == nil { return nil } if params.IsCodeOperationBlocked(destroyErr) { logger.Errorf(destroyControllerBlockedMsg) if api != nil { models, err := api.ListBlockedModels() var bytes []byte if err == nil { bytes, err = formatTabularBlockedModels(models) } if err != nil { logger.Errorf("Unable to list blocked models: %s", err) return cmd.ErrSilent } ctx.Infof(string(bytes)) } return cmd.ErrSilent } if params.IsCodeHasHostedModels(destroyErr) { return destroyErr } logger.Errorf(stdFailureMsg, c.ControllerName()) return destroyErr }
func (s *clientSuite) AssertBlocked(c *gc.C, err error, msg string) { c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err)) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: msg, Code: "operation is blocked", }) }
func (s *blockCheckerSuite) assertErrorBlocked(c *gc.C, blocked bool, err error, msg string) { if blocked { c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) c.Assert(err, gc.ErrorMatches, msg) } else { c.Assert(errors.Cause(err), jc.ErrorIsNil) } }
// processDestroyError determines how to format error message based on its code. // Note that CodeNotImplemented errors have not be propogated in previous implementation. // This behaviour was preserved. func processDestroyError(err error) error { if err == nil || params.IsCodeNotImplemented(err) { return nil } if params.IsCodeOperationBlocked(err) { return err } return errors.Annotate(err, "destroying environment") }
func (c *destroyCommand) handleError(err error) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(`failed to destroy environment %q`, c.envName) return err }
func (c *destroyCommand) handleError(err error, modelName string) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(`failed to destroy model %q`, modelName) return err }
// ProcessBlockedError ensures that correct and user-friendly message is // displayed to the user based on the block type. func ProcessBlockedError(err error, block Block) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { logger.Errorf("\n%v%v", err, blockedMessages[block]) return cmd.ErrSilent } return err }
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed // in a user-friendly manner with readable and digestable error message. func (c *destroyEnvironmentCommand) ensureUserFriendlyErrorLog(err error) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockDestroy) } logger.Errorf(stdFailureMsg, c.EnvName()) return err }
// ProcessBlockedError ensures that correct and user-friendly message is // displayed to the user based on the block type. func ProcessBlockedError(err error, block Block) error { if err == nil { return nil } if params.IsCodeOperationBlocked(err) { msg := blockedMessages[block] logger.Errorf("%v\n%v", err, msg) return errors.New(msg) } return err }
func (s *destroyControllerSuite) TestDestroyControllerNoHostedEnvsWithBlockFail(c *gc.C) { err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) s.BlockDestroyModel(c, "TestBlockDestroyModel") s.BlockRemoveObject(c, "TestBlockRemoveObject") err = s.controller.DestroyController(params.DestroyControllerArgs{}) c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) numBlocks, err := s.State.AllBlocksForController() c.Assert(err, jc.ErrorIsNil) c.Assert(len(numBlocks), gc.Equals, 2) }
func (s *destroySystemSuite) TestDestroySystemNoHostedEnvsWithBlockFail(c *gc.C) { err := common.DestroyEnvironment(s.State, s.otherState.EnvironTag()) c.Assert(err, jc.ErrorIsNil) s.BlockDestroyEnvironment(c, "TestBlockDestroyEnvironment") s.BlockRemoveObject(c, "TestBlockRemoveObject") err = s.systemManager.DestroySystem(params.DestroySystemArgs{}) c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) numBlocks, err := s.State.AllBlocksForSystem() c.Assert(err, jc.ErrorIsNil) c.Assert(len(numBlocks), gc.Equals, 2) }
func (s *destroySystemSuite) TestDestroySystemReturnsBlockedEnvironmentsErr(c *gc.C) { s.BlockDestroyEnvironment(c, "TestBlockDestroyEnvironment") s.BlockRemoveObject(c, "TestBlockRemoveObject") s.otherState.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyEnvironment") s.otherState.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") err := s.systemManager.DestroySystem(params.DestroySystemArgs{ DestroyEnvironments: true, }) c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) numBlocks, err := s.State.AllBlocksForSystem() c.Assert(err, jc.ErrorIsNil) c.Assert(len(numBlocks), gc.Equals, 4) _, err = s.otherState.Environment() c.Assert(err, jc.ErrorIsNil) }
func (s *destroyControllerSuite) TestDestroyControllerReturnsBlockedEnvironmentsErr(c *gc.C) { s.BlockDestroyModel(c, "TestBlockDestroyModel") s.BlockRemoveObject(c, "TestBlockRemoveObject") s.otherState.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") s.otherState.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") err := s.controller.DestroyController(params.DestroyControllerArgs{ DestroyModels: true, }) c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) numBlocks, err := s.State.AllBlocksForController() c.Assert(err, jc.ErrorIsNil) c.Assert(len(numBlocks), gc.Equals, 4) _, err = s.otherState.Model() c.Assert(err, jc.ErrorIsNil) }
func (c *addCommand) Run(ctx *cmd.Context) error { var err error c.Constraints, err = common.ParseConstraints(ctx, c.ConstraintsStr) if err != nil { return err } client, err := c.getClientAPI() if err != nil { return errors.Trace(err) } defer client.Close() var machineManager MachineManagerAPI if len(c.Disks) > 0 { machineManager, err = c.getMachineManagerAPI() if err != nil { return errors.Trace(err) } defer machineManager.Close() if machineManager.BestAPIVersion() < 1 { return errors.New("cannot add machines with disks: not supported by the API server") } } logger.Infof("load config") modelConfigClient, err := c.getModelConfigAPI() if err != nil { return errors.Trace(err) } defer modelConfigClient.Close() configAttrs, err := modelConfigClient.ModelGet() if err != nil { if params.IsCodeUnauthorized(err) { common.PermissionsMessage(ctx.Stderr, "add a machine to this model") } return errors.Trace(err) } config, err := config.New(config.NoDefaults, configAttrs) if err != nil { return errors.Trace(err) } if c.Placement != nil && c.Placement.Scope == "ssh" { logger.Infof("manual provisioning") authKeys, err := common.ReadAuthorizedKeys(ctx, "") if err != nil { return errors.Annotate(err, "reading authorized-keys") } args := manual.ProvisionMachineArgs{ Host: c.Placement.Directive, Client: client, Stdin: ctx.Stdin, Stdout: ctx.Stdout, Stderr: ctx.Stderr, AuthorizedKeys: authKeys, UpdateBehavior: ¶ms.UpdateBehavior{ config.EnableOSRefreshUpdate(), config.EnableOSUpgrade(), }, } machineId, err := manualProvisioner(args) if err == nil { ctx.Infof("created machine %v", machineId) } return err } logger.Infof("model provisioning") if c.Placement != nil && c.Placement.Scope == "model-uuid" { uuid, ok := client.ModelUUID() if !ok { return errors.New("API connection is controller-only (should never happen)") } c.Placement.Scope = uuid } if c.Placement != nil && c.Placement.Scope == instance.MachineScope { // It does not make sense to add-machine <id>. return errors.Errorf("machine-id cannot be specified when adding machines") } jobs := []multiwatcher.MachineJob{multiwatcher.JobHostUnits} machineParams := params.AddMachineParams{ Placement: c.Placement, Series: c.Series, Constraints: c.Constraints, Jobs: jobs, Disks: c.Disks, } machines := make([]params.AddMachineParams, c.NumMachines) for i := 0; i < c.NumMachines; i++ { machines[i] = machineParams } var results []params.AddMachinesResult // If storage is specified, we attempt to use a new API on the service facade. if len(c.Disks) > 0 { results, err = machineManager.AddMachines(machines) } else { results, err = client.AddMachines(machines) } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockChange) } if err != nil { return errors.Trace(err) } errs := []error{} for _, machineInfo := range results { if machineInfo.Error != nil { errs = append(errs, machineInfo.Error) continue } machineId := machineInfo.Machine if names.IsContainerMachine(machineId) { ctx.Infof("created container %v", machineId) } else { ctx.Infof("created machine %v", machineId) } } if len(errs) == 1 { fmt.Fprint(ctx.Stderr, "failed to create 1 machine\n") return errs[0] } if len(errs) > 1 { fmt.Fprintf(ctx.Stderr, "failed to create %d machines\n", len(errs)) returnErr := []string{} for _, e := range errs { returnErr = append(returnErr, e.Error()) } return errors.New(strings.Join(returnErr, ", ")) } return nil }
// AssertBlocked checks if given error is // related to switched block. func (s BlockHelper) AssertBlocked(c *gc.C, err error, msg string) { c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err)) c.Assert(err, gc.ErrorMatches, msg) }
func (c *addCommand) Run(ctx *cmd.Context) error { client, err := c.getClientAPI() if err != nil { return errors.Trace(err) } defer client.Close() var machineManager MachineManagerAPI if len(c.Disks) > 0 { machineManager, err = c.getMachineManagerAPI() if err != nil { return errors.Trace(err) } defer machineManager.Close() if machineManager.BestAPIVersion() < 1 { return errors.New("cannot add machines with disks: not supported by the API server") } } logger.Infof("load config") configAttrs, err := client.ModelGet() if err != nil { return errors.Trace(err) } config, err := config.New(config.NoDefaults, configAttrs) if err != nil { return errors.Trace(err) } if c.Placement != nil && c.Placement.Scope == "ssh" { logger.Infof("manual provisioning") args := manual.ProvisionMachineArgs{ Host: c.Placement.Directive, Client: client, Stdin: ctx.Stdin, Stdout: ctx.Stdout, Stderr: ctx.Stderr, UpdateBehavior: ¶ms.UpdateBehavior{ config.EnableOSRefreshUpdate(), config.EnableOSUpgrade(), }, } machineId, err := manualProvisioner(args) if err == nil { ctx.Infof("created machine %v", machineId) } return err } logger.Infof("model provisioning") if c.Placement != nil && c.Placement.Scope == "model-uuid" { c.Placement.Scope = client.ModelUUID() } if c.Placement != nil && c.Placement.Scope == instance.MachineScope { // It does not make sense to add-machine <id>. return fmt.Errorf("machine-id cannot be specified when adding machines") } jobs := []multiwatcher.MachineJob{multiwatcher.JobHostUnits} // In case of MAAS and Joyent JobManageNetworking is not added // to ensure the non-intrusive start of a networker like above // for the manual provisioning. See this related joyent bug // http://pad.lv/1401423 if config.Type() != provider.MAAS && config.Type() != provider.Joyent { jobs = append(jobs, multiwatcher.JobManageNetworking) } machineParams := params.AddMachineParams{ Placement: c.Placement, Series: c.Series, Constraints: c.Constraints, Jobs: jobs, Disks: c.Disks, } machines := make([]params.AddMachineParams, c.NumMachines) for i := 0; i < c.NumMachines; i++ { machines[i] = machineParams } var results []params.AddMachinesResult // If storage is specified, we attempt to use a new API on the service facade. if len(c.Disks) > 0 { results, err = machineManager.AddMachines(machines) } else { results, err = client.AddMachines(machines) } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockChange) } if err != nil { return errors.Trace(err) } errs := []error{} for _, machineInfo := range results { if machineInfo.Error != nil { errs = append(errs, machineInfo.Error) continue } machineId := machineInfo.Machine if names.IsContainerMachine(machineId) { ctx.Infof("created container %v", machineId) } else { ctx.Infof("created machine %v", machineId) } } if len(errs) == 1 { fmt.Fprintf(ctx.Stderr, "failed to create 1 machine\n") return errs[0] } if len(errs) > 1 { fmt.Fprintf(ctx.Stderr, "failed to create %d machines\n", len(errs)) returnErr := []string{} for _, e := range errs { returnErr = append(returnErr, e.Error()) } return errors.New(strings.Join(returnErr, ", ")) } return nil }
func (s *baseStorageSuite) assertBlocked(c *gc.C, err error, msg string) { c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) c.Assert(err, gc.ErrorMatches, msg) }
func (c *addCommand) Run(ctx *cmd.Context) error { client, err := c.getClientAPI() if err != nil { return errors.Trace(err) } defer client.Close() var machineManager MachineManagerAPI if len(c.Disks) > 0 { machineManager, err = c.getMachineManagerAPI() if err != nil { return errors.Trace(err) } defer machineManager.Close() if machineManager.BestAPIVersion() < 1 { return errors.New("cannot add machines with disks: not supported by the API server") } } logger.Infof("load config") var config *config.Config if defaultStore, err := configstore.Default(); err != nil { return err } else if config, err = c.Config(defaultStore, client); err != nil { return err } if c.Placement != nil && c.Placement.Scope == "ssh" { logger.Infof("manual provisioning") args := manual.ProvisionMachineArgs{ Host: c.Placement.Directive, Client: client, Stdin: ctx.Stdin, Stdout: ctx.Stdout, Stderr: ctx.Stderr, UpdateBehavior: ¶ms.UpdateBehavior{ config.EnableOSRefreshUpdate(), config.EnableOSUpgrade(), }, } machineId, err := manualProvisioner(args) if err == nil { ctx.Infof("created machine %v", machineId) } return err } logger.Infof("environment provisioning") if c.Placement != nil && c.Placement.Scope == "env-uuid" { c.Placement.Scope = client.EnvironmentUUID() } if c.Placement != nil && c.Placement.Scope == instance.MachineScope { // It does not make sense to add-machine <id>. return fmt.Errorf("machine-id cannot be specified when adding machines") } jobs := []multiwatcher.MachineJob{multiwatcher.JobHostUnits} envVersion, err := envcmd.GetEnvironmentVersion(client) if err != nil { return err } // Servers before 1.21-alpha2 don't have the networker so don't // try to use JobManageNetworking with them. // // In case of MAAS and Joyent JobManageNetworking is not added // to ensure the non-intrusive start of a networker like above // for the manual provisioning. See this related joyent bug // http://pad.lv/1401423 if envVersion.Compare(version.MustParse("1.21-alpha2")) >= 0 && config.Type() != provider.MAAS && config.Type() != provider.Joyent { jobs = append(jobs, multiwatcher.JobManageNetworking) } machineParams := params.AddMachineParams{ Placement: c.Placement, Series: c.Series, Constraints: c.Constraints, Jobs: jobs, Disks: c.Disks, } machines := make([]params.AddMachineParams, c.NumMachines) for i := 0; i < c.NumMachines; i++ { machines[i] = machineParams } var results []params.AddMachinesResult // If storage is specified, we attempt to use a new API on the service facade. if len(c.Disks) > 0 { results, err = machineManager.AddMachines(machines) } else { results, err = client.AddMachines(machines) if params.IsCodeNotImplemented(err) { if c.Placement != nil { containerType, parseErr := instance.ParseContainerType(c.Placement.Scope) if parseErr != nil { // The user specified a non-container placement directive: // return original API not implemented error. return err } machineParams.ContainerType = containerType machineParams.ParentId = c.Placement.Directive machineParams.Placement = nil } logger.Infof( "AddMachinesWithPlacement not supported by the API server, " + "falling back to 1.18 compatibility mode", ) results, err = client.AddMachines1dot18([]params.AddMachineParams{machineParams}) } } if params.IsCodeOperationBlocked(err) { return block.ProcessBlockedError(err, block.BlockChange) } if err != nil { return errors.Trace(err) } errs := []error{} for _, machineInfo := range results { if machineInfo.Error != nil { errs = append(errs, machineInfo.Error) continue } machineId := machineInfo.Machine if names.IsContainerMachine(machineId) { ctx.Infof("created container %v", machineId) } else { ctx.Infof("created machine %v", machineId) } } if len(errs) == 1 { fmt.Fprintf(ctx.Stderr, "failed to create 1 machine\n") return errs[0] } if len(errs) > 1 { fmt.Fprintf(ctx.Stderr, "failed to create %d machines\n", len(errs)) returnErr := []string{} for _, e := range errs { returnErr = append(returnErr, e.Error()) } return errors.New(strings.Join(returnErr, ", ")) } return nil }