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 }