github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/dummy/environs.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The dummy provider implements an environment provider for testing
     5  // purposes, registered with environs under the name "dummy".
     6  //
     7  // The configuration YAML for the testing environment
     8  // must specify a "controller" property with a boolean
     9  // value. If this is true, a controller will be started
    10  // when the environment is bootstrapped.
    11  //
    12  // The configuration data also accepts a "broken" property
    13  // of type boolean. If this is non-empty, any operation
    14  // after the environment has been opened will return
    15  // the error "broken environment", and will also log that.
    16  //
    17  // The DNS name of instances is the same as the Id,
    18  // with ".dns" appended.
    19  package dummy
    20  
    21  import (
    22  	"crypto/tls"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net"
    26  	"net/http/httptest"
    27  	"os"
    28  	"runtime"
    29  	"strconv"
    30  	"strings"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/juju/clock"
    35  	"github.com/juju/errors"
    36  	"github.com/juju/jsonschema"
    37  	"github.com/juju/loggo"
    38  	"github.com/juju/pubsub"
    39  	"github.com/juju/retry"
    40  	"github.com/juju/schema"
    41  	gitjujutesting "github.com/juju/testing"
    42  	jc "github.com/juju/testing/checkers"
    43  	"github.com/juju/utils/arch"
    44  	"github.com/juju/version"
    45  	"github.com/prometheus/client_golang/prometheus"
    46  	gc "gopkg.in/check.v1"
    47  	"gopkg.in/juju/charm.v6"
    48  	"gopkg.in/juju/environschema.v1"
    49  	"gopkg.in/juju/names.v2"
    50  	"gopkg.in/juju/worker.v1"
    51  
    52  	"github.com/juju/juju/agent"
    53  	"github.com/juju/juju/api"
    54  	"github.com/juju/juju/apiserver"
    55  	"github.com/juju/juju/apiserver/apiserverhttp"
    56  	"github.com/juju/juju/apiserver/observer"
    57  	"github.com/juju/juju/apiserver/stateauthenticator"
    58  	"github.com/juju/juju/cloud"
    59  	"github.com/juju/juju/cloudconfig/instancecfg"
    60  	"github.com/juju/juju/core/auditlog"
    61  	"github.com/juju/juju/core/cache"
    62  	"github.com/juju/juju/core/constraints"
    63  	"github.com/juju/juju/core/instance"
    64  	corelease "github.com/juju/juju/core/lease"
    65  	"github.com/juju/juju/core/presence"
    66  	"github.com/juju/juju/core/status"
    67  	"github.com/juju/juju/environs"
    68  	"github.com/juju/juju/environs/config"
    69  	"github.com/juju/juju/environs/context"
    70  	"github.com/juju/juju/environs/instances"
    71  	jujuversion "github.com/juju/juju/juju/version"
    72  	"github.com/juju/juju/mongo"
    73  	"github.com/juju/juju/mongo/mongotest"
    74  	"github.com/juju/juju/network"
    75  	"github.com/juju/juju/provider/common"
    76  	"github.com/juju/juju/pubsub/centralhub"
    77  	"github.com/juju/juju/state"
    78  	"github.com/juju/juju/state/multiwatcher"
    79  	"github.com/juju/juju/state/stateenvirons"
    80  	"github.com/juju/juju/storage"
    81  	"github.com/juju/juju/testing"
    82  	coretools "github.com/juju/juju/tools"
    83  	"github.com/juju/juju/worker/lease"
    84  	"github.com/juju/juju/worker/modelcache"
    85  )
    86  
    87  var logger = loggo.GetLogger("juju.provider.dummy")
    88  
    89  var transientErrorInjection chan error
    90  
    91  const BootstrapInstanceId = "localhost"
    92  
    93  var errNotPrepared = errors.New("model is not prepared")
    94  
    95  // SampleCloudSpec returns an environs.CloudSpec that can be used to
    96  // open a dummy Environ.
    97  func SampleCloudSpec() environs.CloudSpec {
    98  	cred := cloud.NewCredential(cloud.UserPassAuthType, map[string]string{"username": "dummy", "password": "secret"})
    99  	return environs.CloudSpec{
   100  		Type:             "dummy",
   101  		Name:             "dummy",
   102  		Endpoint:         "dummy-endpoint",
   103  		IdentityEndpoint: "dummy-identity-endpoint",
   104  		Region:           "dummy-region",
   105  		StorageEndpoint:  "dummy-storage-endpoint",
   106  		Credential:       &cred,
   107  	}
   108  }
   109  
   110  // SampleConfig() returns an environment configuration with all required
   111  // attributes set.
   112  func SampleConfig() testing.Attrs {
   113  	return testing.Attrs{
   114  		"type":                      "dummy",
   115  		"name":                      "only",
   116  		"uuid":                      testing.ModelTag.Id(),
   117  		"authorized-keys":           testing.FakeAuthKeys,
   118  		"firewall-mode":             config.FwInstance,
   119  		"ssl-hostname-verification": true,
   120  		"development":               false,
   121  		"default-series":            jujuversion.SupportedLTS(),
   122  
   123  		"secret":     "pork",
   124  		"controller": true,
   125  	}
   126  }
   127  
   128  // PatchTransientErrorInjectionChannel sets the transientInjectionError
   129  // channel which can be used to inject errors into StartInstance for
   130  // testing purposes
   131  // The injected errors will use the string received on the channel
   132  // and the instance's state will eventually go to error, while the
   133  // received string will appear in the info field of the machine's status
   134  func PatchTransientErrorInjectionChannel(c chan error) func() {
   135  	return gitjujutesting.PatchValue(&transientErrorInjection, c)
   136  }
   137  
   138  // mongoInfo returns a mongo.MongoInfo which allows clients to connect to the
   139  // shared dummy state, if it exists.
   140  func mongoInfo() mongo.MongoInfo {
   141  	if gitjujutesting.MgoServer.Addr() == "" {
   142  		panic("dummy environ state tests must be run with MgoTestPackage")
   143  	}
   144  	mongoPort := strconv.Itoa(gitjujutesting.MgoServer.Port())
   145  	addrs := []string{net.JoinHostPort("localhost", mongoPort)}
   146  	return mongo.MongoInfo{
   147  		Info: mongo.Info{
   148  			Addrs:      addrs,
   149  			CACert:     testing.CACert,
   150  			DisableTLS: !gitjujutesting.MgoServer.SSLEnabled(),
   151  		},
   152  	}
   153  }
   154  
   155  // Operation represents an action on the dummy provider.
   156  type Operation interface{}
   157  
   158  type OpBootstrap struct {
   159  	Context environs.BootstrapContext
   160  	Env     string
   161  	Args    environs.BootstrapParams
   162  }
   163  
   164  type OpFinalizeBootstrap struct {
   165  	Context        environs.BootstrapContext
   166  	Env            string
   167  	InstanceConfig *instancecfg.InstanceConfig
   168  }
   169  
   170  type OpDestroy struct {
   171  	Env         string
   172  	Cloud       string
   173  	CloudRegion string
   174  	Error       error
   175  }
   176  
   177  type OpNetworkInterfaces struct {
   178  	Env        string
   179  	InstanceId instance.Id
   180  	Info       []network.InterfaceInfo
   181  }
   182  
   183  type OpSubnets struct {
   184  	Env        string
   185  	InstanceId instance.Id
   186  	SubnetIds  []network.Id
   187  	Info       []network.SubnetInfo
   188  }
   189  
   190  type OpStartInstance struct {
   191  	Env               string
   192  	MachineId         string
   193  	MachineNonce      string
   194  	PossibleTools     coretools.List
   195  	Instance          instances.Instance
   196  	Constraints       constraints.Value
   197  	SubnetsToZones    map[network.Id][]string
   198  	NetworkInfo       []network.InterfaceInfo
   199  	Volumes           []storage.Volume
   200  	VolumeAttachments []storage.VolumeAttachment
   201  	Info              *mongo.MongoInfo
   202  	Jobs              []multiwatcher.MachineJob
   203  	APIInfo           *api.Info
   204  	Secret            string
   205  	AgentEnvironment  map[string]string
   206  }
   207  
   208  type OpStopInstances struct {
   209  	Env string
   210  	Ids []instance.Id
   211  }
   212  
   213  type OpOpenPorts struct {
   214  	Env        string
   215  	MachineId  string
   216  	InstanceId instance.Id
   217  	Rules      []network.IngressRule
   218  }
   219  
   220  type OpClosePorts struct {
   221  	Env        string
   222  	MachineId  string
   223  	InstanceId instance.Id
   224  	Rules      []network.IngressRule
   225  }
   226  
   227  type OpPutFile struct {
   228  	Env      string
   229  	FileName string
   230  }
   231  
   232  // environProvider represents the dummy provider.  There is only ever one
   233  // instance of this type (dummy)
   234  type environProvider struct {
   235  	mu                     sync.Mutex
   236  	ops                    chan<- Operation
   237  	newStatePolicy         state.NewPolicyFunc
   238  	supportsSpaces         bool
   239  	supportsSpaceDiscovery bool
   240  	apiPort                int
   241  	controllerState        *environState
   242  	state                  map[string]*environState
   243  }
   244  
   245  // APIPort returns the randon api port used by the given provider instance.
   246  func APIPort(p environs.EnvironProvider) int {
   247  	return p.(*environProvider).apiPort
   248  }
   249  
   250  // environState represents the state of an environment.
   251  // It can be shared between several environ values,
   252  // so that a given environment can be opened several times.
   253  type environState struct {
   254  	name           string
   255  	ops            chan<- Operation
   256  	newStatePolicy state.NewPolicyFunc
   257  	mu             sync.Mutex
   258  	maxId          int // maximum instance id allocated so far.
   259  	maxAddr        int // maximum allocated address last byte
   260  	insts          map[instance.Id]*dummyInstance
   261  	globalRules    network.IngressRuleSlice
   262  	bootstrapped   bool
   263  	mux            *apiserverhttp.Mux
   264  	httpServer     *httptest.Server
   265  	apiServer      *apiserver.Server
   266  	apiState       *state.State
   267  	apiStatePool   *state.StatePool
   268  	hub            *pubsub.StructuredHub
   269  	presence       *fakePresence
   270  	leaseManager   *lease.Manager
   271  	creator        string
   272  
   273  	modelCacheWorker worker.Worker
   274  	controller       *cache.Controller
   275  }
   276  
   277  // environ represents a client's connection to a given environment's
   278  // state.
   279  type environ struct {
   280  	storage.ProviderRegistry
   281  	name         string
   282  	modelUUID    string
   283  	cloud        environs.CloudSpec
   284  	ecfgMutex    sync.Mutex
   285  	ecfgUnlocked *environConfig
   286  	spacesMutex  sync.RWMutex
   287  }
   288  
   289  var _ environs.Environ = (*environ)(nil)
   290  var _ environs.Networking = (*environ)(nil)
   291  
   292  // discardOperations discards all Operations written to it.
   293  var discardOperations = make(chan Operation)
   294  
   295  func init() {
   296  	environs.RegisterProvider("dummy", &dummy)
   297  
   298  	// Prime the first ops channel, so that naive clients can use
   299  	// the testing environment by simply importing it.
   300  	go func() {
   301  		for range discardOperations {
   302  		}
   303  	}()
   304  }
   305  
   306  // dummy is the dummy environmentProvider singleton.
   307  var dummy = environProvider{
   308  	ops:                    discardOperations,
   309  	state:                  make(map[string]*environState),
   310  	newStatePolicy:         stateenvirons.GetNewPolicyFunc(),
   311  	supportsSpaces:         true,
   312  	supportsSpaceDiscovery: false,
   313  }
   314  
   315  // Reset resets the entire dummy environment and forgets any registered
   316  // operation listener. All opened environments after Reset will share
   317  // the same underlying state.
   318  func Reset(c *gc.C) {
   319  	logger.Infof("reset model")
   320  	dummy.mu.Lock()
   321  	dummy.ops = discardOperations
   322  	oldState := dummy.state
   323  	dummy.controllerState = nil
   324  	dummy.state = make(map[string]*environState)
   325  	dummy.newStatePolicy = stateenvirons.GetNewPolicyFunc()
   326  	dummy.supportsSpaces = true
   327  	dummy.supportsSpaceDiscovery = false
   328  	dummy.mu.Unlock()
   329  
   330  	// NOTE(axw) we must destroy the old states without holding
   331  	// the provider lock, or we risk deadlocking. Destroying
   332  	// state involves closing the embedded API server, which
   333  	// may require waiting on RPC calls that interact with the
   334  	// EnvironProvider (e.g. EnvironProvider.Open).
   335  	for _, s := range oldState {
   336  		if s.httpServer != nil {
   337  			logger.Debugf("closing httpServer")
   338  			s.httpServer.Close()
   339  		}
   340  		s.destroy()
   341  	}
   342  	if mongoAlive() {
   343  		err := retry.Call(retry.CallArgs{
   344  			Func: gitjujutesting.MgoServer.Reset,
   345  			// Only interested in retrying the intermittent
   346  			// 'unexpected message'.
   347  			IsFatalError: func(err error) bool {
   348  				return !strings.HasSuffix(err.Error(), "unexpected message")
   349  			},
   350  			Delay:    time.Millisecond,
   351  			Clock:    clock.WallClock,
   352  			Attempts: 5,
   353  		})
   354  		c.Assert(err, jc.ErrorIsNil)
   355  	}
   356  }
   357  
   358  func (state *environState) destroy() {
   359  	state.mu.Lock()
   360  	defer state.mu.Unlock()
   361  	state.destroyLocked()
   362  }
   363  
   364  func (state *environState) destroyLocked() {
   365  	if !state.bootstrapped {
   366  		return
   367  	}
   368  	apiServer := state.apiServer
   369  	apiStatePool := state.apiStatePool
   370  	leaseManager := state.leaseManager
   371  	modelCacheWorker := state.modelCacheWorker
   372  	state.apiServer = nil
   373  	state.apiStatePool = nil
   374  	state.apiState = nil
   375  	state.controller = nil
   376  	state.leaseManager = nil
   377  	state.bootstrapped = false
   378  	state.hub = nil
   379  	state.modelCacheWorker = nil
   380  
   381  	// Release the lock while we close resources. In particular,
   382  	// we must not hold the lock while the API server is being
   383  	// closed, as it may need to interact with the Environ while
   384  	// shutting down.
   385  	state.mu.Unlock()
   386  	defer state.mu.Lock()
   387  
   388  	// The apiServer depends on the modelCache, so stop the apiserver first.
   389  	if apiServer != nil {
   390  		logger.Debugf("stopping apiServer")
   391  		if err := apiServer.Stop(); err != nil && mongoAlive() {
   392  			panic(err)
   393  		}
   394  	}
   395  
   396  	if modelCacheWorker != nil {
   397  		logger.Debugf("stopping modelCache worker")
   398  		if err := worker.Stop(modelCacheWorker); err != nil {
   399  			panic(err)
   400  		}
   401  	}
   402  
   403  	if leaseManager != nil {
   404  		if err := worker.Stop(leaseManager); err != nil && mongoAlive() {
   405  			panic(err)
   406  		}
   407  	}
   408  
   409  	if apiStatePool != nil {
   410  		logger.Debugf("closing apiStatePool")
   411  		if err := apiStatePool.Close(); err != nil && mongoAlive() {
   412  			panic(err)
   413  		}
   414  	}
   415  
   416  	if mongoAlive() {
   417  		logger.Debugf("resetting MgoServer")
   418  		gitjujutesting.MgoServer.Reset()
   419  	}
   420  }
   421  
   422  // mongoAlive reports whether the mongo server is
   423  // still alive (i.e. has not been deliberately destroyed).
   424  // If it has been deliberately destroyed, we will
   425  // expect some errors when closing things down.
   426  func mongoAlive() bool {
   427  	return gitjujutesting.MgoServer.Addr() != ""
   428  }
   429  
   430  // GetStateInAPIServer returns the state connection used by the API server
   431  // This is so code in the test suite can trigger Syncs, etc that the API server
   432  // will see, which will then trigger API watchers, etc.
   433  func (e *environ) GetStateInAPIServer() *state.State {
   434  	st, err := e.state()
   435  	if err != nil {
   436  		panic(err)
   437  	}
   438  	return st.apiState
   439  }
   440  
   441  // GetStatePoolInAPIServer returns the StatePool used by the API
   442  // server.  As for GetStatePoolInAPIServer, this is so code in the
   443  // test suite can trigger Syncs etc.
   444  func (e *environ) GetStatePoolInAPIServer() *state.StatePool {
   445  	st, err := e.state()
   446  	if err != nil {
   447  		panic(err)
   448  	}
   449  	return st.apiStatePool
   450  }
   451  
   452  // GetHubInAPIServer returns the central hub used by the API server.
   453  func (e *environ) GetHubInAPIServer() *pubsub.StructuredHub {
   454  	st, err := e.state()
   455  	if err != nil {
   456  		panic(err)
   457  	}
   458  	return st.hub
   459  }
   460  
   461  // GetLeaseManagerInAPIServer returns the channel used to update the
   462  // cache.Controller used by the API server
   463  func (e *environ) GetLeaseManagerInAPIServer() corelease.Manager {
   464  	st, err := e.state()
   465  	if err != nil {
   466  		panic(err)
   467  	}
   468  	return st.leaseManager
   469  }
   470  
   471  // GetController returns the cache.Controller used by the API server.
   472  func (e *environ) GetController() *cache.Controller {
   473  	st, err := e.state()
   474  	if err != nil {
   475  		panic(err)
   476  	}
   477  	return st.controller
   478  }
   479  
   480  // newState creates the state for a new environment with the given name.
   481  func newState(name string, ops chan<- Operation, newStatePolicy state.NewPolicyFunc) *environState {
   482  	buf := make([]byte, 8192)
   483  	buf = buf[:runtime.Stack(buf, false)]
   484  	s := &environState{
   485  		name:           name,
   486  		ops:            ops,
   487  		newStatePolicy: newStatePolicy,
   488  		insts:          make(map[instance.Id]*dummyInstance),
   489  		creator:        string(buf),
   490  	}
   491  	return s
   492  }
   493  
   494  // listenAPI starts an HTTP server listening for API connections.
   495  func (s *environState) listenAPI() int {
   496  	certPool, err := api.CreateCertPool(testing.CACert)
   497  	if err != nil {
   498  		panic(err)
   499  	}
   500  	tlsConfig := api.NewTLSConfig(certPool)
   501  	tlsConfig.ServerName = "juju-apiserver"
   502  	tlsConfig.Certificates = []tls.Certificate{*testing.ServerTLSCert}
   503  	s.mux = apiserverhttp.NewMux()
   504  	s.httpServer = httptest.NewUnstartedServer(s.mux)
   505  	s.httpServer.TLS = tlsConfig
   506  	return s.httpServer.Listener.Addr().(*net.TCPAddr).Port
   507  }
   508  
   509  // SetSupportsSpaces allows to enable and disable SupportsSpaces for tests.
   510  func SetSupportsSpaces(supports bool) bool {
   511  	dummy.mu.Lock()
   512  	defer dummy.mu.Unlock()
   513  	current := dummy.supportsSpaces
   514  	dummy.supportsSpaces = supports
   515  	return current
   516  }
   517  
   518  // SetSupportsSpaceDiscovery allows to enable and disable
   519  // SupportsSpaceDiscovery for tests.
   520  func SetSupportsSpaceDiscovery(supports bool) bool {
   521  	dummy.mu.Lock()
   522  	defer dummy.mu.Unlock()
   523  	current := dummy.supportsSpaceDiscovery
   524  	dummy.supportsSpaceDiscovery = supports
   525  	return current
   526  }
   527  
   528  // Listen directs subsequent operations on any dummy environment
   529  // to channel c (if not nil).
   530  func Listen(c chan<- Operation) {
   531  	dummy.mu.Lock()
   532  	defer dummy.mu.Unlock()
   533  	if c == nil {
   534  		c = discardOperations
   535  	}
   536  	dummy.ops = c
   537  	for _, st := range dummy.state {
   538  		st.mu.Lock()
   539  		st.ops = c
   540  		st.mu.Unlock()
   541  	}
   542  }
   543  
   544  var configSchema = environschema.Fields{
   545  	"controller": {
   546  		Description: "Whether the model should start a controller",
   547  		Type:        environschema.Tbool,
   548  	},
   549  	"broken": {
   550  		Description: "Whitespace-separated Environ methods that should return an error when called",
   551  		Type:        environschema.Tstring,
   552  	},
   553  	"secret": {
   554  		Description: "A secret",
   555  		Type:        environschema.Tstring,
   556  	},
   557  }
   558  
   559  var configFields = func() schema.Fields {
   560  	fs, _, err := configSchema.ValidationSchema()
   561  	if err != nil {
   562  		panic(err)
   563  	}
   564  	return fs
   565  }()
   566  
   567  var configDefaults = schema.Defaults{
   568  	"broken":     "",
   569  	"secret":     "pork",
   570  	"controller": false,
   571  }
   572  
   573  type environConfig struct {
   574  	*config.Config
   575  	attrs map[string]interface{}
   576  }
   577  
   578  func (c *environConfig) controller() bool {
   579  	return c.attrs["controller"].(bool)
   580  }
   581  
   582  func (c *environConfig) broken() string {
   583  	return c.attrs["broken"].(string)
   584  }
   585  
   586  func (c *environConfig) secret() string {
   587  	return c.attrs["secret"].(string)
   588  }
   589  
   590  func (p *environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
   591  	valid, err := p.Validate(cfg, nil)
   592  	if err != nil {
   593  		return nil, err
   594  	}
   595  	return &environConfig{valid, valid.UnknownAttrs()}, nil
   596  }
   597  
   598  func (p *environProvider) Schema() environschema.Fields {
   599  	fields, err := config.Schema(configSchema)
   600  	if err != nil {
   601  		panic(err)
   602  	}
   603  	return fields
   604  }
   605  
   606  var _ config.ConfigSchemaSource = (*environProvider)(nil)
   607  
   608  // ConfigSchema returns extra config attributes specific
   609  // to this provider only.
   610  func (p *environProvider) ConfigSchema() schema.Fields {
   611  	return configFields
   612  }
   613  
   614  // ConfigDefaults returns the default values for the
   615  // provider specific config attributes.
   616  func (p *environProvider) ConfigDefaults() schema.Defaults {
   617  	return configDefaults
   618  }
   619  
   620  func (*environProvider) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema {
   621  	return map[cloud.AuthType]cloud.CredentialSchema{
   622  		cloud.EmptyAuthType: {},
   623  		cloud.UserPassAuthType: {
   624  			{
   625  				"username", cloud.CredentialAttr{Description: "The username to authenticate with."},
   626  			}, {
   627  				"password", cloud.CredentialAttr{
   628  					Description: "The password for the specified username.",
   629  					Hidden:      true,
   630  				},
   631  			},
   632  		},
   633  	}
   634  }
   635  
   636  func (*environProvider) DetectCredentials() (*cloud.CloudCredential, error) {
   637  	return cloud.NewEmptyCloudCredential(), nil
   638  }
   639  
   640  func (*environProvider) FinalizeCredential(ctx environs.FinalizeCredentialContext, args environs.FinalizeCredentialParams) (*cloud.Credential, error) {
   641  	return &args.Credential, nil
   642  }
   643  
   644  func (*environProvider) DetectRegions() ([]cloud.Region, error) {
   645  	return []cloud.Region{{Name: "dummy"}}, nil
   646  }
   647  
   648  func (p *environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
   649  	// Check for valid changes for the base config values.
   650  	if err := config.Validate(cfg, old); err != nil {
   651  		return nil, err
   652  	}
   653  	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
   654  	if err != nil {
   655  		return nil, err
   656  	}
   657  	// Apply the coerced unknown values back into the config.
   658  	return cfg.Apply(validated)
   659  }
   660  
   661  func (e *environ) state() (*environState, error) {
   662  	dummy.mu.Lock()
   663  	defer dummy.mu.Unlock()
   664  	state, ok := dummy.state[e.modelUUID]
   665  	if !ok {
   666  		return nil, errNotPrepared
   667  	}
   668  	return state, nil
   669  }
   670  
   671  // Version is part of the EnvironProvider interface.
   672  func (*environProvider) Version() int {
   673  	return 0
   674  }
   675  
   676  func (p *environProvider) Open(args environs.OpenParams) (environs.Environ, error) {
   677  	p.mu.Lock()
   678  	defer p.mu.Unlock()
   679  	ecfg, err := p.newConfig(args.Config)
   680  	if err != nil {
   681  		return nil, err
   682  	}
   683  	env := &environ{
   684  		ProviderRegistry: StorageProviders(),
   685  		name:             ecfg.Name(),
   686  		modelUUID:        args.Config.UUID(),
   687  		cloud:            args.Cloud,
   688  		ecfgUnlocked:     ecfg,
   689  	}
   690  	if err := env.checkBroken("Open"); err != nil {
   691  		return nil, err
   692  	}
   693  	return env, nil
   694  }
   695  
   696  // CloudSchema returns the schema used to validate input for add-cloud.  Since
   697  // this provider does not support custom clouds, this always returns nil.
   698  func (p *environProvider) CloudSchema() *jsonschema.Schema {
   699  	return nil
   700  }
   701  
   702  // Ping tests the connection to the cloud, to verify the endpoint is valid.
   703  func (p *environProvider) Ping(ctx context.ProviderCallContext, endpoint string) error {
   704  	return errors.NotImplementedf("Ping")
   705  }
   706  
   707  // PrepareConfig is specified in the EnvironProvider interface.
   708  func (p *environProvider) PrepareConfig(args environs.PrepareConfigParams) (*config.Config, error) {
   709  	if _, err := dummy.newConfig(args.Config); err != nil {
   710  		return nil, err
   711  	}
   712  	return args.Config, nil
   713  }
   714  
   715  // Override for testing - the data directory with which the state api server is initialised.
   716  var DataDir = ""
   717  var LogDir = ""
   718  
   719  func (e *environ) ecfg() *environConfig {
   720  	e.ecfgMutex.Lock()
   721  	ecfg := e.ecfgUnlocked
   722  	e.ecfgMutex.Unlock()
   723  	return ecfg
   724  }
   725  
   726  func (e *environ) checkBroken(method string) error {
   727  	for _, m := range strings.Fields(e.ecfg().broken()) {
   728  		if m == method {
   729  			return fmt.Errorf("dummy.%s is broken", method)
   730  		}
   731  	}
   732  	return nil
   733  }
   734  
   735  // PrecheckInstance is specified in the environs.InstancePrechecker interface.
   736  func (*environ) PrecheckInstance(ctx context.ProviderCallContext, args environs.PrecheckInstanceParams) error {
   737  	if args.Placement != "" && args.Placement != "valid" {
   738  		return fmt.Errorf("%s placement is invalid", args.Placement)
   739  	}
   740  	return nil
   741  }
   742  
   743  // Create is part of the Environ interface.
   744  func (e *environ) Create(ctx context.ProviderCallContext, args environs.CreateParams) error {
   745  	dummy.mu.Lock()
   746  	defer dummy.mu.Unlock()
   747  	dummy.state[e.modelUUID] = newState(e.name, dummy.ops, dummy.newStatePolicy)
   748  	return nil
   749  }
   750  
   751  // PrepareForBootstrap is part of the Environ interface.
   752  func (e *environ) PrepareForBootstrap(ctx environs.BootstrapContext) error {
   753  	dummy.mu.Lock()
   754  	defer dummy.mu.Unlock()
   755  	ecfg := e.ecfgUnlocked
   756  
   757  	if ecfg.controller() && dummy.controllerState != nil {
   758  		// Because of global variables, we can only have one dummy
   759  		// controller per process. Panic if there is an attempt to
   760  		// bootstrap while there is another active controller.
   761  		old := dummy.controllerState
   762  		panic(fmt.Errorf("cannot share a state between two dummy environs; old %q; new %q: %s", old.name, e.name, old.creator))
   763  	}
   764  
   765  	// The environment has not been prepared, so create it and record it.
   766  	// We don't start listening for State or API connections until
   767  	// Bootstrap has been called.
   768  	envState := newState(e.name, dummy.ops, dummy.newStatePolicy)
   769  	if ecfg.controller() {
   770  		dummy.apiPort = envState.listenAPI()
   771  		dummy.controllerState = envState
   772  	}
   773  	dummy.state[e.modelUUID] = envState
   774  	return nil
   775  }
   776  
   777  func (e *environ) Bootstrap(ctx environs.BootstrapContext, callCtx context.ProviderCallContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) {
   778  	series := config.PreferredSeries(e.Config())
   779  	availableTools, err := args.AvailableTools.Match(coretools.Filter{Series: series})
   780  	if err != nil {
   781  		return nil, err
   782  	}
   783  	arch := availableTools.Arches()[0]
   784  
   785  	defer delay()
   786  	if err := e.checkBroken("Bootstrap"); err != nil {
   787  		return nil, err
   788  	}
   789  	if _, ok := args.ControllerConfig.CACert(); !ok {
   790  		return nil, errors.New("no CA certificate in controller configuration")
   791  	}
   792  
   793  	logger.Infof("would pick agent binaries from %s", availableTools)
   794  
   795  	estate, err := e.state()
   796  	if err != nil {
   797  		return nil, err
   798  	}
   799  	estate.mu.Lock()
   800  	defer estate.mu.Unlock()
   801  	if estate.bootstrapped {
   802  		return nil, errors.New("model is already bootstrapped")
   803  	}
   804  
   805  	// Create an instance for the bootstrap node.
   806  	logger.Infof("creating bootstrap instance")
   807  	i := &dummyInstance{
   808  		id:           BootstrapInstanceId,
   809  		addresses:    network.NewAddresses("localhost"),
   810  		machineId:    agent.BootstrapMachineId,
   811  		series:       series,
   812  		firewallMode: e.Config().FirewallMode(),
   813  		state:        estate,
   814  		controller:   true,
   815  	}
   816  	estate.insts[i.id] = i
   817  	estate.bootstrapped = true
   818  	estate.ops <- OpBootstrap{Context: ctx, Env: e.name, Args: args}
   819  
   820  	finalize := func(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig, _ environs.BootstrapDialOpts) (err error) {
   821  		if e.ecfg().controller() {
   822  			icfg.Bootstrap.BootstrapMachineInstanceId = BootstrapInstanceId
   823  			if err := instancecfg.FinishInstanceConfig(icfg, e.Config()); err != nil {
   824  				return err
   825  			}
   826  
   827  			adminUser := names.NewUserTag("admin@local")
   828  			var cloudCredentialTag names.CloudCredentialTag
   829  			if icfg.Bootstrap.ControllerCloudCredentialName != "" {
   830  				cloudCredentialTag = names.NewCloudCredentialTag(fmt.Sprintf(
   831  					"%s/%s/%s",
   832  					icfg.Bootstrap.ControllerCloud.Name,
   833  					adminUser.Id(),
   834  					icfg.Bootstrap.ControllerCloudCredentialName,
   835  				))
   836  			}
   837  
   838  			cloudCredentials := make(map[names.CloudCredentialTag]cloud.Credential)
   839  			if icfg.Bootstrap.ControllerCloudCredential != nil && icfg.Bootstrap.ControllerCloudCredentialName != "" {
   840  				cloudCredentials[cloudCredentialTag] = *icfg.Bootstrap.ControllerCloudCredential
   841  			}
   842  
   843  			session, err := mongo.DialWithInfo(mongoInfo(), mongotest.DialOpts())
   844  			if err != nil {
   845  				return err
   846  			}
   847  			defer session.Close()
   848  
   849  			// Since the admin user isn't setup until after here,
   850  			// the password in the info structure is empty, so the admin
   851  			// user is constructed with an empty password here.
   852  			// It is set just below.
   853  			controller, err := state.Initialize(state.InitializeParams{
   854  				Clock:            clock.WallClock,
   855  				ControllerConfig: icfg.Controller.Config,
   856  				ControllerModelArgs: state.ModelArgs{
   857  					Type:                    state.ModelTypeIAAS,
   858  					Owner:                   adminUser,
   859  					Config:                  icfg.Bootstrap.ControllerModelConfig,
   860  					Constraints:             icfg.Bootstrap.BootstrapMachineConstraints,
   861  					CloudName:               icfg.Bootstrap.ControllerCloud.Name,
   862  					CloudRegion:             icfg.Bootstrap.ControllerCloudRegion,
   863  					CloudCredential:         cloudCredentialTag,
   864  					StorageProviderRegistry: e,
   865  				},
   866  				Cloud:            icfg.Bootstrap.ControllerCloud,
   867  				CloudCredentials: cloudCredentials,
   868  				MongoSession:     session,
   869  				NewPolicy:        estate.newStatePolicy,
   870  				AdminPassword:    icfg.Controller.MongoInfo.Password,
   871  			})
   872  			if err != nil {
   873  				return err
   874  			}
   875  			st := controller.SystemState()
   876  			defer func() {
   877  				if err != nil {
   878  					controller.Close()
   879  				}
   880  			}()
   881  			if err := st.SetModelConstraints(args.ModelConstraints); err != nil {
   882  				return errors.Trace(err)
   883  			}
   884  			if err := st.SetAdminMongoPassword(icfg.Controller.MongoInfo.Password); err != nil {
   885  				return errors.Trace(err)
   886  			}
   887  			if err := st.MongoSession().DB("admin").Login("admin", icfg.Controller.MongoInfo.Password); err != nil {
   888  				return err
   889  			}
   890  			env, err := st.Model()
   891  			if err != nil {
   892  				return errors.Trace(err)
   893  			}
   894  			owner, err := st.User(env.Owner())
   895  			if err != nil {
   896  				return errors.Trace(err)
   897  			}
   898  			// We log this out for test purposes only. No one in real life can use
   899  			// a dummy provider for anything other than testing, so logging the password
   900  			// here is fine.
   901  			logger.Debugf("setting password for %q to %q", owner.Name(), icfg.Controller.MongoInfo.Password)
   902  			owner.SetPassword(icfg.Controller.MongoInfo.Password)
   903  			statePool := controller.StatePool()
   904  			stateAuthenticator, err := stateauthenticator.NewAuthenticator(statePool, clock.WallClock)
   905  			if err != nil {
   906  				return errors.Trace(err)
   907  			}
   908  			stateAuthenticator.AddHandlers(estate.mux)
   909  
   910  			machineTag := names.NewMachineTag("0")
   911  			estate.httpServer.StartTLS()
   912  			estate.presence = &fakePresence{make(map[string]presence.Status)}
   913  			estate.hub = centralhub.New(machineTag)
   914  
   915  			estate.leaseManager, err = leaseManager(
   916  				icfg.Controller.Config.ControllerUUID(),
   917  				st,
   918  			)
   919  			if err != nil {
   920  				return errors.Trace(err)
   921  			}
   922  
   923  			modelCache, err := modelcache.NewWorker(modelcache.Config{
   924  				Logger:               loggo.GetLogger("dummy"),
   925  				StatePool:            statePool,
   926  				PrometheusRegisterer: noopRegisterer{},
   927  				Cleanup:              func() {},
   928  			})
   929  			if err != nil {
   930  				return errors.Trace(err)
   931  			}
   932  			estate.modelCacheWorker = modelCache
   933  			err = modelcache.ExtractCacheController(modelCache, &estate.controller)
   934  			if err != nil {
   935  				worker.Stop(modelCache)
   936  				return errors.Trace(err)
   937  			}
   938  
   939  			estate.apiServer, err = apiserver.NewServer(apiserver.ServerConfig{
   940  				StatePool:      statePool,
   941  				Controller:     estate.controller,
   942  				Authenticator:  stateAuthenticator,
   943  				Clock:          clock.WallClock,
   944  				GetAuditConfig: func() auditlog.Config { return auditlog.Config{} },
   945  				Tag:            machineTag,
   946  				DataDir:        DataDir,
   947  				LogDir:         LogDir,
   948  				Mux:            estate.mux,
   949  				Hub:            estate.hub,
   950  				Presence:       estate.presence,
   951  				LeaseManager:   estate.leaseManager,
   952  				NewObserver: func() observer.Observer {
   953  					logger := loggo.GetLogger("juju.apiserver")
   954  					ctx := observer.RequestObserverContext{
   955  						Clock:  clock.WallClock,
   956  						Logger: logger,
   957  						Hub:    estate.hub,
   958  					}
   959  					return observer.NewRequestObserver(ctx)
   960  				},
   961  				RateLimitConfig: apiserver.DefaultRateLimitConfig(),
   962  				PublicDNSName:   icfg.Controller.Config.AutocertDNSName(),
   963  				UpgradeComplete: func() bool {
   964  					return true
   965  				},
   966  				RestoreStatus: func() state.RestoreStatus {
   967  					return state.RestoreNotActive
   968  				},
   969  				MetricsCollector: apiserver.NewMetricsCollector(),
   970  			})
   971  			if err != nil {
   972  				panic(err)
   973  			}
   974  			estate.apiState = st
   975  			estate.apiStatePool = statePool
   976  
   977  			// Maintain the state authenticator (time out local user interactions).
   978  			abort := make(chan struct{})
   979  			go stateAuthenticator.Maintain(abort)
   980  			go func(apiServer *apiserver.Server) {
   981  				defer close(abort)
   982  				apiServer.Wait()
   983  			}(estate.apiServer)
   984  		}
   985  		estate.ops <- OpFinalizeBootstrap{Context: ctx, Env: e.name, InstanceConfig: icfg}
   986  		return nil
   987  	}
   988  
   989  	bsResult := &environs.BootstrapResult{
   990  		Arch:                    arch,
   991  		Series:                  series,
   992  		CloudBootstrapFinalizer: finalize,
   993  	}
   994  	return bsResult, nil
   995  }
   996  
   997  func leaseManager(controllerUUID string, st *state.State) (*lease.Manager, error) {
   998  	target := st.LeaseNotifyTarget(
   999  		ioutil.Discard,
  1000  		loggo.GetLogger("juju.state.raftlease"),
  1001  	)
  1002  	dummyStore := newLeaseStore(clock.WallClock, target, st.LeaseTrapdoorFunc())
  1003  	return lease.NewManager(lease.ManagerConfig{
  1004  		Secretary:            lease.SecretaryFinder(controllerUUID),
  1005  		Store:                dummyStore,
  1006  		Logger:               loggo.GetLogger("juju.worker.lease.dummy"),
  1007  		Clock:                clock.WallClock,
  1008  		MaxSleep:             time.Minute,
  1009  		EntityUUID:           controllerUUID,
  1010  		PrometheusRegisterer: noopRegisterer{},
  1011  	})
  1012  }
  1013  
  1014  func (e *environ) ControllerInstances(ctx context.ProviderCallContext, controllerUUID string) ([]instance.Id, error) {
  1015  	estate, err := e.state()
  1016  	if err != nil {
  1017  		return nil, err
  1018  	}
  1019  	estate.mu.Lock()
  1020  	defer estate.mu.Unlock()
  1021  	if err := e.checkBroken("ControllerInstances"); err != nil {
  1022  		return nil, err
  1023  	}
  1024  	if !estate.bootstrapped {
  1025  		return nil, environs.ErrNotBootstrapped
  1026  	}
  1027  	var controllerInstances []instance.Id
  1028  	for _, v := range estate.insts {
  1029  		if v.controller {
  1030  			controllerInstances = append(controllerInstances, v.Id())
  1031  		}
  1032  	}
  1033  	return controllerInstances, nil
  1034  }
  1035  
  1036  func (e *environ) Config() *config.Config {
  1037  	return e.ecfg().Config
  1038  }
  1039  
  1040  func (e *environ) SetConfig(cfg *config.Config) error {
  1041  	if err := e.checkBroken("SetConfig"); err != nil {
  1042  		return err
  1043  	}
  1044  	ecfg, err := dummy.newConfig(cfg)
  1045  	if err != nil {
  1046  		return err
  1047  	}
  1048  	e.ecfgMutex.Lock()
  1049  	e.ecfgUnlocked = ecfg
  1050  	e.ecfgMutex.Unlock()
  1051  	return nil
  1052  }
  1053  
  1054  // AdoptResources is part of the Environ interface.
  1055  func (e *environ) AdoptResources(ctx context.ProviderCallContext, controllerUUID string, fromVersion version.Number) error {
  1056  	// This provider doesn't track instance -> controller.
  1057  	return nil
  1058  }
  1059  
  1060  func (e *environ) Destroy(ctx context.ProviderCallContext) (res error) {
  1061  	defer delay()
  1062  	estate, err := e.state()
  1063  	if err != nil {
  1064  		if err == errNotPrepared {
  1065  			return nil
  1066  		}
  1067  		return err
  1068  	}
  1069  	defer func() {
  1070  		// The estate is a pointer to a structure that is stored in the dummy global.
  1071  		// The Listen method can change the ops channel of any state, and will do so
  1072  		// under the covers. What we need to do is use the state mutex to add a memory
  1073  		// barrier such that the ops channel we see here is the latest.
  1074  		estate.mu.Lock()
  1075  		ops := estate.ops
  1076  		name := estate.name
  1077  		delete(dummy.state, e.modelUUID)
  1078  		estate.mu.Unlock()
  1079  		ops <- OpDestroy{
  1080  			Env:         name,
  1081  			Cloud:       e.cloud.Name,
  1082  			CloudRegion: e.cloud.Region,
  1083  			Error:       res,
  1084  		}
  1085  	}()
  1086  	if err := e.checkBroken("Destroy"); err != nil {
  1087  		return err
  1088  	}
  1089  	if !e.ecfg().controller() {
  1090  		return nil
  1091  	}
  1092  	estate.destroy()
  1093  	return nil
  1094  }
  1095  
  1096  func (e *environ) DestroyController(ctx context.ProviderCallContext, controllerUUID string) error {
  1097  	if err := e.Destroy(ctx); err != nil {
  1098  		return err
  1099  	}
  1100  	dummy.mu.Lock()
  1101  	dummy.controllerState = nil
  1102  	dummy.mu.Unlock()
  1103  	return nil
  1104  }
  1105  
  1106  // ConstraintsValidator is defined on the Environs interface.
  1107  func (e *environ) ConstraintsValidator(ctx context.ProviderCallContext) (constraints.Validator, error) {
  1108  	validator := constraints.NewValidator()
  1109  	validator.RegisterUnsupported([]string{constraints.CpuPower, constraints.VirtType})
  1110  	validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem})
  1111  	validator.RegisterVocabulary(constraints.Arch, []string{arch.AMD64, arch.ARM64, arch.I386, arch.PPC64EL})
  1112  	return validator, nil
  1113  }
  1114  
  1115  // MaintainInstance is specified in the InstanceBroker interface.
  1116  func (*environ) MaintainInstance(ctx context.ProviderCallContext, args environs.StartInstanceParams) error {
  1117  	return nil
  1118  }
  1119  
  1120  // StartInstance is specified in the InstanceBroker interface.
  1121  func (e *environ) StartInstance(ctx context.ProviderCallContext, args environs.StartInstanceParams) (*environs.StartInstanceResult, error) {
  1122  
  1123  	defer delay()
  1124  	machineId := args.InstanceConfig.MachineId
  1125  	logger.Infof("dummy startinstance, machine %s", machineId)
  1126  	if err := e.checkBroken("StartInstance"); err != nil {
  1127  		return nil, err
  1128  	}
  1129  	estate, err := e.state()
  1130  	if err != nil {
  1131  		return nil, err
  1132  	}
  1133  	estate.mu.Lock()
  1134  	defer estate.mu.Unlock()
  1135  
  1136  	// check if an error has been injected on the transientErrorInjection channel (testing purposes)
  1137  	select {
  1138  	case injectedError := <-transientErrorInjection:
  1139  		return nil, injectedError
  1140  	default:
  1141  	}
  1142  
  1143  	if args.InstanceConfig.MachineNonce == "" {
  1144  		return nil, errors.New("cannot start instance: missing machine nonce")
  1145  	}
  1146  	if args.InstanceConfig.Controller != nil {
  1147  		if args.InstanceConfig.Controller.MongoInfo.Tag != names.NewMachineTag(machineId) {
  1148  			return nil, errors.New("entity tag must match started machine")
  1149  		}
  1150  	}
  1151  	if args.InstanceConfig.APIInfo.Tag != names.NewMachineTag(machineId) {
  1152  		return nil, errors.New("entity tag must match started machine")
  1153  	}
  1154  	logger.Infof("would pick agent binaries from %s", args.Tools)
  1155  	series := args.Tools.OneSeries()
  1156  
  1157  	idString := fmt.Sprintf("%s-%d", e.name, estate.maxId)
  1158  	// Add the addresses we want to see in the machine doc. This means both
  1159  	// IPv4 and IPv6 loopback, as well as the DNS name.
  1160  	addrs := network.NewAddresses(idString+".dns", "127.0.0.1", "::1")
  1161  	logger.Debugf("StartInstance addresses: %v", addrs)
  1162  	i := &dummyInstance{
  1163  		id:           instance.Id(idString),
  1164  		addresses:    addrs,
  1165  		machineId:    machineId,
  1166  		series:       series,
  1167  		firewallMode: e.Config().FirewallMode(),
  1168  		state:        estate,
  1169  	}
  1170  
  1171  	var hc *instance.HardwareCharacteristics
  1172  	// To match current system capability, only provide hardware characteristics for
  1173  	// environ machines, not containers.
  1174  	if state.ParentId(machineId) == "" {
  1175  		// Assume that the provided Availability Zone won't fail,
  1176  		// though one is required.
  1177  		var zone string
  1178  		if args.Placement != "" {
  1179  			split := strings.Split(args.Placement, "=")
  1180  			if len(split) == 2 && split[0] == "zone" {
  1181  				zone = split[1]
  1182  			}
  1183  		}
  1184  		if zone == "" && args.AvailabilityZone != "" {
  1185  			zone = args.AvailabilityZone
  1186  		}
  1187  
  1188  		// We will just assume the instance hardware characteristics exactly matches
  1189  		// the supplied constraints (if specified).
  1190  		hc = &instance.HardwareCharacteristics{
  1191  			Arch:             args.Constraints.Arch,
  1192  			Mem:              args.Constraints.Mem,
  1193  			RootDisk:         args.Constraints.RootDisk,
  1194  			CpuCores:         args.Constraints.CpuCores,
  1195  			CpuPower:         args.Constraints.CpuPower,
  1196  			Tags:             args.Constraints.Tags,
  1197  			AvailabilityZone: &zone,
  1198  		}
  1199  		// Fill in some expected instance hardware characteristics if constraints not specified.
  1200  		if hc.Arch == nil {
  1201  			arch := "amd64"
  1202  			hc.Arch = &arch
  1203  		}
  1204  		if hc.Mem == nil {
  1205  			mem := uint64(1024)
  1206  			hc.Mem = &mem
  1207  		}
  1208  		if hc.RootDisk == nil {
  1209  			disk := uint64(8192)
  1210  			hc.RootDisk = &disk
  1211  		}
  1212  		if hc.CpuCores == nil {
  1213  			cores := uint64(1)
  1214  			hc.CpuCores = &cores
  1215  		}
  1216  	}
  1217  	// Simulate subnetsToZones gets populated when spaces given in constraints.
  1218  	spaces := args.Constraints.IncludeSpaces()
  1219  	var subnetsToZones map[network.Id][]string
  1220  	for isp := range spaces {
  1221  		// Simulate 2 subnets per space.
  1222  		if subnetsToZones == nil {
  1223  			subnetsToZones = make(map[network.Id][]string)
  1224  		}
  1225  		for isn := 0; isn < 2; isn++ {
  1226  			providerId := fmt.Sprintf("subnet-%d", isp+isn)
  1227  			zone := fmt.Sprintf("zone%d", isp+isn)
  1228  			subnetsToZones[network.Id(providerId)] = []string{zone}
  1229  		}
  1230  	}
  1231  	// Simulate creating volumes when requested.
  1232  	volumes := make([]storage.Volume, len(args.Volumes))
  1233  	for iv, v := range args.Volumes {
  1234  		persistent, _ := v.Attributes["persistent"].(bool)
  1235  		volumes[iv] = storage.Volume{
  1236  			Tag: v.Tag,
  1237  			VolumeInfo: storage.VolumeInfo{
  1238  				Size:       v.Size,
  1239  				Persistent: persistent,
  1240  			},
  1241  		}
  1242  	}
  1243  	// Simulate attaching volumes when requested.
  1244  	volumeAttachments := make([]storage.VolumeAttachment, len(args.VolumeAttachments))
  1245  	for iv, v := range args.VolumeAttachments {
  1246  		volumeAttachments[iv] = storage.VolumeAttachment{
  1247  			Volume:  v.Volume,
  1248  			Machine: v.Machine,
  1249  			VolumeAttachmentInfo: storage.VolumeAttachmentInfo{
  1250  				DeviceName: fmt.Sprintf("sd%c", 'b'+rune(iv)),
  1251  				ReadOnly:   v.ReadOnly,
  1252  			},
  1253  		}
  1254  	}
  1255  	var mongoInfo *mongo.MongoInfo
  1256  	if args.InstanceConfig.Controller != nil {
  1257  		mongoInfo = args.InstanceConfig.Controller.MongoInfo
  1258  	}
  1259  	estate.insts[i.id] = i
  1260  	estate.maxId++
  1261  	estate.ops <- OpStartInstance{
  1262  		Env:               e.name,
  1263  		MachineId:         machineId,
  1264  		MachineNonce:      args.InstanceConfig.MachineNonce,
  1265  		PossibleTools:     args.Tools,
  1266  		Constraints:       args.Constraints,
  1267  		SubnetsToZones:    subnetsToZones,
  1268  		Volumes:           volumes,
  1269  		VolumeAttachments: volumeAttachments,
  1270  		Instance:          i,
  1271  		Jobs:              args.InstanceConfig.Jobs,
  1272  		Info:              mongoInfo,
  1273  		APIInfo:           args.InstanceConfig.APIInfo,
  1274  		AgentEnvironment:  args.InstanceConfig.AgentEnvironment,
  1275  		Secret:            e.ecfg().secret(),
  1276  	}
  1277  	return &environs.StartInstanceResult{
  1278  		Instance: i,
  1279  		Hardware: hc,
  1280  	}, nil
  1281  }
  1282  
  1283  func (e *environ) StopInstances(ctx context.ProviderCallContext, ids ...instance.Id) error {
  1284  	defer delay()
  1285  	if err := e.checkBroken("StopInstance"); err != nil {
  1286  		return err
  1287  	}
  1288  	estate, err := e.state()
  1289  	if err != nil {
  1290  		return err
  1291  	}
  1292  	estate.mu.Lock()
  1293  	defer estate.mu.Unlock()
  1294  	for _, id := range ids {
  1295  		delete(estate.insts, id)
  1296  	}
  1297  	estate.ops <- OpStopInstances{
  1298  		Env: e.name,
  1299  		Ids: ids,
  1300  	}
  1301  	return nil
  1302  }
  1303  
  1304  func (e *environ) Instances(ctx context.ProviderCallContext, ids []instance.Id) (insts []instances.Instance, err error) {
  1305  	defer delay()
  1306  	if err := e.checkBroken("Instances"); err != nil {
  1307  		return nil, err
  1308  	}
  1309  	if len(ids) == 0 {
  1310  		return nil, nil
  1311  	}
  1312  	estate, err := e.state()
  1313  	if err != nil {
  1314  		return nil, err
  1315  	}
  1316  	estate.mu.Lock()
  1317  	defer estate.mu.Unlock()
  1318  	notFound := 0
  1319  	for _, id := range ids {
  1320  		inst := estate.insts[id]
  1321  		if inst == nil {
  1322  			err = environs.ErrPartialInstances
  1323  			notFound++
  1324  			insts = append(insts, nil)
  1325  		} else {
  1326  			insts = append(insts, inst)
  1327  		}
  1328  	}
  1329  	if notFound == len(ids) {
  1330  		return nil, environs.ErrNoInstances
  1331  	}
  1332  	return
  1333  }
  1334  
  1335  // SupportsSpaces is specified on environs.Networking.
  1336  func (env *environ) SupportsSpaces(ctx context.ProviderCallContext) (bool, error) {
  1337  	dummy.mu.Lock()
  1338  	defer dummy.mu.Unlock()
  1339  	if !dummy.supportsSpaces {
  1340  		return false, errors.NotSupportedf("spaces")
  1341  	}
  1342  	return true, nil
  1343  }
  1344  
  1345  // SupportsSpaceDiscovery is specified on environs.Networking.
  1346  func (env *environ) SupportsSpaceDiscovery(ctx context.ProviderCallContext) (bool, error) {
  1347  	if err := env.checkBroken("SupportsSpaceDiscovery"); err != nil {
  1348  		return false, err
  1349  	}
  1350  	dummy.mu.Lock()
  1351  	defer dummy.mu.Unlock()
  1352  	if !dummy.supportsSpaceDiscovery {
  1353  		return false, nil
  1354  	}
  1355  	return true, nil
  1356  }
  1357  
  1358  // SupportsContainerAddresses is specified on environs.Networking.
  1359  func (env *environ) SupportsContainerAddresses(ctx context.ProviderCallContext) (bool, error) {
  1360  	return false, errors.NotSupportedf("container addresses")
  1361  }
  1362  
  1363  // Spaces is specified on environs.Networking.
  1364  func (env *environ) Spaces(ctx context.ProviderCallContext) ([]network.SpaceInfo, error) {
  1365  	if err := env.checkBroken("Spaces"); err != nil {
  1366  		return []network.SpaceInfo{}, err
  1367  	}
  1368  	return []network.SpaceInfo{{
  1369  		Name:       "foo",
  1370  		ProviderId: network.Id("0"),
  1371  		Subnets: []network.SubnetInfo{{
  1372  			ProviderId:        network.Id("1"),
  1373  			AvailabilityZones: []string{"zone1"},
  1374  		}, {
  1375  			ProviderId:        network.Id("2"),
  1376  			AvailabilityZones: []string{"zone1"},
  1377  		}}}, {
  1378  		Name:       "Another Foo 99!",
  1379  		ProviderId: "1",
  1380  		Subnets: []network.SubnetInfo{{
  1381  			ProviderId:        network.Id("3"),
  1382  			AvailabilityZones: []string{"zone1"},
  1383  		}}}, {
  1384  		Name:       "foo-",
  1385  		ProviderId: "2",
  1386  		Subnets: []network.SubnetInfo{{
  1387  			ProviderId:        network.Id("4"),
  1388  			AvailabilityZones: []string{"zone1"},
  1389  		}}}, {
  1390  		Name:       "---",
  1391  		ProviderId: "3",
  1392  		Subnets: []network.SubnetInfo{{
  1393  			ProviderId:        network.Id("5"),
  1394  			AvailabilityZones: []string{"zone1"},
  1395  		}}}}, nil
  1396  }
  1397  
  1398  // NetworkInterfaces implements Environ.NetworkInterfaces().
  1399  func (env *environ) NetworkInterfaces(ctx context.ProviderCallContext, instId instance.Id) ([]network.InterfaceInfo, error) {
  1400  	if err := env.checkBroken("NetworkInterfaces"); err != nil {
  1401  		return nil, err
  1402  	}
  1403  
  1404  	estate, err := env.state()
  1405  	if err != nil {
  1406  		return nil, err
  1407  	}
  1408  	estate.mu.Lock()
  1409  	defer estate.mu.Unlock()
  1410  
  1411  	// Simulate 3 NICs - primary and secondary enabled plus a disabled NIC.
  1412  	// all configured using DHCP and having fake DNS servers and gateway.
  1413  	info := make([]network.InterfaceInfo, 3)
  1414  	for i, netName := range []string{"private", "public", "disabled"} {
  1415  		info[i] = network.InterfaceInfo{
  1416  			DeviceIndex:      i,
  1417  			ProviderId:       network.Id(fmt.Sprintf("dummy-eth%d", i)),
  1418  			ProviderSubnetId: network.Id("dummy-" + netName),
  1419  			InterfaceType:    network.EthernetInterface,
  1420  			CIDR:             fmt.Sprintf("0.%d.0.0/24", (i+1)*10),
  1421  			InterfaceName:    fmt.Sprintf("eth%d", i),
  1422  			VLANTag:          i,
  1423  			MACAddress:       fmt.Sprintf("aa:bb:cc:dd:ee:f%d", i),
  1424  			Disabled:         i == 2,
  1425  			NoAutoStart:      i%2 != 0,
  1426  			ConfigType:       network.ConfigDHCP,
  1427  			Address: network.NewAddress(
  1428  				fmt.Sprintf("0.%d.0.%d", (i+1)*10, estate.maxAddr+2),
  1429  			),
  1430  			DNSServers: network.NewAddresses("ns1.dummy", "ns2.dummy"),
  1431  			GatewayAddress: network.NewAddress(
  1432  				fmt.Sprintf("0.%d.0.1", (i+1)*10),
  1433  			),
  1434  		}
  1435  	}
  1436  
  1437  	estate.ops <- OpNetworkInterfaces{
  1438  		Env:        env.name,
  1439  		InstanceId: instId,
  1440  		Info:       info,
  1441  	}
  1442  
  1443  	return info, nil
  1444  }
  1445  
  1446  type azShim struct {
  1447  	name      string
  1448  	available bool
  1449  }
  1450  
  1451  func (az azShim) Name() string {
  1452  	return az.name
  1453  }
  1454  
  1455  func (az azShim) Available() bool {
  1456  	return az.available
  1457  }
  1458  
  1459  // AvailabilityZones implements environs.ZonedEnviron.
  1460  func (env *environ) AvailabilityZones(ctx context.ProviderCallContext) ([]common.AvailabilityZone, error) {
  1461  	// TODO(dimitern): Fix this properly.
  1462  	return []common.AvailabilityZone{
  1463  		azShim{"zone1", true},
  1464  		azShim{"zone2", false},
  1465  		azShim{"zone3", true},
  1466  		azShim{"zone4", true},
  1467  	}, nil
  1468  }
  1469  
  1470  // InstanceAvailabilityZoneNames implements environs.ZonedEnviron.
  1471  func (env *environ) InstanceAvailabilityZoneNames(ctx context.ProviderCallContext, ids []instance.Id) ([]string, error) {
  1472  	if err := env.checkBroken("InstanceAvailabilityZoneNames"); err != nil {
  1473  		return nil, errors.NotSupportedf("instance availability zones")
  1474  	}
  1475  	availabilityZones, err := env.AvailabilityZones(ctx)
  1476  	if err != nil {
  1477  		return nil, err
  1478  	}
  1479  	azMaxIndex := len(availabilityZones) - 1
  1480  	azIndex := 0
  1481  	returnValue := make([]string, len(ids))
  1482  	for i := range ids {
  1483  		if availabilityZones[azIndex].Available() {
  1484  			returnValue[i] = availabilityZones[azIndex].Name()
  1485  		} else {
  1486  			// Based on knowledge of how the AZs are setup above
  1487  			// in AvailabilityZones()
  1488  			azIndex += 1
  1489  			returnValue[i] = availabilityZones[azIndex].Name()
  1490  		}
  1491  		azIndex += 1
  1492  		if azIndex == azMaxIndex {
  1493  			azIndex = 0
  1494  		}
  1495  	}
  1496  	return returnValue, nil
  1497  }
  1498  
  1499  // DeriveAvailabilityZones is part of the common.ZonedEnviron interface.
  1500  func (env *environ) DeriveAvailabilityZones(ctx context.ProviderCallContext, args environs.StartInstanceParams) ([]string, error) {
  1501  	return nil, nil
  1502  }
  1503  
  1504  // Subnets implements environs.Environ.Subnets.
  1505  func (env *environ) Subnets(ctx context.ProviderCallContext, instId instance.Id, subnetIds []network.Id) ([]network.SubnetInfo, error) {
  1506  	if err := env.checkBroken("Subnets"); err != nil {
  1507  		return nil, err
  1508  	}
  1509  
  1510  	estate, err := env.state()
  1511  	if err != nil {
  1512  		return nil, err
  1513  	}
  1514  	estate.mu.Lock()
  1515  	defer estate.mu.Unlock()
  1516  
  1517  	if ok, _ := env.SupportsSpaceDiscovery(ctx); ok {
  1518  		// Space discovery needs more subnets to work with.
  1519  		return env.subnetsForSpaceDiscovery(estate)
  1520  	}
  1521  
  1522  	allSubnets := []network.SubnetInfo{{
  1523  		CIDR:              "0.10.0.0/24",
  1524  		ProviderId:        "dummy-private",
  1525  		AvailabilityZones: []string{"zone1", "zone2"},
  1526  	}, {
  1527  		CIDR:       "0.20.0.0/24",
  1528  		ProviderId: "dummy-public",
  1529  	}}
  1530  
  1531  	// Filter result by ids, if given.
  1532  	var result []network.SubnetInfo
  1533  	for _, subId := range subnetIds {
  1534  		switch subId {
  1535  		case "dummy-private":
  1536  			result = append(result, allSubnets[0])
  1537  		case "dummy-public":
  1538  			result = append(result, allSubnets[1])
  1539  		}
  1540  	}
  1541  	if len(subnetIds) == 0 {
  1542  		result = append([]network.SubnetInfo{}, allSubnets...)
  1543  	}
  1544  	if len(result) == 0 {
  1545  		// No results, so just return them now.
  1546  		estate.ops <- OpSubnets{
  1547  			Env:        env.name,
  1548  			InstanceId: instId,
  1549  			SubnetIds:  subnetIds,
  1550  			Info:       result,
  1551  		}
  1552  		return result, nil
  1553  	}
  1554  
  1555  	estate.ops <- OpSubnets{
  1556  		Env:        env.name,
  1557  		InstanceId: instId,
  1558  		SubnetIds:  subnetIds,
  1559  		Info:       result,
  1560  	}
  1561  	return result, nil
  1562  }
  1563  
  1564  func (env *environ) subnetsForSpaceDiscovery(estate *environState) ([]network.SubnetInfo, error) {
  1565  	result := []network.SubnetInfo{{
  1566  		ProviderId:        network.Id("1"),
  1567  		AvailabilityZones: []string{"zone1"},
  1568  		CIDR:              "192.168.1.0/24",
  1569  	}, {
  1570  		ProviderId:        network.Id("2"),
  1571  		AvailabilityZones: []string{"zone1"},
  1572  		CIDR:              "192.168.2.0/24",
  1573  		VLANTag:           1,
  1574  	}, {
  1575  		ProviderId:        network.Id("3"),
  1576  		AvailabilityZones: []string{"zone1"},
  1577  		CIDR:              "192.168.3.0/24",
  1578  	}, {
  1579  		ProviderId:        network.Id("4"),
  1580  		AvailabilityZones: []string{"zone1"},
  1581  		CIDR:              "192.168.4.0/24",
  1582  	}, {
  1583  		ProviderId:        network.Id("5"),
  1584  		AvailabilityZones: []string{"zone1"},
  1585  		CIDR:              "192.168.5.0/24",
  1586  	}}
  1587  	estate.ops <- OpSubnets{
  1588  		Env:        env.name,
  1589  		InstanceId: instance.UnknownId,
  1590  		SubnetIds:  []network.Id{},
  1591  		Info:       result,
  1592  	}
  1593  	return result, nil
  1594  }
  1595  
  1596  func (e *environ) AllInstances(ctx context.ProviderCallContext) ([]instances.Instance, error) {
  1597  	defer delay()
  1598  	if err := e.checkBroken("AllInstances"); err != nil {
  1599  		return nil, err
  1600  	}
  1601  	var insts []instances.Instance
  1602  	estate, err := e.state()
  1603  	if err != nil {
  1604  		return nil, err
  1605  	}
  1606  	estate.mu.Lock()
  1607  	defer estate.mu.Unlock()
  1608  	for _, v := range estate.insts {
  1609  		insts = append(insts, v)
  1610  	}
  1611  	return insts, nil
  1612  }
  1613  
  1614  func (e *environ) OpenPorts(ctx context.ProviderCallContext, rules []network.IngressRule) error {
  1615  	if mode := e.ecfg().FirewallMode(); mode != config.FwGlobal {
  1616  		return fmt.Errorf("invalid firewall mode %q for opening ports on model", mode)
  1617  	}
  1618  	estate, err := e.state()
  1619  	if err != nil {
  1620  		return err
  1621  	}
  1622  	estate.mu.Lock()
  1623  	defer estate.mu.Unlock()
  1624  	for _, r := range rules {
  1625  		if len(r.SourceCIDRs) == 0 {
  1626  			r.SourceCIDRs = []string{"0.0.0.0/0"}
  1627  		}
  1628  		found := false
  1629  		for _, rule := range estate.globalRules {
  1630  			if r.String() == rule.String() {
  1631  				found = true
  1632  			}
  1633  		}
  1634  		if !found {
  1635  			estate.globalRules = append(estate.globalRules, r)
  1636  		}
  1637  	}
  1638  
  1639  	return nil
  1640  }
  1641  
  1642  func (e *environ) ClosePorts(ctx context.ProviderCallContext, rules []network.IngressRule) error {
  1643  	if mode := e.ecfg().FirewallMode(); mode != config.FwGlobal {
  1644  		return fmt.Errorf("invalid firewall mode %q for closing ports on model", mode)
  1645  	}
  1646  	estate, err := e.state()
  1647  	if err != nil {
  1648  		return err
  1649  	}
  1650  	estate.mu.Lock()
  1651  	defer estate.mu.Unlock()
  1652  	for _, r := range rules {
  1653  		for i, rule := range estate.globalRules {
  1654  			if r.String() == rule.String() {
  1655  				estate.globalRules = estate.globalRules[:i+copy(estate.globalRules[i:], estate.globalRules[i+1:])]
  1656  			}
  1657  		}
  1658  	}
  1659  	return nil
  1660  }
  1661  
  1662  func (e *environ) IngressRules(ctx context.ProviderCallContext) (rules []network.IngressRule, err error) {
  1663  	if mode := e.ecfg().FirewallMode(); mode != config.FwGlobal {
  1664  		return nil, fmt.Errorf("invalid firewall mode %q for retrieving ingress rules from model", mode)
  1665  	}
  1666  	estate, err := e.state()
  1667  	if err != nil {
  1668  		return nil, err
  1669  	}
  1670  	estate.mu.Lock()
  1671  	defer estate.mu.Unlock()
  1672  	for _, r := range estate.globalRules {
  1673  		rules = append(rules, r)
  1674  	}
  1675  	network.SortIngressRules(rules)
  1676  	return
  1677  }
  1678  
  1679  func (*environ) Provider() environs.EnvironProvider {
  1680  	return &dummy
  1681  }
  1682  
  1683  type dummyInstance struct {
  1684  	state        *environState
  1685  	rules        network.IngressRuleSlice
  1686  	id           instance.Id
  1687  	status       string
  1688  	machineId    string
  1689  	series       string
  1690  	firewallMode string
  1691  	controller   bool
  1692  
  1693  	mu        sync.Mutex
  1694  	addresses []network.Address
  1695  	broken    []string
  1696  }
  1697  
  1698  func (inst *dummyInstance) Id() instance.Id {
  1699  	return inst.id
  1700  }
  1701  
  1702  func (inst *dummyInstance) Status(ctx context.ProviderCallContext) instance.Status {
  1703  	inst.mu.Lock()
  1704  	defer inst.mu.Unlock()
  1705  	// TODO(perrito666) add a provider status -> juju status mapping.
  1706  	jujuStatus := status.Pending
  1707  	if inst.status != "" {
  1708  		dummyStatus := status.Status(inst.status)
  1709  		if dummyStatus.KnownInstanceStatus() {
  1710  			jujuStatus = dummyStatus
  1711  		}
  1712  	}
  1713  
  1714  	return instance.Status{
  1715  		Status:  jujuStatus,
  1716  		Message: inst.status,
  1717  	}
  1718  
  1719  }
  1720  
  1721  // SetInstanceAddresses sets the addresses associated with the given
  1722  // dummy instance.
  1723  func SetInstanceAddresses(inst instances.Instance, addrs []network.Address) {
  1724  	inst0 := inst.(*dummyInstance)
  1725  	inst0.mu.Lock()
  1726  	inst0.addresses = append(inst0.addresses[:0], addrs...)
  1727  	logger.Debugf("setting instance %q addresses to %v", inst0.Id(), addrs)
  1728  	inst0.mu.Unlock()
  1729  }
  1730  
  1731  // SetInstanceStatus sets the status associated with the given
  1732  // dummy instance.
  1733  func SetInstanceStatus(inst instances.Instance, status string) {
  1734  	inst0 := inst.(*dummyInstance)
  1735  	inst0.mu.Lock()
  1736  	inst0.status = status
  1737  	inst0.mu.Unlock()
  1738  }
  1739  
  1740  // SetInstanceBroken marks the named methods of the instance as broken.
  1741  // Any previously broken methods not in the set will no longer be broken.
  1742  func SetInstanceBroken(inst instances.Instance, methods ...string) {
  1743  	inst0 := inst.(*dummyInstance)
  1744  	inst0.mu.Lock()
  1745  	inst0.broken = methods
  1746  	inst0.mu.Unlock()
  1747  }
  1748  
  1749  func (inst *dummyInstance) checkBroken(method string) error {
  1750  	for _, m := range inst.broken {
  1751  		if m == method {
  1752  			return fmt.Errorf("dummyInstance.%s is broken", method)
  1753  		}
  1754  	}
  1755  	return nil
  1756  }
  1757  
  1758  func (inst *dummyInstance) Addresses(ctx context.ProviderCallContext) ([]network.Address, error) {
  1759  	inst.mu.Lock()
  1760  	defer inst.mu.Unlock()
  1761  	if err := inst.checkBroken("Addresses"); err != nil {
  1762  		return nil, err
  1763  	}
  1764  	return append([]network.Address{}, inst.addresses...), nil
  1765  }
  1766  
  1767  func (inst *dummyInstance) OpenPorts(ctx context.ProviderCallContext, machineId string, rules []network.IngressRule) error {
  1768  	defer delay()
  1769  	logger.Infof("openPorts %s, %#v", machineId, rules)
  1770  	if inst.firewallMode != config.FwInstance {
  1771  		return fmt.Errorf("invalid firewall mode %q for opening ports on instance",
  1772  			inst.firewallMode)
  1773  	}
  1774  	if inst.machineId != machineId {
  1775  		panic(fmt.Errorf("OpenPorts with mismatched machine id, expected %q got %q", inst.machineId, machineId))
  1776  	}
  1777  	inst.state.mu.Lock()
  1778  	defer inst.state.mu.Unlock()
  1779  	if err := inst.checkBroken("OpenPorts"); err != nil {
  1780  		return err
  1781  	}
  1782  	inst.state.ops <- OpOpenPorts{
  1783  		Env:        inst.state.name,
  1784  		MachineId:  machineId,
  1785  		InstanceId: inst.Id(),
  1786  		Rules:      rules,
  1787  	}
  1788  	for _, r := range rules {
  1789  		if len(r.SourceCIDRs) == 0 {
  1790  			r.SourceCIDRs = []string{"0.0.0.0/0"}
  1791  		}
  1792  		found := false
  1793  		for i, rule := range inst.rules {
  1794  			if r.PortRange == rule.PortRange {
  1795  				ruleCopy := r
  1796  				inst.rules[i] = ruleCopy
  1797  				found = true
  1798  				break
  1799  			}
  1800  			if r.String() == rule.String() {
  1801  				found = true
  1802  				break
  1803  			}
  1804  		}
  1805  		if !found {
  1806  			inst.rules = append(inst.rules, r)
  1807  		}
  1808  	}
  1809  	return nil
  1810  }
  1811  
  1812  func (inst *dummyInstance) ClosePorts(ctx context.ProviderCallContext, machineId string, rules []network.IngressRule) error {
  1813  	defer delay()
  1814  	if inst.firewallMode != config.FwInstance {
  1815  		return fmt.Errorf("invalid firewall mode %q for closing ports on instance",
  1816  			inst.firewallMode)
  1817  	}
  1818  	if inst.machineId != machineId {
  1819  		panic(fmt.Errorf("ClosePorts with mismatched machine id, expected %s got %s", inst.machineId, machineId))
  1820  	}
  1821  	inst.state.mu.Lock()
  1822  	defer inst.state.mu.Unlock()
  1823  	if err := inst.checkBroken("ClosePorts"); err != nil {
  1824  		return err
  1825  	}
  1826  	inst.state.ops <- OpClosePorts{
  1827  		Env:        inst.state.name,
  1828  		MachineId:  machineId,
  1829  		InstanceId: inst.Id(),
  1830  		Rules:      rules,
  1831  	}
  1832  	for _, r := range rules {
  1833  		for i, rule := range inst.rules {
  1834  			if r.String() == rule.String() {
  1835  				inst.rules = inst.rules[:i+copy(inst.rules[i:], inst.rules[i+1:])]
  1836  			}
  1837  		}
  1838  	}
  1839  	return nil
  1840  }
  1841  
  1842  func (inst *dummyInstance) IngressRules(ctx context.ProviderCallContext, machineId string) (rules []network.IngressRule, err error) {
  1843  	defer delay()
  1844  	if inst.firewallMode != config.FwInstance {
  1845  		return nil, fmt.Errorf("invalid firewall mode %q for retrieving ingress rules from instance",
  1846  			inst.firewallMode)
  1847  	}
  1848  	if inst.machineId != machineId {
  1849  		panic(fmt.Errorf("Rules with mismatched machine id, expected %q got %q", inst.machineId, machineId))
  1850  	}
  1851  	inst.state.mu.Lock()
  1852  	defer inst.state.mu.Unlock()
  1853  	if err := inst.checkBroken("IngressRules"); err != nil {
  1854  		return nil, err
  1855  	}
  1856  	for _, r := range inst.rules {
  1857  		rules = append(rules, r)
  1858  	}
  1859  	network.SortIngressRules(rules)
  1860  	return
  1861  }
  1862  
  1863  // providerDelay controls the delay before dummy responds.
  1864  // non empty values in JUJU_DUMMY_DELAY will be parsed as
  1865  // time.Durations into this value.
  1866  var providerDelay, _ = time.ParseDuration(os.Getenv("JUJU_DUMMY_DELAY")) // parse errors are ignored
  1867  
  1868  // pause execution to simulate the latency of a real provider
  1869  func delay() {
  1870  	if providerDelay > 0 {
  1871  		logger.Infof("pausing for %v", providerDelay)
  1872  		<-time.After(providerDelay)
  1873  	}
  1874  }
  1875  
  1876  func (e *environ) AllocateContainerAddresses(ctx context.ProviderCallContext, hostInstanceID instance.Id, containerTag names.MachineTag, preparedInfo []network.InterfaceInfo) ([]network.InterfaceInfo, error) {
  1877  	return nil, errors.NotSupportedf("container address allocation")
  1878  }
  1879  
  1880  func (e *environ) ReleaseContainerAddresses(ctx context.ProviderCallContext, interfaces []network.ProviderInterfaceInfo) error {
  1881  	return errors.NotSupportedf("container address allocation")
  1882  }
  1883  
  1884  // ProviderSpaceInfo implements NetworkingEnviron.
  1885  func (*environ) ProviderSpaceInfo(ctx context.ProviderCallContext, space *network.SpaceInfo) (*environs.ProviderSpaceInfo, error) {
  1886  	return nil, errors.NotSupportedf("provider space info")
  1887  }
  1888  
  1889  // AreSpacesRoutable implements NetworkingEnviron.
  1890  func (*environ) AreSpacesRoutable(ctx context.ProviderCallContext, space1, space2 *environs.ProviderSpaceInfo) (bool, error) {
  1891  	return false, nil
  1892  }
  1893  
  1894  // MaybeWriteLXDProfile implements environs.LXDProfiler.
  1895  func (env *environ) MaybeWriteLXDProfile(pName string, put *charm.LXDProfile) error {
  1896  	return nil
  1897  }
  1898  
  1899  // LXDProfileNames implements environs.LXDProfiler.
  1900  func (env *environ) LXDProfileNames(containerName string) ([]string, error) {
  1901  	return nil, nil
  1902  }
  1903  
  1904  // ReplaceOrAddInstanceProfile implements environs.LXDProfiler.
  1905  func (env *environ) ReplaceOrAddInstanceProfile(instId, oldProfile, newProfile string, put *charm.LXDProfile) ([]string, error) {
  1906  	return []string{newProfile}, nil
  1907  }
  1908  
  1909  // SSHAddresses implements environs.SSHAddresses.
  1910  // For testing we cut "100.100.100.100" out of this list.
  1911  func (*environ) SSHAddresses(ctx context.ProviderCallContext, addresses []network.Address) ([]network.Address, error) {
  1912  	var rv []network.Address
  1913  	for _, addr := range addresses {
  1914  		if addr.Value != "100.100.100.100" {
  1915  			rv = append(rv, addr)
  1916  		}
  1917  	}
  1918  	return rv, nil
  1919  }
  1920  
  1921  // SuperSubnets implements environs.SuperSubnets
  1922  func (*environ) SuperSubnets(ctx context.ProviderCallContext) ([]string, error) {
  1923  	return nil, errors.NotSupportedf("super subnets")
  1924  }
  1925  
  1926  // SetAgentStatus sets the presence for a particular agent in the fake presence implementation.
  1927  func (e *environ) SetAgentStatus(agent string, status presence.Status) {
  1928  	estate, err := e.state()
  1929  	if err != nil {
  1930  		panic(err)
  1931  	}
  1932  	estate.presence.agent[agent] = status
  1933  }
  1934  
  1935  // fakePresence returns alive for all agent alive requests.
  1936  type fakePresence struct {
  1937  	agent map[string]presence.Status
  1938  }
  1939  
  1940  func (*fakePresence) Disable()        {}
  1941  func (*fakePresence) Enable()         {}
  1942  func (*fakePresence) IsEnabled() bool { return true }
  1943  func (*fakePresence) Connect(server, model, agent string, id uint64, controllerAgent bool, userData string) {
  1944  }
  1945  func (*fakePresence) Disconnect(server string, id uint64)                            {}
  1946  func (*fakePresence) Activity(server string, id uint64)                              {}
  1947  func (*fakePresence) ServerDown(server string)                                       {}
  1948  func (*fakePresence) UpdateServer(server string, connections []presence.Value) error { return nil }
  1949  func (f *fakePresence) Connections() presence.Connections                            { return f }
  1950  
  1951  func (f *fakePresence) ForModel(model string) presence.Connections   { return f }
  1952  func (f *fakePresence) ForServer(server string) presence.Connections { return f }
  1953  func (f *fakePresence) ForAgent(agent string) presence.Connections   { return f }
  1954  func (*fakePresence) Count() int                                     { return 0 }
  1955  func (*fakePresence) Models() []string                               { return nil }
  1956  func (*fakePresence) Servers() []string                              { return nil }
  1957  func (*fakePresence) Agents() []string                               { return nil }
  1958  func (*fakePresence) Values() []presence.Value                       { return nil }
  1959  
  1960  func (f *fakePresence) AgentStatus(agent string) (presence.Status, error) {
  1961  	if status, found := f.agent[agent]; found {
  1962  		return status, nil
  1963  	}
  1964  	return presence.Alive, nil
  1965  }
  1966  
  1967  type noopRegisterer struct {
  1968  	prometheus.Registerer
  1969  }
  1970  
  1971  func (noopRegisterer) Register(prometheus.Collector) error {
  1972  	return nil
  1973  }
  1974  
  1975  func (noopRegisterer) Unregister(prometheus.Collector) bool {
  1976  	return true
  1977  }