1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
|
import rcStatus
import resources as Res
import time
import os
import rcExceptions as ex
from rcGlobalEnv import rcEnv
from rcUtilities import justcall
from rcUtilitiesLinux import check_ping
import resContainer
class CloudVm(resContainer.Container):
startup_timeout = 240
shutdown_timeout = 120
save_timeout = 240
def __init__(self,
rid,
name,
guestos=None,
cloud_id=None,
image_id=None,
size="t2.micro",
key_name=None,
subnet=None,
osvc_root_path=None,
**kwargs):
resContainer.Container.__init__(self,
rid=rid,
name=name,
type="container.amazon",
guestos=guestos,
osvc_root_path=osvc_root_path,
**kwargs)
self.cloud_id = cloud_id
self.save_name = name + '.save'
self.size_id = size
self.image_id = image_id
self.key_name = key_name
self.subnet_name = subnet
self.addr = None
def keyfile(self):
kf = [os.path.join(rcEnv.pathetc, self.key_name+'.pem'),
os.path.join(rcEnv.pathetc, self.key_name+'.pub'),
os.path.join(rcEnv.pathvar, self.key_name+'.pem'),
os.path.join(rcEnv.pathvar, self.key_name+'.pub')]
for k in kf:
if os.path.exists(k):
return k
raise ex.excError("key file for key name '%s' not found"%self.key_name)
def rcp_from(self, src, dst):
if self.guestos == "Windows":
""" Windows has no sshd.
"""
raise ex.excNotSupported("remote copy not supported on Windows")
self.getaddr()
if self.addr is None:
raise ex.excError('no usable ip to send files to')
timeout = 5
cmd = [ 'scp', '-o', 'StrictHostKeyChecking=no',
'-o', 'ConnectTimeout='+str(timeout),
'-i', self.keyfile(),
self.addr+':'+src, dst]
out, err, ret = justcall(cmd)
if ret != 0:
raise ex.excError("'%s' execution error:\n%s"%(' '.join(cmd), err))
return out, err, ret
def rcp(self, src, dst):
if self.guestos == "Windows":
""" Windows has no sshd.
"""
raise ex.excNotSupported("remote copy not supported on Windows")
self.getaddr()
if self.addr is None:
raise ex.excError('no usable ip to send files to')
timeout = 5
cmd = [ 'scp', '-o', 'StrictHostKeyChecking=no',
'-o', 'ConnectTimeout='+str(timeout),
'-i', self.keyfile(),
src, self.addr+':'+dst]
out, err, ret = justcall(cmd)
if ret != 0:
raise ex.excError("'%s' execution error:\n%s"%(' '.join(cmd), err))
return out, err, ret
def rcmd(self, cmd):
if self.guestos == "Windows":
""" Windows has no sshd.
"""
raise ex.excNotSupported("remote commands not supported on Windows")
self.getaddr()
if self.addr is None:
raise ex.excError('no usable ip to send command to')
if type(cmd) == str:
cmd = cmd.split(" ")
timeout = 5
cmd = [ 'ssh', '-o', 'StrictHostKeyChecking=no',
'-o', 'ForwardX11=no',
'-o', 'BatchMode=yes',
'-n',
'-o', 'ConnectTimeout='+str(timeout),
'-i', self.keyfile(),
self.addr] + cmd
out, err, ret = justcall(cmd)
if ret != 0:
raise ex.excError("'%s' execution error:\n%s"%(' '.join(cmd), err))
return out, err, ret
def get_subnet(self):
c = self.get_cloud()
for subnet in c.driver.ex_list_subnets():
if subnet.name == self.subnet_name:
return subnet
raise ex.excError("%s subnet not found"%self.subnet_name)
def get_size(self):
c = self.get_cloud()
for size in c.driver.list_sizes():
if size.id == self.size_id:
return size
raise ex.excError("%s size not found"%self.size_name)
def get_cloud(self):
if hasattr(self, 'cloud'):
return self.cloud
c = self.svc.node.cloud_get(self.cloud_id)
self.cloud = c
return self.cloud
def get_node(self):
c = self.get_cloud()
l = c.list_nodes()
for n in l:
if n.name == self.name:
return n
return
def get_image(self, image_id):
c = self.get_cloud()
l = c.driver.list_images(ex_image_ids=[image_id])
d = {}
for image in l:
if image.id == image_id:
# exact match
return image
raise ex.excError("image %s not found" % image_id)
def has_image(self, image_id):
c = self.get_cloud()
l = c.driver.list_images([image_id])
for image in l:
if image.id == image_id:
return True
return False
def __str__(self):
return "%s name=%s" % (Res.Resource.__str__(self), self.name)
def getaddr(self):
if self.addr is not None:
return
n = self.get_node()
if n is None:
raise ex.excError("could not get node details")
ips = set(n.public_ips+n.private_ips)
if len(ips) == 0:
return 0
# find first pinging ip
for ip in ips:
if check_ping(ip, timeout=1, count=1):
self.addr = ip
break
return 0
def files_to_sync(self):
return []
def check_capabilities(self):
return True
def ping(self):
if self.addr is None:
return 0
return check_ping(self.addr, timeout=1, count=1)
def start(self):
if self.is_up():
self.log.info("container %s already started" % self.name)
return
if rcEnv.nodename in self.svc.drpnodes:
self.install_drp_flag()
self.container_start()
self.can_rollback = True
self.wait_for_startup()
def container_start(self):
"""
RUNNING = 0
REBOOTING = 1
TERMINATED = 2
PENDING = 3
UNKNOWN = 4
STOPPED = 5
SUSPENDED = 6
ERROR = 7
PAUSED = 8
"""
from libcloud.compute.types import NodeState
n = self.get_node()
if n is None:
self.provision()
return
elif n.state == NodeState().RUNNING:
self.log.info("already running")
return
elif n.state == NodeState().PENDING:
self.log.info("already pending. wait for running state.")
self.wait_for_fn(self.is_up, self.startup_timeout, 5)
return
elif n.state == NodeState().REBOOTING:
self.log.info("currently rebooting. wait for running state.")
self.wait_for_fn(self.is_up, self.startup_timeout, 5)
return
elif n.state == NodeState().STOPPED:
c = self.get_cloud()
self.log.info("starting ebs ec2 instance through aws")
c.driver.ex_start_node(n)
self.log.info("wait for container up status")
self.wait_for_fn(self.is_up, self.startup_timeout, 5)
return
raise ex.excError("don't know what to do with node in state: %s"%NodeState().tostring(n.state))
def container_reboot(self):
c = self.get_cloud()
n = self.get_node()
try:
c.driver.reboot_node(n)
except Exception as e:
raise ex.excError(str(e))
def wait_for_startup(self):
pass
def stop(self):
if self.is_down():
self.log.info("container %s already stopped" % self.name)
return
try:
self.container_stop()
self.wait_for_shutdown()
except ex.excError:
self.container_forcestop()
self.wait_for_shutdown()
def container_stop(self):
cmd = "shutdown -h now"
self.log.info("remote command: %s"%cmd)
self.rcmd(cmd)
def container_forcestop(self):
c = self.get_cloud()
n = self.get_node()
self.log.info("stopping ebs ec2 instance through aws")
c.driver.ex_stop_node(n)
def print_obj(self, n):
for k in dir(n):
if '__' in k:
continue
print(k, "=", getattr(n, k))
def is_up(self):
from libcloud.compute.types import NodeState
n = self.get_node()
if n is not None and n.state == NodeState().RUNNING:
return True
if n is None:
self.status_log("state:unknown")
else:
self.status_log("state:"+NodeState().tostring(n.state))
return False
def get_container_info(self):
self.info = {'vcpus': '0', 'vmem': '0'}
c = self.get_cloud()
n = self.get_node()
try:
size = c.driver.ex_get_size(n.extra['flavorId'])
self.info['vmem'] = str(size.ram)
except:
pass
return self.info
def check_manual_boot(self):
return True
def install_drp_flag(self):
pass
def provision(self):
prereq = True
if self.image_id is None:
self.log.error("the image keyword is mandatory for the provision action")
prereq &= False
if self.size_id is None:
self.log.error("the size keyword is mandatory for the provision action")
prereq &= False
if self.subnet_name is None:
self.log.error("the subnet keyword is mandatory for the provision action")
prereq &= False
if self.key_name is None:
self.log.error("the key_name keyword is mandatory for the provision action")
prereq &= False
if not prereq:
raise ex.excError()
c = self.get_cloud()
image = self.get_image(self.image_id)
size = self.get_size()
subnet = self.get_subnet()
self.log.info("create instance %s, size %s, image %s, key %s, subnet %s"%(self.name, size.name, image.name, self.key_name, subnet.name))
c.driver.create_node(name=self.name, size=size, image=image, ex_keyname=self.key_name, ex_subnet=subnet)
self.log.info("wait for container up status")
self.wait_for_fn(self.is_up, self.startup_timeout, 5)
|