Rebase master #3788

Closed
wants to merge 511 commits into
from
Commits
The table of contents is too big for display.
+23,651 −6,755
Split
View
@@ -13,6 +13,7 @@ import (
"net/http"
"net/url"
"strings"
+ "sync/atomic"
"time"
"github.com/juju/errors"
@@ -80,11 +81,13 @@ type state struct {
// closed is a channel that gets closed when State.Close is called.
closed chan struct{}
- // loggedIn holds whether the client has successfully logged in.
- loggedIn bool
+ // loggedIn holds whether the client has successfully logged
+ // in. It's a int32 so that the atomic package can be used to
+ // access it safely.
+ loggedIn int32
// tag and password and nonce hold the cached login credentials.
- // These are only valid if loggedIn is true.
+ // These are only valid if loggedIn is 1.
tag string
password string
nonce string
@@ -282,7 +285,7 @@ func tlsConfigForCACert(caCert string) (*tls.Config, error) {
// ConnectStream implements Connection.ConnectStream.
func (st *state) ConnectStream(path string, attrs url.Values) (base.Stream, error) {
- if !st.loggedIn {
+ if !st.isLoggedIn() {
return nil, errors.New("cannot use ConnectStream without logging in")
}
// We use the standard "macaraq" macaroon authentication dance here.
@@ -598,3 +601,11 @@ func (s *state) BestFacadeVersion(facade string) int {
func (s *state) serverRoot() string {
return s.serverScheme + "://" + s.serverRootAddress
}
+
+func (s *state) isLoggedIn() bool {
+ return atomic.LoadInt32(&s.loggedIn) == 1
+}
+
+func (s *state) setLoggedIn() {
+ atomic.StoreInt32(&s.loggedIn, 1)
+}
View
@@ -692,8 +692,8 @@ func (c *Client) AddCharmWithAuthorization(curl *charm.URL, csMac *macaroon.Maca
// ResolveCharm resolves the best available charm URLs with series, for charm
// locations without a series specified.
-func (c *Client) ResolveCharm(ref *charm.Reference) (*charm.URL, error) {
- args := params.ResolveCharms{References: []charm.Reference{*ref}}
+func (c *Client) ResolveCharm(ref *charm.URL) (*charm.URL, error) {
+ args := params.ResolveCharms{References: []charm.URL{*ref}}
result := new(params.ResolveCharmResults)
if err := c.facade.FacadeCall("ResolveCharms", args, result); err != nil {
return nil, err
View
@@ -60,6 +60,7 @@ var facadeVersions = map[string]int{
"StringsWatcher": 0,
"SystemManager": 1,
"Upgrader": 0,
+ "UnitAssigner": 1,
"Uniter": 2,
"UserManager": 0,
"VolumeAttachmentsWatcher": 1,
@@ -6,6 +6,7 @@ package api_test
import (
"strings"
+ jc "github.com/juju/testing/checkers"
"github.com/juju/utils/set"
gc "gopkg.in/check.v1"
@@ -43,7 +44,7 @@ func (s *facadeVersionSuite) TestFacadeVersionsMatchServerVersions(c *gc.C) {
c.Check(serverFacadeNames.Difference(clientFacadeNames).SortedValues(), gc.HasLen, 0)
c.Check(clientFacadeNames.Difference(serverFacadeNames).SortedValues(), gc.HasLen, 0)
// Next check that the best versions match
- c.Check(*api.FacadeVersions, gc.DeepEquals, serverFacadeBestVersions)
+ c.Check(*api.FacadeVersions, jc.DeepEquals, serverFacadeBestVersions)
}
func checkBestVersion(c *gc.C, desiredVersion int, versions []int, expectedVersion int) {
View
@@ -18,7 +18,7 @@ import (
// HTTPClient implements Connection.APICaller.HTTPClient.
func (s *state) HTTPClient() (*httprequest.Client, error) {
- if !s.loggedIn {
+ if !s.isLoggedIn() {
return nil, errors.New("no HTTP client available without logging in")
}
baseURL, err := s.apiEndpoint("/", "")
View
@@ -29,6 +29,7 @@ import (
"github.com/juju/juju/api/resumer"
"github.com/juju/juju/api/rsyslog"
"github.com/juju/juju/api/storageprovisioner"
+ "github.com/juju/juju/api/unitassigner"
"github.com/juju/juju/api/uniter"
"github.com/juju/juju/api/upgrader"
"github.com/juju/juju/network"
@@ -182,4 +183,5 @@ type Connection interface {
Cleaner() *cleaner.API
Rsyslog() *rsyslog.State
MetadataUpdater() *imagemetadata.Client
+ UnitAssigner() unitassigner.API
}
@@ -90,15 +90,19 @@ func (s *provisionerSuite) SetUpTest(c *gc.C) {
func (s *provisionerSuite) TestPrepareContainerInterfaceInfoNoFeatureFlag(c *gc.C) {
s.SetFeatureFlags() // clear the flag
ifaceInfo, err := s.provisioner.PrepareContainerInterfaceInfo(names.NewMachineTag("42"))
- c.Assert(err, gc.ErrorMatches, "address allocation not supported")
+ // We'll still attempt to reserve an address, in case we're running on MAAS
+ // 1.8+ and have registered the container as a device.
+ c.Assert(err, gc.ErrorMatches, "machine 42 not found")
c.Assert(ifaceInfo, gc.HasLen, 0)
}
func (s *provisionerSuite) TestReleaseContainerAddressNoFeatureFlag(c *gc.C) {
s.SetFeatureFlags() // clear the flag
err := s.provisioner.ReleaseContainerAddresses(names.NewMachineTag("42"))
+ // We'll still attempt to release all addresses, in case we're running on
+ // MAAS 1.8+ and have registered the container as a device.
c.Assert(err, gc.ErrorMatches,
- `cannot release static addresses for "42": address allocation not supported`,
+ `cannot release static addresses for "42": machine 42 not found`,
)
}
@@ -875,12 +879,13 @@ func (s *provisionerSuite) TestPrepareContainerInterfaceInfo(c *gc.C) {
Disabled: false,
NoAutoStart: false,
ConfigType: network.ConfigStatic,
- // Overwrite the Address field below with the actual one, as
- // it's chosen randomly.
- Address: network.Address{},
- DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"),
- GatewayAddress: network.NewAddress("0.10.0.2"),
- ExtraConfig: nil,
+ DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"),
+ GatewayAddress: network.NewAddress("0.10.0.2"),
+ ExtraConfig: nil,
+ // Overwrite Address and MACAddress fields below with the actual ones,
+ // as they are chosen randomly.
+ Address: network.Address{},
+ MACAddress: "",
}}
c.Assert(ifaceInfo[0].Address, gc.Not(gc.DeepEquals), network.Address{})
c.Assert(ifaceInfo[0].MACAddress, gc.Not(gc.DeepEquals), "")
@@ -912,7 +917,7 @@ func (s *provisionerSuite) TestReleaseContainerAddresses(c *gc.C) {
addr := network.NewAddress(fmt.Sprintf("0.10.0.%d", i))
ipaddr, err := s.State.AddIPAddress(addr, sub.ID())
c.Check(err, jc.ErrorIsNil)
- err = ipaddr.AllocateTo(container.Id(), "", "")
+ err = ipaddr.AllocateTo(container.Id(), "nic42", "aa:bb:cc:dd:ee:f0")
c.Check(err, jc.ErrorIsNil)
}
c.Assert(err, jc.ErrorIsNil)
View
@@ -31,6 +31,7 @@ import (
"github.com/juju/juju/api/resumer"
"github.com/juju/juju/api/rsyslog"
"github.com/juju/juju/api/storageprovisioner"
+ "github.com/juju/juju/api/unitassigner"
"github.com/juju/juju/api/uniter"
"github.com/juju/juju/api/upgrader"
"github.com/juju/juju/apiserver/params"
@@ -197,7 +198,8 @@ func (st *state) setLoginResult(tag names.Tag, environTag, controllerTag string,
for _, facade := range facades {
st.facadeVersions[facade.Name] = facade.Versions
}
- st.loggedIn = true
+
+ st.setLoggedIn()
return nil
}
@@ -274,6 +276,12 @@ func (st *state) Machiner() *machiner.State {
return machiner.NewState(st)
}
+// UnitAssigner returns a version of the state that provides functionality
+// required by the unitassigner worker.
+func (st *state) UnitAssigner() unitassigner.API {
+ return unitassigner.New(st)
+}
+
// Resumer returns a version of the state that provides functionality
// required by the resumer worker.
func (st *state) Resumer() *resumer.API {
@@ -0,0 +1,14 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package unitassigner
+
+import (
+ "testing"
+
+ gc "gopkg.in/check.v1"
+)
+
+func TestPackage(t *testing.T) {
+ gc.TestingT(t)
+}
@@ -0,0 +1,82 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package unitassigner
+
+import (
+ "github.com/juju/errors"
+ "github.com/juju/juju/api/base"
+ "github.com/juju/juju/api/watcher"
+ "github.com/juju/juju/apiserver/params"
+
+ "github.com/juju/names"
+)
+
+const uaFacade = "UnitAssigner"
+
+// API provides access to the UnitAssigner API facade.
+type API struct {
+ facade base.FacadeCaller
+}
+
+// New creates a new client-side UnitAssigner facade.
+func New(caller base.APICaller) API {
+ fc := base.NewFacadeCaller(caller, uaFacade)
+ return API{facade: fc}
+}
+
+// AssignUnits tells the state server to run whatever unit assignments it has.
+// Unit assignments for units that no longer exist will return an error that
+// satisfies errors.IsNotFound.
+func (a API) AssignUnits(tags []names.UnitTag) ([]error, error) {
+ entities := make([]params.Entity, len(tags))
+ for i, tag := range tags {
+ entities[i] = params.Entity{Tag: tag.String()}
+ }
+ args := params.Entities{Entities: entities}
+ var result params.ErrorResults
+ if err := a.facade.FacadeCall("AssignUnits", args, &result); err != nil {
+ return nil, err
+ }
+
+ errs := make([]error, len(result.Results))
+ for i, e := range result.Results {
+ if e.Error != nil {
+ errs[i] = convertNotFound(e.Error)
+ }
+ }
+ return errs, nil
+}
+
+// convertNotFound converts param notfound errors into errors.notfound values.
+func convertNotFound(err error) error {
+ if params.IsCodeNotFound(err) {
+ return errors.NewNotFound(err, "")
+ }
+ return err
+}
+
+// WatchUnitAssignments watches the server for new unit assignments to be
+// created.
+func (a API) WatchUnitAssignments() (watcher.StringsWatcher, error) {
+ var result params.StringsWatchResult
+ err := a.facade.FacadeCall("WatchUnitAssignments", nil, &result)
+ if err != nil {
+ return nil, err
+ }
+ if result.Error != nil {
+ return nil, result.Error
+ }
+ w := watcher.NewStringsWatcher(a.facade.RawAPICaller(), result)
+ return w, nil
+}
+
+// SetAgentStatus sets the status of the unit agents.
+func (a API) SetAgentStatus(args params.SetStatus) error {
+ var result params.ErrorResults
+ err := a.facade.FacadeCall("SetAgentStatus", args, &result)
+ if err != nil {
+ return err
+ }
+ return result.Combine()
+}
Oops, something went wrong.