Skip to content

Commit

Permalink
Resolve conflicts and get the tests passing.
Browse files Browse the repository at this point in the history
  • Loading branch information
howbazaar committed Aug 24, 2017
2 parents d8f9d83 + 4ba2790 commit 4dace8f
Show file tree
Hide file tree
Showing 99 changed files with 2,253 additions and 565 deletions.
19 changes: 19 additions & 0 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ type Config interface {
// successfully run, which is also the same as the initially deployed version.
UpgradedToVersion() version.Number

// LoggingConfig returns the logging config for this agent. Initially this
// value is empty, but as the agent gets notified of model agent config
// changes this value is saved.
LoggingConfig() string

// Value returns the value associated with the key, or an empty string if
// the key is not found.
Value(key string) string
Expand Down Expand Up @@ -309,6 +314,9 @@ type configSetterOnly interface {
// SetMongoMemoryProfile sets the passed policy as the one to be
// used.
SetMongoMemoryProfile(mongo.MemoryProfile)

// SetLoggingConfig sets the logging config value for the agent.
SetLoggingConfig(string)
}

// LogFileName returns the filename for the Agent's log file.
Expand Down Expand Up @@ -365,6 +373,7 @@ type configInternal struct {
apiDetails *connectionDetails
oldPassword string
servingInfo *params.StateServingInfo
loggingConfig string
values map[string]string
mongoVersion string
mongoMemoryProfile string
Expand Down Expand Up @@ -578,6 +587,16 @@ func (c *configInternal) SetValue(key, value string) {
}
}

// LoggingConfig implements Config.
func (c *configInternal) LoggingConfig() string {
return c.loggingConfig
}

// SetLoggingConfig implements configSetterOnly.
func (c *configInternal) SetLoggingConfig(value string) {
c.loggingConfig = value
}

func (c *configInternal) SetOldPassword(oldPassword string) {
c.oldPassword = oldPassword
}
Expand Down
7 changes: 5 additions & 2 deletions agent/format-2.0.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ type format_2_0Serialization struct {
APIAddresses []string `yaml:"apiaddresses,omitempty"`
APIPassword string `yaml:"apipassword,omitempty"`

OldPassword string `yaml:"oldpassword,omitempty"`
Values map[string]string `yaml:"values"`
OldPassword string `yaml:"oldpassword,omitempty"`
LoggingConfig string `yaml:"loggingconfig,omitempty"`
Values map[string]string `yaml:"values"`

// Only controller machines have these next items set.
ControllerCert string `yaml:"controllercert,omitempty"`
Expand Down Expand Up @@ -100,6 +101,7 @@ func (formatter_2_0) unmarshal(data []byte) (*configInternal, error) {
model: modelTag,
caCert: format.CACert,
oldPassword: format.OldPassword,
loggingConfig: format.LoggingConfig,
values: format.Values,
}
if len(format.StateAddresses) > 0 {
Expand Down Expand Up @@ -173,6 +175,7 @@ func (formatter_2_0) marshal(config *configInternal) ([]byte, error) {
Model: modelTag,
CACert: string(config.caCert),
OldPassword: config.oldPassword,
LoggingConfig: config.loggingConfig,
Values: config.values,
}
if config.servingInfo != nil {
Expand Down
16 changes: 16 additions & 0 deletions agent/format-2.0_whitebox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ func (*format_2_0Suite) TestReadConfWithExisting2_0ConfigFileContents(c *gc.C) {
c.Assert(config.Jobs(), jc.DeepEquals, []multiwatcher.MachineJob{multiwatcher.JobManageModel})
}

func (*format_2_0Suite) TestMarshalUnmarshal(c *gc.C) {
loggingConfig := "juju=INFO;unit=INFO"
config := newTestConfig(c)
// configFilePath is not serialized as it is the location of the file.
config.configFilePath = ""
config.SetLoggingConfig(loggingConfig)

data, err := format_2_0.marshal(config)
c.Assert(err, jc.ErrorIsNil)
newConfig, err := format_2_0.unmarshal(data)
c.Assert(err, jc.ErrorIsNil)

c.Check(newConfig, gc.DeepEquals, config)
c.Check(newConfig.LoggingConfig(), gc.Equals, loggingConfig)
}

var agentConfig2_0Contents = `
# format 2.0
controller: controller-deadbeef-1bad-500d-9000-4b1d0d06f00d
Expand Down
9 changes: 8 additions & 1 deletion agent/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ func registerFormat(format formatter) {
// - Create a formatter for the new version (including a marshal() method);
// - Call registerFormat in the new format's init() function.
// - Change this to point to the new format;
// - Remove the marshal() method from the old format;
//
// When a new format version is introduced there is going to need to be some
// refactoring around the config writing when provisioning a machine as the
// controller may well understand a config format that the model does not. So
// when generating the agent.conf for the model's machine, it needs to be
// written out in a format that the model can understand. Right now it will be
// written out in the format that the controller understands, and that will
// not continue to be correct.

// currentFormat holds the current agent config version's formatter.
var currentFormat = format_2_0
Expand Down
15 changes: 15 additions & 0 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ func (c *Client) ForceDestroyMachines(machines ...string) error {
return c.facade.FacadeCall("DestroyMachines", params, nil)
}

// DestroyMachinesWithParams removes a given set of machines and all associated units.
//
// NOTE(wallyworld) this exists only for backwards compatibility, when MachineManager
// facade v4 is not available. The MachineManager.DestroyMachinesWithParams method
// should be preferred.
//
// TODO(wallyworld) 2017-03-16 #1673323
// Drop this in Juju 3.0.
func (c *Client) DestroyMachinesWithParams(force, keep bool, machines ...string) error {
if keep {
return errors.NotSupportedf("destroy machine with keep-instance=true")
}
return c.DestroyMachines(machines...)
}

// GetModelConstraints returns the constraints for the model.
func (c *Client) GetModelConstraints() (constraints.Value, error) {
results := new(params.GetConstraintsResults)
Expand Down
2 changes: 1 addition & 1 deletion api/controller/legacy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (s *legacySuite) TestDestroyController(c *gc.C) {
sysManager := s.OpenAPI(c)
defer sysManager.Close()
err := sysManager.DestroyController(controller.DestroyControllerParams{})
c.Assert(err, gc.ErrorMatches, `failed to destroy model: hosting 1 other models \(controller has hosted models\)`)
c.Assert(err, gc.ErrorMatches, `failed to destroy model: hosting 1 other model \(controller has hosted models\)`)
}

func (s *legacySuite) TestListBlockedModels(c *gc.C) {
Expand Down
2 changes: 1 addition & 1 deletion api/facadeversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var facadeVersions = map[string]int{
"LogForwarding": 1,
"Logger": 1,
"MachineActions": 1,
"MachineManager": 3,
"MachineManager": 4,
"MachineUndertaker": 1,
"Machiner": 1,
"MeterStatus": 1,
Expand Down
36 changes: 36 additions & 0 deletions api/machinemanager/machinemanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,42 @@ func (client *Client) ForceDestroyMachines(machines ...string) ([]params.Destroy
return client.destroyMachines("ForceDestroyMachine", machines)
}

// DestroyMachinesWithParams removes the given set of machines, the semantics of which
// is determined by the force and keep parameters.
// TODO(wallyworld) - for Juju 3.0, this should be the preferred api to use.
func (client *Client) DestroyMachinesWithParams(force, keep bool, machines ...string) ([]params.DestroyMachineResult, error) {
args := params.DestroyMachinesParams{
Force: force,
Keep: keep,
MachineTags: make([]string, 0, len(machines)),
}
allResults := make([]params.DestroyMachineResult, len(machines))
index := make([]int, 0, len(machines))
for i, machineId := range machines {
if !names.IsValidMachine(machineId) {
allResults[i].Error = &params.Error{
Message: errors.NotValidf("machine ID %q", machineId).Error(),
}
continue
}
index = append(index, i)
args.MachineTags = append(args.MachineTags, names.NewMachineTag(machineId).String())
}
if len(args.MachineTags) > 0 {
var result params.DestroyMachineResults
if err := client.facade.FacadeCall("DestroyMachineWithParams", args, &result); err != nil {
return nil, errors.Trace(err)
}
if n := len(result.Results); n != len(args.MachineTags) {
return nil, errors.Errorf("expected %d result(s), got %d", len(args.MachineTags), n)
}
for i, result := range result.Results {
allResults[index[i]] = result
}
}
return allResults, nil
}

func (client *Client) destroyMachines(method string, machines []string) ([]params.DestroyMachineResult, error) {
args := params.Entities{
Entities: make([]params.Entity, 0, len(machines)),
Expand Down
30 changes: 30 additions & 0 deletions api/machinemanager/machinemanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,33 @@ func (s *MachinemanagerSuite) TestDestroyMachinesInvalidIds(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
c.Assert(results, jc.DeepEquals, expectedResults)
}

func (s *MachinemanagerSuite) TestDestroyMachinesWithParams(c *gc.C) {
expectedResults := []params.DestroyMachineResult{{
Error: &params.Error{Message: "boo"},
}, {
Info: &params.DestroyMachineInfo{
DestroyedUnits: []params.Entity{{Tag: "unit-foo-0"}},
DestroyedStorage: []params.Entity{{Tag: "storage-pgdata-0"}},
DetachedStorage: []params.Entity{{Tag: "storage-pgdata-1"}},
},
}}
client := newClient(func(objType string, version int, id, request string, a, response interface{}) error {
c.Assert(request, gc.Equals, "DestroyMachineWithParams")
c.Assert(a, jc.DeepEquals, params.DestroyMachinesParams{
Keep: true,
Force: true,
MachineTags: []string{
"machine-0",
"machine-0-lxd-1",
},
})
c.Assert(response, gc.FitsTypeOf, &params.DestroyMachineResults{})
out := response.(*params.DestroyMachineResults)
*out = params.DestroyMachineResults{expectedResults}
return nil
})
results, err := client.DestroyMachinesWithParams(true, true, "0", "0/lxd/1")
c.Assert(err, jc.ErrorIsNil)
c.Assert(results, jc.DeepEquals, expectedResults)
}
16 changes: 16 additions & 0 deletions api/migrationtarget/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,19 @@ func (c *Client) AdoptResources(modelUUID string) error {
func (c *Client) CACert() (string, error) {
return common.NewAPIAddresser(c.caller).CACert()
}

// CheckMachines compares the machines in state with the ones reported
// by the provider and reports any discrepancies.
func (c *Client) CheckMachines(modelUUID string) ([]error, error) {
var result params.ErrorResults
args := params.ModelArgs{names.NewModelTag(modelUUID).String()}
err := c.caller.FacadeCall("CheckMachines", args, &result)
if err != nil {
return nil, errors.Trace(err)
}
var results []error
for _, res := range result.Results {
results = append(results, errors.Errorf(res.Error.Message))
}
return results, nil
}
20 changes: 20 additions & 0 deletions api/migrationtarget/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,26 @@ func (s *ClientSuite) TestAdoptResources(c *gc.C) {
})
}

func (s *ClientSuite) TestCheckMachines(c *gc.C) {
var stub jujutesting.Stub
apiCaller := apitesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
target, ok := result.(*params.ErrorResults)
c.Assert(ok, jc.IsTrue)
*target = params.ErrorResults{Results: []params.ErrorResult{
{Error: &params.Error{Message: "oops"}},
{Error: &params.Error{Message: "oh no"}},
}}
stub.AddCall(objType+"."+request, id, arg)
return nil
})
client := migrationtarget.NewClient(apiCaller)
results, err := client.CheckMachines("django")
c.Assert(results, gc.HasLen, 2)
c.Assert(results[0], gc.ErrorMatches, "oops")
c.Assert(results[1], gc.ErrorMatches, "oh no")
s.AssertModelCall(c, &stub, names.NewModelTag("django"), "CheckMachines", err, false)
}

func (s *ClientSuite) TestUploadCharm(c *gc.C) {
const charmBody = "charming"
curl := charm.MustParseURL("cs:~user/foo-2")
Expand Down
41 changes: 41 additions & 0 deletions api/provisioner/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package provisioner
import (
"fmt"

"github.com/juju/errors"
"github.com/juju/version"
"gopkg.in/juju/names.v2"

apiwatcher "github.com/juju/juju/api/watcher"
Expand All @@ -27,6 +29,21 @@ func (m *Machine) Tag() names.Tag {
return m.tag
}

// ModelAgentVersion returns the agent version the machine's model is currently
// running or an error.
func (m *Machine) ModelAgentVersion() (*version.Number, error) {
mc, err := m.st.ModelConfig()
if err != nil {
return nil, errors.Trace(err)
}

if v, ok := mc.AgentVersion(); ok {
return &v, nil
}

return nil, errors.New("failed to get model's agent version.")
}

// MachineTag returns the identifier for the machine as the most specific type
func (m *Machine) MachineTag() names.MachineTag {
return m.tag
Expand Down Expand Up @@ -280,6 +297,30 @@ func (m *Machine) InstanceId() (instance.Id, error) {
return instance.Id(result.Result), nil
}

// KeepInstance returns the value of the keep-instance
// for the machine.
func (m *Machine) KeepInstance() (bool, error) {
var results params.BoolResults
args := params.Entities{
Entities: []params.Entity{{Tag: m.tag.String()}},
}
err := m.st.facade.FacadeCall("KeepInstance", args, &results)
if err != nil {
return false, err
}
if len(results.Results) != 1 {
return false, fmt.Errorf("expected 1 result, got %d", len(results.Results))
}
result := results.Results[0]
if result.Error != nil {
if params.IsCodeNotSupported(err) {
return false, errors.NewNotSupported(nil, "KeepInstance")
}
return false, result.Error
}
return result.Result, nil
}

// SetPassword sets the machine's password.
func (m *Machine) SetPassword(password string) error {
var result params.ErrorResults
Expand Down
10 changes: 10 additions & 0 deletions api/provisioner/provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,16 @@ func (s *provisionerSuite) TestSeries(c *gc.C) {
c.Assert(series, gc.Equals, "quantal")
}

func (s *provisionerSuite) TestKeepInstance(c *gc.C) {
err := s.machine.SetKeepInstance(true)
c.Assert(err, jc.ErrorIsNil)
apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
c.Assert(err, jc.ErrorIsNil)
keep, err := apiMachine.KeepInstance()
c.Assert(err, jc.ErrorIsNil)
c.Assert(keep, jc.IsTrue)
}

func (s *provisionerSuite) TestDistributionGroup(c *gc.C) {
apiMachine, err := s.provisioner.Machine(s.machine.Tag().(names.MachineTag))
c.Assert(err, jc.ErrorIsNil)
Expand Down
3 changes: 2 additions & 1 deletion apiserver/allfacades.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ func AllFacades() *facade.Registry {
reg("MachineActions", 1, machineactions.NewExternalFacade)

reg("MachineManager", 2, machinemanager.NewFacade)
reg("MachineManager", 3, machinemanager.NewFacade) // Version 3 adds DestroyMachine and ForceDestroyMachine.
reg("MachineManager", 3, machinemanager.NewFacade) // Version 3 adds DestroyMachine and ForceDestroyMachine.
reg("MachineManager", 4, machinemanager.NewFacadeV4) // Version 4 adds DestroyMachineWithParams.

reg("MachineUndertaker", 1, machineundertaker.NewFacade)
reg("Machiner", 1, machine.NewMachinerAPI)
Expand Down
4 changes: 4 additions & 0 deletions apiserver/common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ func ServerError(err error) *params.Error {
code = params.CodeHasHostedModels
case state.IsHasPersistentStorageError(err):
code = params.CodeHasPersistentStorage
case state.IsModelNotEmptyError(err):
code = params.CodeModelNotEmpty
case isNoAddressSetError(err):
code = params.CodeNoAddressSet
case errors.IsNotProvisioned(err):
Expand Down Expand Up @@ -316,6 +318,8 @@ func RestoreError(err error) error {
return err
case params.IsCodeHasPersistentStorage(err):
return err
case params.IsCodeModelNotEmpty(err):
return err
case params.IsCodeNoAddressSet(err):
// TODO(ericsnow) Handle isNoAddressSetError here.
// ...by parsing msg?
Expand Down
Loading

0 comments on commit 4dace8f

Please sign in to comment.