github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/cloud/providers/mock/mock.go (about)

     1  package mock
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/evergreen-ci/evergreen"
     9  	"github.com/evergreen-ci/evergreen/cloud"
    10  	"github.com/evergreen-ci/evergreen/model/distro"
    11  	"github.com/evergreen-ci/evergreen/model/host"
    12  	"github.com/evergreen-ci/evergreen/util"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  const ProviderName = "mock"
    17  
    18  // MockInstance mocks a running server that Evergreen knows about. It contains
    19  // fields that can be set to change the response the cloud manager returns
    20  // when this mock instance is queried for.
    21  type MockInstance struct {
    22  	IsUp               bool
    23  	IsSSHReachable     bool
    24  	Status             cloud.CloudStatus
    25  	SSHOptions         []string
    26  	TimeTilNextPayment time.Duration
    27  	DNSName            string
    28  	OnUpRan            bool
    29  }
    30  
    31  var MockInstances map[string]MockInstance = map[string]MockInstance{}
    32  var lock = sync.RWMutex{}
    33  
    34  func Clear() {
    35  	MockInstances = map[string]MockInstance{}
    36  	lock = sync.RWMutex{}
    37  }
    38  
    39  // MockCloudManager implements the CloudManager interface for testing
    40  // purposes. It contains a map of MockInstances that it knows about
    41  // which its various functions return information about. Once set before
    42  // testing, this map should only be touched either through the associated
    43  // cloud manager functions, or in association with the mutex.
    44  type MockCloudManager struct {
    45  	Instances map[string]MockInstance
    46  	mutex     *sync.RWMutex
    47  }
    48  
    49  func FetchMockProvider() *MockCloudManager {
    50  	return &MockCloudManager{
    51  		Instances: MockInstances,
    52  		mutex:     &lock,
    53  	}
    54  }
    55  
    56  func (mockMgr *MockCloudManager) SpawnInstance(distro *distro.Distro, hostOpts cloud.HostOptions) (*host.Host, error) {
    57  	intentHost := cloud.NewIntent(*distro, fmt.Sprintf("mock_%v", util.RandomString()), ProviderName, hostOpts)
    58  	if err := intentHost.Insert(); err != nil {
    59  		return nil, errors.Wrapf(err, "Could not insert intent host '%v'", intentHost.Id)
    60  	}
    61  	l := mockMgr.mutex
    62  	l.Lock()
    63  	defer l.Unlock()
    64  	mockMgr.Instances[intentHost.Id] = MockInstance{
    65  		IsUp:               false,
    66  		IsSSHReachable:     false,
    67  		Status:             cloud.StatusInitializing,
    68  		SSHOptions:         []string{},
    69  		TimeTilNextPayment: time.Duration(0),
    70  		DNSName:            "",
    71  	}
    72  	return intentHost, nil
    73  }
    74  
    75  // get the status of an instance
    76  func (mockMgr *MockCloudManager) GetInstanceStatus(host *host.Host) (cloud.CloudStatus, error) {
    77  	l := mockMgr.mutex
    78  	l.RLock()
    79  	instance, ok := mockMgr.Instances[host.Id]
    80  	l.RUnlock()
    81  	if !ok {
    82  		return cloud.StatusUnknown, errors.Errorf("unable to fetch host: %s", host.Id)
    83  	}
    84  
    85  	return instance.Status, nil
    86  }
    87  
    88  // get instance DNS
    89  func (mockMgr *MockCloudManager) GetDNSName(host *host.Host) (string, error) {
    90  	l := mockMgr.mutex
    91  	l.RLock()
    92  	instance, ok := mockMgr.Instances[host.Id]
    93  	l.RUnlock()
    94  	if !ok {
    95  		return "", errors.Errorf("unable to fetch host: %s", host.Id)
    96  	}
    97  	return instance.DNSName, nil
    98  }
    99  
   100  func (_ *MockCloudManager) GetSettings() cloud.ProviderSettings {
   101  	return &MockCloudManager{}
   102  }
   103  
   104  func (_ *MockCloudManager) Validate() error {
   105  	return nil
   106  }
   107  
   108  func (mockMgr *MockCloudManager) CanSpawn() (bool, error) {
   109  	return true, nil
   110  }
   111  
   112  // terminate an instance
   113  func (mockMgr *MockCloudManager) TerminateInstance(host *host.Host) error {
   114  	l := mockMgr.mutex
   115  	l.Lock()
   116  	defer l.Unlock()
   117  	instance, ok := mockMgr.Instances[host.Id]
   118  	if !ok {
   119  		return errors.Errorf("unable to fetch host: %s", host.Id)
   120  	}
   121  	if host.Status == evergreen.HostTerminated {
   122  		return errors.Errorf("Cannot terminate %s; already marked as terminated!", host.Id)
   123  	}
   124  
   125  	instance.Status = cloud.StatusTerminated
   126  	mockMgr.Instances[host.Id] = instance
   127  
   128  	return errors.WithStack(host.Terminate())
   129  }
   130  
   131  func (mockMgr *MockCloudManager) Configure(settings *evergreen.Settings) error {
   132  	//no-op. maybe will need to load something from settings in the future.
   133  	return nil
   134  }
   135  
   136  func (mockMgr *MockCloudManager) IsSSHReachable(host *host.Host, keyPath string) (bool, error) {
   137  	l := mockMgr.mutex
   138  	l.RLock()
   139  	instance, ok := mockMgr.Instances[host.Id]
   140  	l.RUnlock()
   141  	if !ok {
   142  		return false, errors.Errorf("unable to fetch host: %s", host.Id)
   143  	}
   144  	return instance.IsSSHReachable, nil
   145  }
   146  
   147  func (mockMgr *MockCloudManager) IsUp(host *host.Host) (bool, error) {
   148  	l := mockMgr.mutex
   149  	l.RLock()
   150  	instance, ok := mockMgr.Instances[host.Id]
   151  	l.RUnlock()
   152  	if !ok {
   153  		return false, errors.Errorf("unable to fetch host: %s", host.Id)
   154  	}
   155  	return instance.IsUp, nil
   156  }
   157  
   158  func (mockMgr *MockCloudManager) OnUp(host *host.Host) error {
   159  	l := mockMgr.mutex
   160  	l.Lock()
   161  	defer l.Unlock()
   162  	instance, ok := mockMgr.Instances[host.Id]
   163  	if !ok {
   164  		return errors.Errorf("unable to fetch host: %s", host.Id)
   165  	}
   166  	instance.OnUpRan = true
   167  	mockMgr.Instances[host.Id] = instance
   168  
   169  	return nil
   170  }
   171  
   172  func (mockMgr *MockCloudManager) GetSSHOptions(host *host.Host, keyPath string) ([]string, error) {
   173  	l := mockMgr.mutex
   174  	l.RLock()
   175  	instance, ok := mockMgr.Instances[host.Id]
   176  	l.RUnlock()
   177  	if !ok {
   178  		return []string{}, errors.Errorf("unable to fetch host: %s", host.Id)
   179  	}
   180  	return instance.SSHOptions, nil
   181  }
   182  
   183  func (mockMgr *MockCloudManager) TimeTilNextPayment(host *host.Host) time.Duration {
   184  	l := mockMgr.mutex
   185  	l.RLock()
   186  	instance, ok := mockMgr.Instances[host.Id]
   187  	l.RUnlock()
   188  	if !ok {
   189  		return time.Duration(0)
   190  	}
   191  	return instance.TimeTilNextPayment
   192  }