Skip to content
Browse files

Removing modules that will be broken out as separate modules under bo…

…to organization.
  • Loading branch information...
1 parent 5aa93b7 commit 043319b92e7752dbbe8d1241eabf87e05e37610f @garnaat garnaat committed Mar 27, 2012
View
22 boto/contrib/__init__.py
@@ -1,22 +0,0 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-#
-
View
52 boto/contrib/m2helpers.py
@@ -1,52 +0,0 @@
-# Copyright (c) 2006,2007 Jon Colverson
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-This module was contributed by Jon Colverson. It provides a couple of helper
-functions that allow you to use M2Crypto's implementation of HTTPSConnection
-rather than the default version in httplib.py. The main benefit is that
-M2Crypto's version verifies the certificate of the server.
-
-To use this feature, do something like this:
-
-from boto.ec2.connection import EC2Connection
-
-ec2 = EC2Connection(ACCESS_KEY_ID, SECRET_ACCESS_KEY,
- https_connection_factory=https_connection_factory(cafile=CA_FILE))
-
-See http://code.google.com/p/boto/issues/detail?id=57 for more details.
-"""
-from M2Crypto import SSL
-from M2Crypto.httpslib import HTTPSConnection
-
-def secure_context(cafile=None, capath=None):
- ctx = SSL.Context()
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9)
- if ctx.load_verify_locations(cafile=cafile, capath=capath) != 1:
- raise Exception("Couldn't load certificates")
- return ctx
-
-def https_connection_factory(cafile=None, capath=None):
- def factory(*args, **kwargs):
- return HTTPSConnection(
- ssl_context=secure_context(cafile=cafile, capath=capath),
- *args, **kwargs)
- return (factory, (SSL.SSLError,))
View
52 boto/contrib/ymlmessage.py
@@ -1,52 +0,0 @@
-# Copyright (c) 2006,2007 Chris Moyer
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-This module was contributed by Chris Moyer. It provides a subclass of the
-SQS Message class that supports YAML as the body of the message.
-
-This module requires the yaml module.
-"""
-from boto.sqs.message import Message
-import yaml
-
-class YAMLMessage(Message):
- """
- The YAMLMessage class provides a YAML compatible message. Encoding and
- decoding are handled automaticaly.
-
- Access this message data like such:
-
- m.data = [ 1, 2, 3]
- m.data[0] # Returns 1
-
- This depends on the PyYAML package
- """
-
- def __init__(self, queue=None, body='', xml_attrs=None):
- self.data = None
- Message.__init__(self, queue, body)
-
- def set_body(self, body):
- self.data = yaml.load(body)
-
- def get_body(self):
- return yaml.dump(self.data)
View
84 boto/ec2/buyreservation.py
@@ -1,84 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-import boto.ec2
-from boto.sdb.db.property import StringProperty, IntegerProperty
-from boto.manage import propget
-
-InstanceTypes = ['m1.small', 'm1.large', 'm1.xlarge',
- 'c1.medium', 'c1.xlarge', 'm2.xlarge',
- 'm2.2xlarge', 'm2.4xlarge', 'cc1.4xlarge',
- 't1.micro']
-
-class BuyReservation(object):
-
- def get_region(self, params):
- if not params.get('region', None):
- prop = StringProperty(name='region', verbose_name='EC2 Region',
- choices=boto.ec2.regions)
- params['region'] = propget.get(prop, choices=boto.ec2.regions)
-
- def get_instance_type(self, params):
- if not params.get('instance_type', None):
- prop = StringProperty(name='instance_type', verbose_name='Instance Type',
- choices=InstanceTypes)
- params['instance_type'] = propget.get(prop)
-
- def get_quantity(self, params):
- if not params.get('quantity', None):
- prop = IntegerProperty(name='quantity', verbose_name='Number of Instances')
- params['quantity'] = propget.get(prop)
-
- def get_zone(self, params):
- if not params.get('zone', None):
- prop = StringProperty(name='zone', verbose_name='EC2 Availability Zone',
- choices=self.ec2.get_all_zones)
- params['zone'] = propget.get(prop)
-
- def get(self, params):
- self.get_region(params)
- self.ec2 = params['region'].connect()
- self.get_instance_type(params)
- self.get_zone(params)
- self.get_quantity(params)
-
-if __name__ == "__main__":
- obj = BuyReservation()
- params = {}
- obj.get(params)
- offerings = obj.ec2.get_all_reserved_instances_offerings(instance_type=params['instance_type'],
- availability_zone=params['zone'].name)
- print('\nThe following Reserved Instances Offerings are available:\n')
- for offering in offerings:
- offering.describe()
- prop = StringProperty(name='offering', verbose_name='Offering',
- choices=offerings)
- offering = propget.get(prop)
- print('\nYou have chosen this offering:')
- offering.describe()
- unit_price = float(offering.fixed_price)
- total_price = unit_price * params['quantity']
- print('!!! You are about to purchase %d of these offerings for a total of $%.2f !!!' % (params['quantity'], total_price))
- answer = raw_input('Are you sure you want to do this? If so, enter YES: ')
- if answer.strip().lower() == 'yes':
- offering.purchase(params['quantity'])
- else:
- print('Purchase cancelled')
View
23 boto/manage/__init__.py
@@ -1,23 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-#
-
-
View
242 boto/manage/cmdshell.py
@@ -1,242 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-from boto.mashups.interactive import interactive_shell
-import boto
-import os
-import time
-import shutil
-import paramiko
-import socket
-import subprocess
-import boto.compat as compat
-
-
-class SSHClient(object):
-
- def __init__(self, server,
- host_key_file='~/.ssh/known_hosts',
- uname='root', ssh_pwd=None):
- self.server = server
- self.host_key_file = host_key_file
- self.uname = uname
- self._pkey = paramiko.RSAKey.from_private_key_file(server.ssh_key_file,
- password=ssh_pwd)
- self._ssh_client = paramiko.SSHClient()
- self._ssh_client.load_system_host_keys()
- self._ssh_client.load_host_keys(os.path.expanduser(host_key_file))
- self._ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- self.connect()
-
- def connect(self):
- retry = 0
- while retry < 5:
- try:
- self._ssh_client.connect(self.server.hostname,
- username=self.uname,
- pkey=self._pkey)
- return
- except socket.error as err:
- (value, message) = err.args
- if value == 61 or value == 111:
- print('SSH Connection refused, will retry in 5 seconds')
- time.sleep(5)
- retry += 1
- else:
- raise
- except paramiko.BadHostKeyException:
- print("%s has an entry in ~/.ssh/known_hosts and it doesn't match" % self.server.hostname)
- print('Edit that file to remove the entry and then hit return to try again')
- raw_input('Hit Enter when ready')
- retry += 1
- except EOFError:
- print('Unexpected Error from SSH Connection, retry in 5 seconds')
- time.sleep(5)
- retry += 1
- print('Could not establish SSH connection')
-
- def open_sftp(self):
- return self._ssh_client.open_sftp()
-
- def get_file(self, src, dst):
- sftp_client = self.open_sftp()
- sftp_client.get(src, dst)
-
- def put_file(self, src, dst):
- sftp_client = self.open_sftp()
- sftp_client.put(src, dst)
-
- def open(self, filename, mode='r', bufsize=-1):
- """
- Open a file on the remote system and return a file-like object.
- """
- sftp_client = self.open_sftp()
- return sftp_client.open(filename, mode, bufsize)
-
- def listdir(self, path):
- sftp_client = self.open_sftp()
- return sftp_client.listdir(path)
-
- def isdir(self, path):
- status = self.run('[ -d %s ] || echo "FALSE"' % path)
- if status[1].startswith('FALSE'):
- return 0
- return 1
-
- def exists(self, path):
- status = self.run('[ -a %s ] || echo "FALSE"' % path)
- if status[1].startswith('FALSE'):
- return 0
- return 1
-
- def shell(self):
- """
- Start an interactive shell session on the remote host.
- """
- channel = self._ssh_client.invoke_shell()
- interactive_shell(channel)
-
- def run(self, command):
- """
- Execute a command on the remote host. Return a tuple containing
- an integer status and a two strings, the first containing stdout
- and the second containing stderr from the command.
- """
- boto.log.debug('running:%s on %s' % (command, self.server.instance_id))
- status = 0
- try:
- t = self._ssh_client.exec_command(command)
- except paramiko.SSHException:
- status = 1
- std_out = t[1].read()
- std_err = t[2].read()
- t[0].close()
- t[1].close()
- t[2].close()
- boto.log.debug('stdout: %s' % std_out)
- boto.log.debug('stderr: %s' % std_err)
- return (status, std_out, std_err)
-
- def run_pty(self, command):
- """
- Execute a command on the remote host with a pseudo-terminal.
- Returns a string containing the output of the command.
- """
- boto.log.debug('running:%s on %s' % (command, self.server.instance_id))
- channel = self._ssh_client.get_transport().open_session()
- channel.get_pty()
- channel.exec_command(command)
- return channel
-
- def close(self):
- transport = self._ssh_client.get_transport()
- transport.close()
- self.server.reset_cmdshell()
-
-class LocalClient(object):
-
- def __init__(self, server, host_key_file=None, uname='root'):
- self.server = server
- self.host_key_file = host_key_file
- self.uname = uname
-
- def get_file(self, src, dst):
- shutil.copyfile(src, dst)
-
- def put_file(self, src, dst):
- shutil.copyfile(src, dst)
-
- def listdir(self, path):
- return os.listdir(path)
-
- def isdir(self, path):
- return os.path.isdir(path)
-
- def exists(self, path):
- return os.path.exists(path)
-
- def shell(self):
- raise NotImplementedError('shell not supported with LocalClient')
-
- def run(self):
- boto.log.info('running:%s' % self.command)
- log_fp = compat.StringIO()
- process = subprocess.Popen(self.command, shell=True, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- while process.poll() == None:
- time.sleep(1)
- t = process.communicate()
- log_fp.write(t[0])
- log_fp.write(t[1])
- boto.log.info(log_fp.getvalue())
- boto.log.info('output: %s' % log_fp.getvalue())
- return (process.returncode, log_fp.getvalue())
-
- def close(self):
- pass
-
-class FakeServer(object):
- """
- A little class to fake out SSHClient (which is expecting a
- :class`boto.manage.server.Server` instance. This allows us
- to
- """
- def __init__(self, instance, ssh_key_file):
- self.instance = instance
- self.ssh_key_file = ssh_key_file
- self.hostname = instance.dns_name
- self.instance_id = self.instance.id
-
-def start(server):
- instance_id = boto.config.get('Instance', 'instance-id', None)
- if instance_id == server.instance_id:
- return LocalClient(server)
- else:
- return SSHClient(server)
-
-def sshclient_from_instance(instance, ssh_key_file,
- host_key_file='~/.ssh/known_hosts',
- user_name='root', ssh_pwd=None):
- """
- Create and return an SSHClient object given an
- instance object.
-
- :type instance: :class`boto.ec2.instance.Instance` object
- :param instance: The instance object.
-
- :type ssh_key_file: str
- :param ssh_key_file: A path to the private key file used
- to log into instance.
-
- :type host_key_file: str
- :param host_key_file: A path to the known_hosts file used
- by the SSH client.
- Defaults to ~/.ssh/known_hosts
- :type user_name: str
- :param user_name: The username to use when logging into
- the instance. Defaults to root.
-
- :type ssh_pwd: str
- :param ssh_pwd: The passphrase, if any, associated with
- private key.
- """
- s = FakeServer(instance, ssh_key_file)
- return SSHClient(s, host_key_file, user_name, ssh_pwd)
View
64 boto/manage/propget.py
@@ -1,64 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-
-def get(prop, choices=None):
- prompt = prop.verbose_name
- if not prompt:
- prompt = prop.name
- if choices:
- if callable(choices):
- choices = choices()
- else:
- choices = prop.get_choices()
- valid = False
- while not valid:
- if choices:
- min = 1
- max = len(choices)
- for i in range(min, max+1):
- value = choices[i-1]
- if isinstance(value, tuple):
- value = value[0]
- print('[%d] %s' % (i, value))
- value = raw_input('%s [%d-%d]: ' % (prompt, min, max))
- try:
- int_value = int(value)
- value = choices[int_value-1]
- if isinstance(value, tuple):
- value = value[1]
- valid = True
- except ValueError:
- print('%s is not a valid choice' % value)
- except IndexError:
- print('%s is not within the range[%d-%d]' % (min, max))
- else:
- value = raw_input('%s: ' % prompt)
- try:
- value = prop.validate(value)
- if prop.empty(value) and prop.required:
- print('A value is required')
- else:
- valid = True
- except:
- print('Invalid value: %s' % value)
- return value
-
View
557 boto/manage/server.py
@@ -1,557 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-# Copyright (c) 2010 Chris Moyer http://coredumped.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-High-level abstraction of an EC2 server
-"""
-from __future__ import with_statement
-import boto.ec2
-from boto.mashups.iobject import IObject
-from boto.pyami.config import BotoConfigPath, Config
-from boto.sdb.db.model import Model
-from boto.sdb.db.property import StringProperty, IntegerProperty, BooleanProperty, CalculatedProperty
-from boto.manage import propget
-from boto.ec2.zone import Zone
-from boto.ec2.keypair import KeyPair
-import os, time
-from contextlib import closing
-from boto.exception import EC2ResponseError
-import boto.compat as compat
-
-InstanceTypes = ['m1.small', 'm1.large', 'm1.xlarge',
- 'c1.medium', 'c1.xlarge',
- 'm2.2xlarge', 'm2.4xlarge']
-
-class Bundler(object):
-
- def __init__(self, server, uname='root'):
- from boto.manage.cmdshell import SSHClient
- self.server = server
- self.uname = uname
- self.ssh_client = SSHClient(server, uname=uname)
-
- def copy_x509(self, key_file, cert_file):
- print('\tcopying cert and pk over to /mnt directory on server')
- self.ssh_client.open_sftp()
- path, name = os.path.split(key_file)
- self.remote_key_file = '/mnt/%s' % name
- self.ssh_client.put_file(key_file, self.remote_key_file)
- path, name = os.path.split(cert_file)
- self.remote_cert_file = '/mnt/%s' % name
- self.ssh_client.put_file(cert_file, self.remote_cert_file)
- print('...complete!')
-
- def bundle_image(self, prefix, size, ssh_key):
- command = ""
- if self.uname != 'root':
- command = "sudo "
- command += 'ec2-bundle-vol '
- command += '-c %s -k %s ' % (self.remote_cert_file, self.remote_key_file)
- command += '-u %s ' % self.server._reservation.owner_id
- command += '-p %s ' % prefix
- command += '-s %d ' % size
- command += '-d /mnt '
- if self.server.instance_type == 'm1.small' or self.server.instance_type == 'c1.medium':
- command += '-r i386'
- else:
- command += '-r x86_64'
- return command
-
- def upload_bundle(self, bucket, prefix, ssh_key):
- command = ""
- if self.uname != 'root':
- command = "sudo "
- command += 'ec2-upload-bundle '
- command += '-m /mnt/%s.manifest.xml ' % prefix
- command += '-b %s ' % bucket
- command += '-a %s ' % self.server.ec2.aws_access_key_id
- command += '-s %s ' % self.server.ec2.aws_secret_access_key
- return command
-
- def bundle(self, bucket=None, prefix=None, key_file=None, cert_file=None,
- size=None, ssh_key=None, fp=None, clear_history=True):
- iobject = IObject()
- if not bucket:
- bucket = iobject.get_string('Name of S3 bucket')
- if not prefix:
- prefix = iobject.get_string('Prefix for AMI file')
- if not key_file:
- key_file = iobject.get_filename('Path to RSA private key file')
- if not cert_file:
- cert_file = iobject.get_filename('Path to RSA public cert file')
- if not size:
- size = iobject.get_int('Size (in MB) of bundled image')
- if not ssh_key:
- ssh_key = self.server.get_ssh_key_file()
- self.copy_x509(key_file, cert_file)
- if not fp:
- fp = compat.StringIO()
- fp.write('sudo mv %s /mnt/boto.cfg; ' % BotoConfigPath)
- fp.write('mv ~/.ssh/authorized_keys /mnt/authorized_keys; ')
- if clear_history:
- fp.write('history -c; ')
- fp.write(self.bundle_image(prefix, size, ssh_key))
- fp.write('; ')
- fp.write(self.upload_bundle(bucket, prefix, ssh_key))
- fp.write('; ')
- fp.write('sudo mv /mnt/boto.cfg %s; ' % BotoConfigPath)
- fp.write('mv /mnt/authorized_keys ~/.ssh/authorized_keys')
- command = fp.getvalue()
- print('running the following command on the remote server:')
- print(command)
- t = self.ssh_client.run(command)
- print('\t%s' % t[0])
- print('\t%s' % t[1])
- print('...complete!')
- print('registering image...')
- self.image_id = self.server.ec2.register_image(name=prefix, image_location='%s/%s.manifest.xml' % (bucket, prefix))
- return self.image_id
-
-class CommandLineGetter(object):
-
- def get_ami_list(self):
- my_amis = []
- for ami in self.ec2.get_all_images():
- # hack alert, need a better way to do this!
- if ami.location.find('pyami') >= 0:
- my_amis.append((ami.location, ami))
- return my_amis
-
- def get_region(self, params):
- region = params.get('region', None)
- if isinstance(region, compat.string_types):
- region = boto.ec2.get_region(region)
- params['region'] = region
- if not region:
- prop = self.cls.find_property('region_name')
- params['region'] = propget.get(prop, choices=boto.ec2.regions)
- self.ec2 = params['region'].connect()
-
- def get_name(self, params):
- if not params.get('name', None):
- prop = self.cls.find_property('name')
- params['name'] = propget.get(prop)
-
- def get_description(self, params):
- if not params.get('description', None):
- prop = self.cls.find_property('description')
- params['description'] = propget.get(prop)
-
- def get_instance_type(self, params):
- if not params.get('instance_type', None):
- prop = StringProperty(name='instance_type', verbose_name='Instance Type',
- choices=InstanceTypes)
- params['instance_type'] = propget.get(prop)
-
- def get_quantity(self, params):
- if not params.get('quantity', None):
- prop = IntegerProperty(name='quantity', verbose_name='Number of Instances')
- params['quantity'] = propget.get(prop)
-
- def get_zone(self, params):
- if not params.get('zone', None):
- prop = StringProperty(name='zone', verbose_name='EC2 Availability Zone',
- choices=self.ec2.get_all_zones)
- params['zone'] = propget.get(prop)
-
- def get_ami_id(self, params):
- valid = False
- while not valid:
- ami = params.get('ami', None)
- if not ami:
- prop = StringProperty(name='ami', verbose_name='AMI')
- ami = propget.get(prop)
- try:
- rs = self.ec2.get_all_images([ami])
- if len(rs) == 1:
- valid = True
- params['ami'] = rs[0]
- except EC2ResponseError:
- pass
-
- def get_group(self, params):
- group = params.get('group', None)
- if isinstance(group, compat.string_types):
- group_list = self.ec2.get_all_security_groups()
- for g in group_list:
- if g.name == group:
- group = g
- params['group'] = g
- if not group:
- prop = StringProperty(name='group', verbose_name='EC2 Security Group',
- choices=self.ec2.get_all_security_groups)
- params['group'] = propget.get(prop)
-
- def get_key(self, params):
- keypair = params.get('keypair', None)
- if isinstance(keypair, compat.string_types):
- key_list = self.ec2.get_all_key_pairs()
- for k in key_list:
- if k.name == keypair:
- keypair = k.name
- params['keypair'] = k.name
- if not keypair:
- prop = StringProperty(name='keypair', verbose_name='EC2 KeyPair',
- choices=self.ec2.get_all_key_pairs)
- params['keypair'] = propget.get(prop).name
-
- def get(self, cls, params):
- self.cls = cls
- self.get_region(params)
- self.ec2 = params['region'].connect()
- self.get_name(params)
- self.get_description(params)
- self.get_instance_type(params)
- self.get_zone(params)
- self.get_quantity(params)
- self.get_ami_id(params)
- self.get_group(params)
- self.get_key(params)
-
-class Server(Model):
-
- #
- # The properties of this object consists of real properties for data that
- # is not already stored in EC2 somewhere (e.g. name, description) plus
- # calculated properties for all of the properties that are already in
- # EC2 (e.g. hostname, security groups, etc.)
- #
- name = StringProperty(unique=True, verbose_name="Name")
- description = StringProperty(verbose_name="Description")
- region_name = StringProperty(verbose_name="EC2 Region Name")
- instance_id = StringProperty(verbose_name="EC2 Instance ID")
- elastic_ip = StringProperty(verbose_name="EC2 Elastic IP Address")
- production = BooleanProperty(verbose_name="Is This Server Production", default=False)
- ami_id = CalculatedProperty(verbose_name="AMI ID", calculated_type=str, use_method=True)
- zone = CalculatedProperty(verbose_name="Availability Zone Name", calculated_type=str, use_method=True)
- hostname = CalculatedProperty(verbose_name="Public DNS Name", calculated_type=str, use_method=True)
- private_hostname = CalculatedProperty(verbose_name="Private DNS Name", calculated_type=str, use_method=True)
- groups = CalculatedProperty(verbose_name="Security Groups", calculated_type=list, use_method=True)
- security_group = CalculatedProperty(verbose_name="Primary Security Group Name", calculated_type=str, use_method=True)
- key_name = CalculatedProperty(verbose_name="Key Name", calculated_type=str, use_method=True)
- instance_type = CalculatedProperty(verbose_name="Instance Type", calculated_type=str, use_method=True)
- status = CalculatedProperty(verbose_name="Current Status", calculated_type=str, use_method=True)
- launch_time = CalculatedProperty(verbose_name="Server Launch Time", calculated_type=str, use_method=True)
- console_output = CalculatedProperty(verbose_name="Console Output", calculated_type=file, use_method=True)
-
- packages = []
- plugins = []
-
- @classmethod
- def add_credentials(cls, cfg, aws_access_key_id, aws_secret_access_key):
- if not cfg.has_section('Credentials'):
- cfg.add_section('Credentials')
- cfg.set('Credentials', 'aws_access_key_id', aws_access_key_id)
- cfg.set('Credentials', 'aws_secret_access_key', aws_secret_access_key)
- if not cfg.has_section('DB_Server'):
- cfg.add_section('DB_Server')
- cfg.set('DB_Server', 'db_type', 'SimpleDB')
- cfg.set('DB_Server', 'db_name', cls._manager.domain.name)
-
- @classmethod
- def create(cls, config_file=None, logical_volume = None, cfg = None, **params):
- """
- Create a new instance based on the specified configuration file or the specified
- configuration and the passed in parameters.
-
- If the config_file argument is not None, the configuration is read from there.
- Otherwise, the cfg argument is used.
-
- The config file may include other config files with a #import reference. The included
- config files must reside in the same directory as the specified file.
-
- The logical_volume argument, if supplied, will be used to get the current physical
- volume ID and use that as an override of the value specified in the config file. This
- may be useful for debugging purposes when you want to debug with a production config
- file but a test Volume.
-
- The dictionary argument may be used to override any EC2 configuration values in the
- config file.
- """
- if config_file:
- cfg = Config(path=config_file)
- if cfg.has_section('EC2'):
- # include any EC2 configuration values that aren't specified in params:
- for option in cfg.options('EC2'):
- if option not in params:
- params[option] = cfg.get('EC2', option)
- getter = CommandLineGetter()
- getter.get(cls, params)
- region = params.get('region')
- ec2 = region.connect()
- cls.add_credentials(cfg, ec2.aws_access_key_id, ec2.aws_secret_access_key)
- ami = params.get('ami')
- kp = params.get('keypair')
- group = params.get('group')
- zone = params.get('zone')
- # deal with possibly passed in logical volume:
- if logical_volume != None:
- cfg.set('EBS', 'logical_volume_name', logical_volume.name)
- cfg_fp = compat.StringIO()
- cfg.write(cfg_fp)
- # deal with the possibility that zone and/or keypair are strings read from the config file:
- if isinstance(zone, Zone):
- zone = zone.name
- if isinstance(kp, KeyPair):
- kp = kp.name
- reservation = ami.run(min_count=1,
- max_count=params.get('quantity', 1),
- key_name=kp,
- security_groups=[group],
- instance_type=params.get('instance_type'),
- placement = zone,
- user_data = cfg_fp.getvalue())
- l = []
- i = 0
- elastic_ip = params.get('elastic_ip')
- instances = reservation.instances
- if elastic_ip != None and instances.__len__() > 0:
- instance = instances[0]
- print('Waiting for instance to start so we can set its elastic IP address...')
- # Sometimes we get a message from ec2 that says that the instance does not exist.
- # Hopefully the following delay will giv eec2 enough time to get to a stable state:
- time.sleep(5)
- while instance.update() != 'running':
- time.sleep(1)
- instance.use_ip(elastic_ip)
- print('set the elastic IP of the first instance to %s' % elastic_ip)
- for instance in instances:
- s = cls()
- s.ec2 = ec2
- s.name = params.get('name') + '' if i==0 else str(i)
- s.description = params.get('description')
- s.region_name = region.name
- s.instance_id = instance.id
- if elastic_ip and i == 0:
- s.elastic_ip = elastic_ip
- s.put()
- l.append(s)
- i += 1
- return l
-
- @classmethod
- def create_from_instance_id(cls, instance_id, name, description=''):
- regions = boto.ec2.regions()
- for region in regions:
- ec2 = region.connect()
- try:
- rs = ec2.get_all_instances([instance_id])
- except:
- rs = []
- if len(rs) == 1:
- s = cls()
- s.ec2 = ec2
- s.name = name
- s.description = description
- s.region_name = region.name
- s.instance_id = instance_id
- s._reservation = rs[0]
- for instance in s._reservation.instances:
- if instance.id == instance_id:
- s._instance = instance
- s.put()
- return s
- return None
-
- @classmethod
- def create_from_current_instances(cls):
- servers = []
- regions = boto.ec2.regions()
- for region in regions:
- ec2 = region.connect()
- rs = ec2.get_all_instances()
- for reservation in rs:
- for instance in reservation.instances:
- try:
- Server.find(instance_id=instance.id).next()
- boto.log.info('Server for %s already exists' % instance.id)
- except StopIteration:
- s = cls()
- s.ec2 = ec2
- s.name = instance.id
- s.region_name = region.name
- s.instance_id = instance.id
- s._reservation = reservation
- s.put()
- servers.append(s)
- return servers
-
- def __init__(self, id=None, **kw):
- Model.__init__(self, id, **kw)
- self.ssh_key_file = None
- self.ec2 = None
- self._cmdshell = None
- self._reservation = None
- self._instance = None
- self._setup_ec2()
-
- def _setup_ec2(self):
- if self.ec2 and self._instance and self._reservation:
- return
- if self.id:
- if self.region_name:
- for region in boto.ec2.regions():
- if region.name == self.region_name:
- self.ec2 = region.connect()
- if self.instance_id and not self._instance:
- try:
- rs = self.ec2.get_all_instances([self.instance_id])
- if len(rs) >= 1:
- for instance in rs[0].instances:
- if instance.id == self.instance_id:
- self._reservation = rs[0]
- self._instance = instance
- except EC2ResponseError:
- pass
-
- def _status(self):
- status = ''
- if self._instance:
- self._instance.update()
- status = self._instance.state
- return status
-
- def _hostname(self):
- hostname = ''
- if self._instance:
- hostname = self._instance.public_dns_name
- return hostname
-
- def _private_hostname(self):
- hostname = ''
- if self._instance:
- hostname = self._instance.private_dns_name
- return hostname
-
- def _instance_type(self):
- it = ''
- if self._instance:
- it = self._instance.instance_type
- return it
-
- def _launch_time(self):
- lt = ''
- if self._instance:
- lt = self._instance.launch_time
- return lt
-
- def _console_output(self):
- co = ''
- if self._instance:
- co = self._instance.get_console_output()
- return co
-
- def _groups(self):
- gn = []
- if self._reservation:
- gn = self._reservation.groups
- return gn
-
- def _security_group(self):
- groups = self._groups()
- if len(groups) >= 1:
- return groups[0].id
- return ""
-
- def _zone(self):
- zone = None
- if self._instance:
- zone = self._instance.placement
- return zone
-
- def _key_name(self):
- kn = None
- if self._instance:
- kn = self._instance.key_name
- return kn
-
- def put(self):
- Model.put(self)
- self._setup_ec2()
-
- def delete(self):
- if self.production:
- raise ValueError("Can't delete a production server")
- #self.stop()
- Model.delete(self)
-
- def stop(self):
- if self.production:
- raise ValueError("Can't delete a production server")
- if self._instance:
- self._instance.stop()
-
- def terminate(self):
- if self.production:
- raise ValueError("Can't delete a production server")
- if self._instance:
- self._instance.terminate()
-
- def reboot(self):
- if self._instance:
- self._instance.reboot()
-
- def wait(self):
- while self.status != 'running':
- time.sleep(5)
-
- def get_ssh_key_file(self):
- if not self.ssh_key_file:
- ssh_dir = os.path.expanduser('~/.ssh')
- if os.path.isdir(ssh_dir):
- ssh_file = os.path.join(ssh_dir, '%s.pem' % self.key_name)
- if os.path.isfile(ssh_file):
- self.ssh_key_file = ssh_file
- if not self.ssh_key_file:
- iobject = IObject()
- self.ssh_key_file = iobject.get_filename('Path to OpenSSH Key file')
- return self.ssh_key_file
-
- def get_cmdshell(self):
- if not self._cmdshell:
- from . import cmdshell
- self.get_ssh_key_file()
- self._cmdshell = cmdshell.start(self)
- return self._cmdshell
-
- def reset_cmdshell(self):
- self._cmdshell = None
-
- def run(self, command):
- with closing(self.get_cmdshell()) as cmd:
- status = cmd.run(command)
- return status
-
- def get_bundler(self, uname='root'):
- self.get_ssh_key_file()
- return Bundler(self, uname)
-
- def get_ssh_client(self, uname='root', ssh_pwd=None):
- from boto.manage.cmdshell import SSHClient
- self.get_ssh_key_file()
- return SSHClient(self, uname=uname, ssh_pwd=ssh_pwd)
-
- def install(self, pkg):
- return self.run('apt-get -y install %s' % pkg)
-
-
-
View
176 boto/manage/task.py
@@ -1,176 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-#
-
-import boto
-from boto.sdb.db.property import StringProperty, DateTimeProperty, IntegerProperty
-from boto.sdb.db.model import Model
-import boto.compat as compat
-import datetime, subprocess, time
-
-def check_hour(val):
- if val == '*':
- return
- if int(val) < 0 or int(val) > 23:
- raise ValueError
-
-class Task(Model):
-
- """
- A scheduled, repeating task that can be executed by any participating servers.
- The scheduling is similar to cron jobs. Each task has an hour attribute.
- The allowable values for hour are [0-23|*].
-
- To keep the operation reasonably efficient and not cause excessive polling,
- the minimum granularity of a Task is hourly. Some examples:
-
- hour='*' - the task would be executed each hour
- hour='3' - the task would be executed at 3AM GMT each day.
-
- """
- name = StringProperty()
- hour = StringProperty(required=True, validator=check_hour, default='*')
- command = StringProperty(required=True)
- last_executed = DateTimeProperty()
- last_status = IntegerProperty()
- last_output = StringProperty()
- message_id = StringProperty()
-
- @classmethod
- def start_all(cls, queue_name):
- for task in cls.all():
- task.start(queue_name)
-
- def __init__(self, id=None, **kw):
- Model.__init__(self, id, **kw)
- self.hourly = self.hour == '*'
- self.daily = self.hour != '*'
- self.now = datetime.datetime.utcnow()
-
- def check(self):
- """
- Determine how long until the next scheduled time for a Task.
- Returns the number of seconds until the next scheduled time or zero
- if the task needs to be run immediately.
- If it's an hourly task and it's never been run, run it now.
- If it's a daily task and it's never been run and the hour is right, run it now.
- """
- boto.log.info('checking Task[%s]-now=%s, last=%s' % (self.name, self.now, self.last_executed))
-
- if self.hourly and not self.last_executed:
- return 0
-
- if self.daily and not self.last_executed:
- if int(self.hour) == self.now.hour:
- return 0
- else:
- return max( (int(self.hour)-self.now.hour), (self.now.hour-int(self.hour)) )*60*60
-
- delta = self.now - self.last_executed
- if self.hourly:
- if delta.seconds >= 60*60:
- return 0
- else:
- return 60*60 - delta.seconds
- else:
- if int(self.hour) == self.now.hour:
- if delta.days >= 1:
- return 0
- else:
- return 82800 # 23 hours, just to be safe
- else:
- return max( (int(self.hour)-self.now.hour), (self.now.hour-int(self.hour)) )*60*60
-
- def _run(self, msg, vtimeout):
- boto.log.info('Task[%s] - running:%s' % (self.name, self.command))
- log_fp = compat.StringIO()
- process = subprocess.Popen(self.command, shell=True, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- nsecs = 5
- current_timeout = vtimeout
- while process.poll() == None:
- boto.log.info('nsecs=%s, timeout=%s' % (nsecs, current_timeout))
- if nsecs >= current_timeout:
- current_timeout += vtimeout
- boto.log.info('Task[%s] - setting timeout to %d seconds' % (self.name, current_timeout))
- if msg:
- msg.change_visibility(current_timeout)
- time.sleep(5)
- nsecs += 5
- t = process.communicate()
- log_fp.write(t[0])
- log_fp.write(t[1])
- boto.log.info('Task[%s] - output: %s' % (self.name, log_fp.getvalue()))
- self.last_executed = self.now
- self.last_status = process.returncode
- self.last_output = log_fp.getvalue()[0:1023]
-
- def run(self, msg, vtimeout=60):
- delay = self.check()
- boto.log.info('Task[%s] - delay=%s seconds' % (self.name, delay))
- if delay == 0:
- self._run(msg, vtimeout)
- queue = msg.queue
- new_msg = queue.new_message(self.id)
- new_msg = queue.write(new_msg)
- self.message_id = new_msg.id
- self.put()
- boto.log.info('Task[%s] - new message id=%s' % (self.name, new_msg.id))
- msg.delete()
- boto.log.info('Task[%s] - deleted message %s' % (self.name, msg.id))
- else:
- boto.log.info('new_vtimeout: %d' % delay)
- msg.change_visibility(delay)
-
- def start(self, queue_name):
- boto.log.info('Task[%s] - starting with queue: %s' % (self.name, queue_name))
- queue = boto.lookup('sqs', queue_name)
- msg = queue.new_message(self.id)
- msg = queue.write(msg)
- self.message_id = msg.id
- self.put()
- boto.log.info('Task[%s] - start successful' % self.name)
-
-class TaskPoller(object):
-
- def __init__(self, queue_name):
- self.sqs = boto.connect_sqs()
- self.queue = self.sqs.lookup(queue_name)
-
- def poll(self, wait=60, vtimeout=60):
- while 1:
- m = self.queue.read(vtimeout)
- if m:
- task = Task.get_by_id(m.get_body())
- if task:
- if not task.message_id or m.id == task.message_id:
- boto.log.info('Task[%s] - read message %s' % (task.name, m.id))
- task.run(m, vtimeout)
- else:
- boto.log.info('Task[%s] - found extraneous message, ignoring' % task.name)
- else:
- time.sleep(wait)
-
-
-
-
-
-
View
34 boto/manage/test_manage.py
@@ -1,34 +0,0 @@
-from boto.manage.server import Server
-from boto.manage.volume import Volume
-import time
-
-print('--> Creating New Volume')
-volume = Volume.create()
-print(volume)
-
-print('--> Creating New Server')
-server_list = Server.create()
-server = server_list[0]
-print(server)
-
-print('----> Waiting for Server to start up')
-while server.status != 'running':
- print('*')
- time.sleep(10)
-print('----> Server is running')
-
-print('--> Run "df -k" on Server')
-status = server.run('df -k')
-print(status[1])
-
-print('--> Now run volume.make_ready to make the volume ready to use on server')
-volume.make_ready(server)
-
-print('--> Run "df -k" on Server')
-status = server.run('df -k')
-print(status[1])
-
-print('--> Do an "ls -al" on the new filesystem')
-status = server.run('ls -al %s' % volume.mount_point)
-print(status[1])
-
View
420 boto/manage/volume.py
@@ -1,420 +0,0 @@
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-from __future__ import with_statement
-from boto.sdb.db.model import Model
-from boto.sdb.db.property import StringProperty, IntegerProperty, ListProperty, ReferenceProperty, CalculatedProperty
-from boto.manage.server import Server
-from boto.manage import propget
-import boto.utils
-import boto.ec2
-import time
-import traceback
-from contextlib import closing
-import datetime
-
-
-class CommandLineGetter(object):
-
- def get_region(self, params):
- if not params.get('region', None):
- prop = self.cls.find_property('region_name')
- params['region'] = propget.get(prop, choices=boto.ec2.regions)
-
- def get_zone(self, params):
- if not params.get('zone', None):
- prop = StringProperty(name='zone', verbose_name='EC2 Availability Zone',
- choices=self.ec2.get_all_zones)
- params['zone'] = propget.get(prop)
-
- def get_name(self, params):
- if not params.get('name', None):
- prop = self.cls.find_property('name')
- params['name'] = propget.get(prop)
-
- def get_size(self, params):
- if not params.get('size', None):
- prop = IntegerProperty(name='size', verbose_name='Size (GB)')
- params['size'] = propget.get(prop)
-
- def get_mount_point(self, params):
- if not params.get('mount_point', None):
- prop = self.cls.find_property('mount_point')
- params['mount_point'] = propget.get(prop)
-
- def get_device(self, params):
- if not params.get('device', None):
- prop = self.cls.find_property('device')
- params['device'] = propget.get(prop)
-
- def get(self, cls, params):
- self.cls = cls
- self.get_region(params)
- self.ec2 = params['region'].connect()
- self.get_zone(params)
- self.get_name(params)
- self.get_size(params)
- self.get_mount_point(params)
- self.get_device(params)
-
-class Volume(Model):
-
- name = StringProperty(required=True, unique=True, verbose_name='Name')
- region_name = StringProperty(required=True, verbose_name='EC2 Region')
- zone_name = StringProperty(required=True, verbose_name='EC2 Zone')
- mount_point = StringProperty(verbose_name='Mount Point')
- device = StringProperty(verbose_name="Device Name", default='/dev/sdp')
- volume_id = StringProperty(required=True)
- past_volume_ids = ListProperty(item_type=str)
- server = ReferenceProperty(Server, collection_name='volumes',
- verbose_name='Server Attached To')
- volume_state = CalculatedProperty(verbose_name="Volume State",
- calculated_type=str, use_method=True)
- attachment_state = CalculatedProperty(verbose_name="Attachment State",
- calculated_type=str, use_method=True)
- size = CalculatedProperty(verbose_name="Size (GB)",
- calculated_type=int, use_method=True)
-
- @classmethod
- def create(cls, **params):
- getter = CommandLineGetter()
- getter.get(cls, params)
- region = params.get('region')
- ec2 = region.connect()
- zone = params.get('zone')
- size = params.get('size')
- ebs_volume = ec2.create_volume(size, zone.name)
- v = cls()
- v.ec2 = ec2
- v.volume_id = ebs_volume.id
- v.name = params.get('name')
- v.mount_point = params.get('mount_point')
- v.device = params.get('device')
- v.region_name = region.name
- v.zone_name = zone.name
- v.put()
- return v
-
- @classmethod
- def create_from_volume_id(cls, region_name, volume_id, name):
- vol = None
- ec2 = boto.ec2.connect_to_region(region_name)
- rs = ec2.get_all_volumes([volume_id])
- if len(rs) == 1:
- v = rs[0]
- vol = cls()
- vol.volume_id = v.id
- vol.name = name
- vol.region_name = v.region.name
- vol.zone_name = v.zone
- vol.put()
- return vol
-
- def create_from_latest_snapshot(self, name, size=None):
- snapshot = self.get_snapshots()[-1]
- return self.create_from_snapshot(name, snapshot, size)
-
- def create_from_snapshot(self, name, snapshot, size=None):
- if size < self.size:
- size = self.size
- ec2 = self.get_ec2_connection()
- if self.zone_name == None or self.zone_name == '':
- # deal with the migration case where the zone is not set in the logical volume:
- current_volume = ec2.get_all_volumes([self.volume_id])[0]
- self.zone_name = current_volume.zone
- ebs_volume = ec2.create_volume(size, self.zone_name, snapshot)
- v = Volume()
- v.ec2 = self.ec2
- v.volume_id = ebs_volume.id
- v.name = name
- v.mount_point = self.mount_point
- v.device = self.device
- v.region_name = self.region_name
- v.zone_name = self.zone_name
- v.put()
- return v
-
- def get_ec2_connection(self):
- if self.server:
- return self.server.ec2
- if not hasattr(self, 'ec2') or self.ec2 == None:
- self.ec2 = boto.ec2.connect_to_region(self.region_name)
- return self.ec2
-
- def _volume_state(self):
- ec2 = self.get_ec2_connection()
- rs = ec2.get_all_volumes([self.volume_id])
- return rs[0].volume_state()
-
- def _attachment_state(self):
- ec2 = self.get_ec2_connection()
- rs = ec2.get_all_volumes([self.volume_id])
- return rs[0].attachment_state()
-
- def _size(self):
- if not hasattr(self, '__size'):
- ec2 = self.get_ec2_connection()
- rs = ec2.get_all_volumes([self.volume_id])
- self.__size = rs[0].size
- return self.__size
-
- def install_xfs(self):
- if self.server:
- self.server.install('xfsprogs xfsdump')
-
- def get_snapshots(self):
- """
- Returns a list of all completed snapshots for this volume ID.
- """
- ec2 = self.get_ec2_connection()
- rs = ec2.get_all_snapshots()
- all_vols = [self.volume_id] + self.past_volume_ids
- snaps = []
- for snapshot in rs:
- if snapshot.volume_id in all_vols:
- if snapshot.progress == '100%':
- snapshot.date = boto.utils.parse_ts(snapshot.start_time)
- snapshot.keep = True
- snaps.append(snapshot)
- snaps.sort(cmp=lambda x,y: cmp(x.date, y.date))
- return snaps
-
- def attach(self, server=None):
- if self.attachment_state == 'attached':
- print('already attached')
- return None
- if server:
- self.server = server
- self.put()
- ec2 = self.get_ec2_connection()
- ec2.attach_volume(self.volume_id, self.server.instance_id, self.device)
-
- def detach(self, force=False):
- state = self.attachment_state
- if state == 'available' or state == None or state == 'detaching':
- print('already detached')
- return None
- ec2 = self.get_ec2_connection()
- ec2.detach_volume(self.volume_id, self.server.instance_id, self.device, force)
- self.server = None
- self.put()
-
- def checkfs(self, use_cmd=None):
- if self.server == None:
- raise ValueError('server attribute must be set to run this command')
- # detemine state of file system on volume, only works if attached
- if use_cmd:
- cmd = use_cmd
- else:
- cmd = self.server.get_cmdshell()
- status = cmd.run('xfs_check %s' % self.device)
- if not use_cmd:
- cmd.close()
- if status[1].startswith('bad superblock magic number 0'):
- return False
- return True
-
- def wait(self):
- if self.server == None:
- raise ValueError('server attribute must be set to run this command')
- with closing(self.server.get_cmdshell()) as cmd:
- # wait for the volume device to appear
- cmd = self.server.get_cmdshell()
- while not cmd.exists(self.device):
- boto.log.info('%s still does not exist, waiting 10 seconds' % self.device)
- time.sleep(10)
-
- def format(self):
- if self.server == None:
- raise ValueError('server attribute must be set to run this command')
- status = None
- with closing(self.server.get_cmdshell()) as cmd:
- if not self.checkfs(cmd):
- boto.log.info('make_fs...')
- status = cmd.run('mkfs -t xfs %s' % self.device)
- return status
-
- def mount(self):
- if self.server == None:
- raise ValueError('server attribute must be set to run this command')
- boto.log.info('handle_mount_point')
- with closing(self.server.get_cmdshell()) as cmd:
- cmd = self.server.get_cmdshell()
- if not cmd.isdir(self.mount_point):
- boto.log.info('making directory')
- # mount directory doesn't exist so create it
- cmd.run("mkdir %s" % self.mount_point)
- else:
- boto.log.info('directory exists already')
- status = cmd.run('mount -l')
- lines = status[1].split('\n')
- for line in lines:
- t = line.split()
- if t and t[2] == self.mount_point:
- # something is already mounted at the mount point
- # unmount that and mount it as /tmp
- if t[0] != self.device:
- cmd.run('umount %s' % self.mount_point)
- cmd.run('mount %s /tmp' % t[0])
- cmd.run('chmod 777 /tmp')
- break
- # Mount up our new EBS volume onto mount_point
- cmd.run("mount %s %s" % (self.device, self.mount_point))
- cmd.run('xfs_growfs %s' % self.mount_point)
-
- def make_ready(self, server):
- self.server = server
- self.put()
- self.install_xfs()
- self.attach()
- self.wait()
- self.format()
- self.mount()
-
- def freeze(self):
- if self.server:
- return self.server.run("/usr/sbin/xfs_freeze -f %s" % self.mount_point)
-
- def unfreeze(self):
- if self.server:
- return self.server.run("/usr/sbin/xfs_freeze -u %s" % self.mount_point)
-
- def snapshot(self):
- # if this volume is attached to a server
- # we need to freeze the XFS file system
- try:
- self.freeze()
- if self.server == None:
- snapshot = self.get_ec2_connection().create_snapshot(self.volume_id)
- else:
- snapshot = self.server.ec2.create_snapshot(self.volume_id)
- boto.log.info('Snapshot of Volume %s created: %s' % (self.name, snapshot))
- except Exception:
- boto.log.info('Snapshot error')
- boto.log.info(traceback.format_exc())
- finally:
- status = self.unfreeze()
- return status
-
- def get_snapshot_range(self, snaps, start_date=None, end_date=None):
- l = []
- for snap in snaps:
- if start_date and end_date:
- if snap.date >= start_date and snap.date <= end_date:
- l.append(snap)
- elif start_date:
- if snap.date >= start_date:
- l.append(snap)
- elif end_date:
- if snap.date <= end_date:
- l.append(snap)
- else:
- l.append(snap)
- return l
-
- def trim_snapshots(self, delete=False):
- """
- Trim the number of snapshots for this volume. This method always
- keeps the oldest snapshot. It then uses the parameters passed in
- to determine how many others should be kept.
-
- The algorithm is to keep all snapshots from the current day. Then
- it will keep the first snapshot of the day for the previous seven days.
- Then, it will keep the first snapshot of the week for the previous
- four weeks. After than, it will keep the first snapshot of the month
- for as many months as there are.
-
- """
- snaps = self.get_snapshots()
- # Always keep the oldest and the newest
- if len(snaps) <= 2:
- return snaps
- snaps = snaps[1:-1]
- now = datetime.datetime.now(snaps[0].date.tzinfo)
- midnight = datetime.datetime(year=now.year, month=now.month,
- day=now.day, tzinfo=now.tzinfo)
- # Keep the first snapshot from each day of the previous week
- one_week = datetime.timedelta(days=7, seconds=60*60)
- print(midnight-one_week, midnight)
- previous_week = self.get_snapshot_range(snaps, midnight-one_week, midnight)
- print(previous_week)
- if not previous_week:
- return snaps
- current_day = None
- for snap in previous_week:
- if current_day and current_day == snap.date.day:
- snap.keep = False
- else:
- current_day = snap.date.day
- # Get ourselves onto the next full week boundary
- if previous_week:
- week_boundary = previous_week[0].date
- if week_boundary.weekday() != 0:
- delta = datetime.timedelta(days=week_boundary.weekday())
- week_boundary = week_boundary - delta
- # Keep one within this partial week
- partial_week = self.get_snapshot_range(snaps, week_boundary, previous_week[0].date)
- if len(partial_week) > 1:
- for snap in partial_week[1:]:
- snap.keep = False
- # Keep the first snapshot of each week for the previous 4 weeks
- for i in range(0,4):
- weeks_worth = self.get_snapshot_range(snaps, week_boundary-one_week, week_boundary)
- if len(weeks_worth) > 1:
- for snap in weeks_worth[1:]:
- snap.keep = False
- week_boundary = week_boundary - one_week
- # Now look through all remaining snaps and keep one per month
- remainder = self.get_snapshot_range(snaps, end_date=week_boundary)
- current_month = None
- for snap in remainder:
- if current_month and current_month == snap.date.month:
- snap.keep = False
- else:
- current_month = snap.date.month
- if delete:
- for snap in snaps:
- if not snap.keep:
- boto.log.info('Deleting %s(%s) for %s' % (snap, snap.date, self.name))
- snap.delete()
- return snaps
-
- def grow(self, size):
- pass
-
- def copy(self, snapshot):
- pass
-
- def get_snapshot_from_date(self, date):
- pass
-
- def delete(self, delete_ebs_volume=False):
- if delete_ebs_volume:
- self.detach()
- ec2 = self.get_ec2_connection()
- ec2.delete_volume(self.volume_id)
- Model.delete(self)
-
- def archive(self):
- # snapshot volume, trim snaps, delete volume-id
- pass
-
-
View
23 boto/mashups/__init__.py
@@ -1,23 +0,0 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-#
-
-
View
97 boto/mashups/interactive.py
@@ -1,97 +0,0 @@
-# Copyright (C) 2003-2007 Robey Pointer <robey@lag.net>
-#
-# This file is part of paramiko.
-#
-# Paramiko is free software; you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation; either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-
-
-import socket
-import sys
-
-# windows does not have termios...
-try:
- import termios
- import tty
- has_termios = True
-except ImportError:
- has_termios = False
-
-
-def interactive_shell(chan):
- if has_termios:
- posix_shell(chan)
- else:
- windows_shell(chan)
-
-
-def posix_shell(chan):
- import select
-
- oldtty = termios.tcgetattr(sys.stdin)
- try:
- tty.setraw(sys.stdin.fileno())
- tty.setcbreak(sys.stdin.fileno())
- chan.settimeout(0.0)
-
- while True:
- r, w, e = select.select([chan, sys.stdin], [], [])
- if chan in r:
- try:
- x = chan.recv(1024)
- if len(x) == 0:
- print '\r\n*** EOF\r\n',
- break
- sys.stdout.write(x)
- sys.stdout.flush()
- except socket.timeout:
- pass
- if sys.stdin in r:
- x = sys.stdin.read(1)
- if len(x) == 0:
- break
- chan.send(x)
-
- finally:
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
-
-
-# thanks to Mike Looijmans for this code
-def windows_shell(chan):
- import threading
-
- sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
-
- def writeall(sock):
- while True:
- data = sock.recv(256)
- if not data:
- sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
- sys.stdout.flush()
- break
- sys.stdout.write(data)
- sys.stdout.flush()
-
- writer = threading.Thread(target=writeall, args=(chan,))
- writer.start()
-
- try:
- while True:
- d = sys.stdin.read(1)
- if not d:
- break
- chan.send(d)
- except EOFError:
- # user hit ^Z or F6
- pass
View
115 boto/mashups/iobject.py
@@ -1,115 +0,0 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-import os
-
-def int_val_fn(v):
- try:
- int(v)
- return True
- except:
- return False
-
-class IObject(object):
-
- def choose_from_list(self, item_list, search_str='',
- prompt='Enter Selection'):
- if not item_list:
- print 'No Choices Available'
- return
- choice = None
- while not choice:
- n = 1
- choices = []
- for item in item_list:
- if isinstance(item, basestring):
- print '[%d] %s' % (n, item)
- choices.append(item)
- n += 1
- else:
- obj, id, desc = item
- if desc:
- if desc.find(search_str) >= 0:
- print '[%d] %s - %s' % (n, id, desc)
- choices.append(obj)
- n += 1
- else:
- if id.find(search_str) >= 0:
- print '[%d] %s' % (n, id)
- choices.append(obj)
- n += 1
- if choices:
- val = raw_input('%s[1-%d]: ' % (prompt, len(choices)))
- if val.startswith('/'):
- search_str = val[1:]
- else:
- try:
- int_val = int(val)
- if int_val == 0:
- return None
- choice = choices[int_val-1]
- except ValueError:
- print '%s is not a valid choice' % val
- except IndexError:
- print '%s is not within the range[1-%d]' % (val,
- len(choices))
- else:
- print "No objects matched your pattern"
- search_str = ''
- return choice
-
- def get_string(self, prompt, validation_fn=None):
- okay = False
- while not okay:
- val = raw_input('%s: ' % prompt)
- if validation_fn:
- okay = validation_fn(val)
- if not okay:
- print 'Invalid value: %s' % val
- else:
- okay = True
- return val
-
- def get_filename(self, prompt):
- okay = False
- val = ''
- while not okay:
- val = raw_input('%s: %s' % (prompt, val))
- val = os.path.expanduser(val)
- if os.path.isfile(val):
- okay = True
- elif os.path.isdir(val):
- path = val
- val = self.choose_from_list(os.listdir(path))
- if val:
- val = os.path.join(path, val)
- okay = True
- else:
- val = ''
- else:
- print 'Invalid value: %s' % val
- val = ''
- return val
-
- def get_int(self, prompt):
- s = self.get_string(prompt, int_val_fn)
- return int(s)
-
View
211 boto/mashups/order.py
@@ -1,211 +0,0 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-High-level abstraction of an EC2 order for servers
-"""
-
-import boto
-import boto.ec2
-from boto.mashups.server import Server, ServerSet
-from boto.mashups.iobject import IObject
-from boto.pyami.config import Config
-from boto.sdb.persist import get_domain, set_domain
-import time, StringIO
-
-InstanceTypes = ['m1.small', 'm1.large', 'm1.xlarge', 'c1.medium', 'c1.xlarge']
-
-class Item(IObject):
-
- def __init__(self):
- self.region = None
- self.name = None
- self.instance_type = None
- self.quantity = 0
- self.zone = None
- self.ami = None
- self.groups = []
- self.key = None
- self.ec2 = None
- self.config = None
-
- def set_userdata(self, key, value):
- self.userdata[key] = value
-
- def get_userdata(self, key):
- return self.userdata[key]
-
- def set_region(self, region=None):
- if region:
- self.region = region
- else:
- l = [(r, r.name, r.endpoint) for r in boto.ec2.regions()]
- self.region = self.choose_from_list(l, prompt='Choose Region')
-
- def set_name(self, name=None):
- if name:
- self.name = name
- else:
- self.name = self.get_string('Name')
-
- def set_instance_type(self, instance_type=None):
- if instance_type:
- self.instance_type = instance_type
- else:
- self.instance_type = self.choose_from_list(InstanceTypes, 'Instance Type')
-
- def set_quantity(self, n=0):
- if n > 0:
- self.quantity = n
- else:
- self.quantity = self.get_int('Quantity')
-
- def set_zone(self, zone=None):
- if zone:
- self.zone = zone
- else:
- l = [(z, z.name, z.state) for z in self.ec2.get_all_zones()]
- self.zone = self.choose_from_list(l, prompt='Choose Availability Zone')
-
- def set_ami(self, ami=None):
- if ami:
- self.ami = ami
- else:
- l = [(a, a.id, a.location) for a in self.ec2.get_all_images()]
- self.ami = self.choose_from_list(l, prompt='Choose AMI')
-
- def add_group(self, group=None):
- if group:
- self.groups.append(group)
- else:
- l = [(s, s.name, s.description) for s in self.ec2.get_all_security_groups()]
- self.groups.append(self.choose_from_list(l, prompt='Choose Security Group'))
-
- def set_key(self, key=None):
- if key:
- self.key = key
- else:
- l = [(k, k.name, '') for k in self.ec2.get_all_key_pairs()]
- self.key = self.choose_from_list(l, prompt='Choose Keypair')
-
- def update_config(self):
- if not self.config.has_section('Credentials'):
- self.config.add_section('Credentials')
- self.config.set('Credentials', 'aws_access_key_id', self.ec2.aws_access_key_id)
- self.config.set('Credentials', 'aws_secret_access_key', self.ec2.aws_secret_access_key)
- if not self.config.has_section('Pyami'):
- self.config.add_section('Pyami')
- sdb_domain = get_domain()
- if sdb_domain:
- self.config.set('Pyami', 'server_sdb_domain', sdb_domain)
- self.config.set('Pyami', 'server_sdb_name', self.name)
-
- def set_config(self, config_path=None):
- if not config_path:
- config_path = self.get_filename('Specify Config file')
- self.config = Config(path=config_path)
-
- def get_userdata_string(self):
- s = StringIO.StringIO()
- self.config.write(s)
- return s.getvalue()
-
- def enter(self, **params):
- self.region = params.get('region', self.region)
- if not self.region:
- self.set_region()
- self.ec2 = self.region.connect()
- self.name = params.get('name', self.name)
- if not self.name:
- self.set_name()
- self.instance_type = params.get('instance_type', self.instance_type)
- if not self.instance_type:
- self.set_instance_type()
- self.zone = params.get('zone', self.zone)
- if not self.zone:
- self.set_zone()
- self.quantity = params.get('quantity', self.quantity)
- if not self.quantity:
- self.set_quantity()
- self.ami = params.get('ami', self.ami)
- if not self.ami:
- self.set_ami()
- self.groups = params.get('groups', self.groups)
- if not self.groups:
- self.add_group()
- self.key = params.get('key', self.key)
- if not self.key:
- self.set_key()
- self.config = params.get('config', self.config)
- if not self.config:
- self.set_config()
- self.update_config()
-
-class Order(IObject):
-
- def __init__(self):
- self.items = []
- self.reservation = None
-
- def add_item(self, **params):
- item = Item()
- item.enter(**params)
- self.items.append(item)
-
- def display(self):
- print 'This Order consists of the following items'
- print
- print 'QTY\tNAME\tTYPE\nAMI\t\tGroups\t\t\tKeyPair'
- for item in self.items:
- print '%s\t%s\t%s\t%s\t%s\t%s' % (item.quantity, item.name, item.instance_type,
- item.ami.id, item.groups, item.key.name)
-
- def place(self, block=True):
- if get_domain() == None:
- print 'SDB Persistence Domain not set'
- domain_name = self.get_string('Specify SDB Domain')
- set_domain(domain_name)
- s = ServerSet()
- for item in self.items:
- r = item.ami.run(min_count=1, max_count=item.quantity,
- key_name=item.key.name, user_data=item.get_userdata_string(),
- security_groups=item.groups, instance_type=item.instance_type,
- placement=item.zone.name)
- if block:
- states = [i.state for i in r.instances]
- if states.count('running') != len(states):
- print states
- time.sleep(15)
- states = [i.update() for i in r.instances]
- for i in r.instances:
- server = Server()
- server.name = item.name
- server.instance_id = i.id
- server.reservation = r
- server.save()
- s.append(server)
- if len(s) == 1:
- return s[0]
- else:
- return s
-
-
-
View
394 boto/mashups/server.py
@@ -1,394 +0,0 @@
-# Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-High-level abstraction of an EC2 server
-"""
-import boto
-from boto.mashups.iobject import IObject
-from boto.pyami.config import Config, BotoConfigPath
-from boto.mashups.interactive import interactive_shell
-from boto.sdb.db.model import Model
-from boto.sdb.db.property import StringProperty
-import os
-import StringIO
-
-
-class ServerSet(list):
-
- def __getattr__(self, name):
- results = []
- is_callable = False
- for server in self:
- try:
- val = getattr(server, name)
- if callable(val):
- is_callable = True
- results.append(val)
- except:
- results.append(None)
- if is_callable:
- self.map_list = results
- return self.map
- return results
-
- def map(self, *args):
- results = []
- for fn in self.map_list:
- results.append(fn(*args))
- return results
-
-class Server(Model):
-
- @property
- def ec2(self):
- if self._ec2 is None:
- self._ec2 = boto.connect_ec2()
- return self._ec2
-
- @classmethod
- def Inventory(cls):
- """
- Returns a list of Server instances, one for each Server object
- persisted in the db
- """
- l = ServerSet()
- rs = cls.find()
- for server in rs:
- l.append(server)
- return l
-
- @classmethod
- def Register(cls, name, instance_id, description=''):
- s = cls()
- s.name = name
- s.instance_id = instance_id
- s.description = description
- s.save()
- return s
-
- def __init__(self, id=None, **kw):
- Model.__init__(self, id, **kw)
- self._reservation = None
- self._instance = None
- self._ssh_client = None
- self._pkey = None
- self._config = None
- self._ec2 = None
-
- name = StringProperty(unique=True, verbose_name="Name")
- instance_id = StringProperty(verbose_name="Instance ID")
- config_uri = StringProperty()
- ami_id = StringProperty(verbose_name="AMI ID")
- zone = StringProperty(verbose_name="Availability Zone")
- security_group = StringProperty(verbose_name="Security Group", default="default")
- key_name = StringProperty(verbose_name="Key Name")
- elastic_ip = StringProperty(verbose_name="Elastic IP")
- instance_type = StringProperty(verbose_name="Instance Type")
- description = StringProperty(verbose_name="Description")
- log = StringProperty()
-
- def setReadOnly(self,