Пример #1
0
def copy_aws_credentials(src_fname, dst_fname, region):
    """
    Opens a Boto file, changes the region and saves it to a new file, changing
    the ec2 region.
    """
    log("copy_aws_credentials from src[%s] to [%s] in region [%s]" % (
                                                                src_fname,
                                                                dst_fname,
                                                                region))

    ec2_region_endpoint = {"us-east-1": "ec2.us-east-1.amazonaws.com",
            "us-west-2": "ec2.us-west-2.amazonaws.com",
            "us-west-1": "ec2.us-west-1.amazonaws.com",
            "eu-west-1": "ec2.eu-west-1.amazonaws.com",
            "ap-southeast-1": "ec2.ap-southeast-1.amazonaws.com",
            "ap-southeast-2": "ec2.ap-southeast-2.amazonaws.com",
            "ap-northeast-1": "ec2.ap-northeast-1.amazonaws.com",
            "sa-east-1": "ec2.sa-east-1.amazonaws.com"}[region]
    creds = BotoConfig(src_fname)

    # check for AZ override in the CloudSim section
    az = creds.get('CloudSim', region)
    if az in ['any', None]:
        az = region  # use region without a specific AZ
    print(src_fname, dst_fname, region)
    creds.set('Boto', 'ec2_region_name', az)
    log("copy_aws_credentials: using Availability Zone: %s" % az)
    creds.set('Boto', 'ec2_region_endpoint', ec2_region_endpoint)
    with open(dst_fname, 'w') as f:
        creds.write(f)
Пример #2
0
 def create(cls, config_file=None, logical_volume=None, cfg=None, **params):
     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 = StringIO.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...'
         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
Пример #3
0
 def create(cls, config_file=None, logical_volume = None, cfg = None, **params):
     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 = StringIO.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...'
         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
Пример #4
0
    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 = StringIO.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 is not 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
Пример #5
0
    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 = 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 is not 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
Пример #6
0
class Server(Model):

    ec2 = boto.connect_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

    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, value):
        raise AttributeError

    def getInstance(self):
        if not self._instance:
            if self.instance_id:
                try:
                    rs = self.ec2.get_all_instances([self.instance_id])
                except:
                    return None
                if len(rs) > 0:
                    self._reservation = rs[0]
                    self._instance = self._reservation.instances[0]
        return self._instance

    instance = property(getInstance, setReadOnly, None, 'The Instance for the server')
    
    def getAMI(self):
        if self.instance:
            return self.instance.image_id

    ami = property(getAMI, setReadOnly, None, 'The AMI for the server')
    
    def getStatus(self):
        if self.instance:
            self.instance.update()
            return self.instance.state

    status = property(getStatus, setReadOnly, None,
                      'The status of the server')
    
    def getHostname(self):
        if self.instance:
            return self.instance.public_dns_name

    hostname = property(getHostname, setReadOnly, None,
                        'The public DNS name of the server')

    def getPrivateHostname(self):
        if self.instance:
            return self.instance.private_dns_name

    private_hostname = property(getPrivateHostname, setReadOnly, None,
                                'The private DNS name of the server')

    def getLaunchTime(self):
        if self.instance:
            return self.instance.launch_time

    launch_time = property(getLaunchTime, setReadOnly, None,
                           'The time the Server was started')

    def getConsoleOutput(self):
        if self.instance:
            return self.instance.get_console_output()

    console_output = property(getConsoleOutput, setReadOnly, None,
                              'Retrieve the console output for server')

    def getGroups(self):
        if self._reservation:
            return self._reservation.groups
        else:
            return None

    groups = property(getGroups, setReadOnly, None,
                      'The Security Groups controlling access to this server')

    def getConfig(self):
        if not self._config:
            remote_file = BotoConfigPath
            local_file = '%s.ini' % self.instance.id
            self.get_file(remote_file, local_file)
            self._config = Config(local_file)
        return self._config

    def setConfig(self, config):
        local_file = '%s.ini' % self.instance.id
        fp = open(local_file)
        config.write(fp)
        fp.close()
        self.put_file(local_file, BotoConfigPath)
        self._config = config

    config = property(getConfig, setConfig, None,
                      'The instance data for this server')

    def set_config(self, config):
        """
        Set SDB based config
        """
        self._config = config
        self._config.dump_to_sdb("botoConfigs", self.id)

    def load_config(self):
        self._config = Config(do_load=False)
        self._config.load_from_sdb("botoConfigs", self.id)

    def stop(self):
        if self.instance:
            self.instance.stop()

    def start(self):
        self.stop()
        ec2 = boto.connect_ec2()
        ami = ec2.get_all_images(image_ids = [str(self.ami_id)])[0]
        groups = ec2.get_all_security_groups(groupnames=[str(self.security_group)])
        if not self._config:
            self.load_config()
        if not self._config.has_section("Credentials"):
            self._config.add_section("Credentials")
            self._config.set("Credentials", "aws_access_key_id", ec2.aws_access_key_id)
            self._config.set("Credentials", "aws_secret_access_key", ec2.aws_secret_access_key)

        if not self._config.has_section("Pyami"):
            self._config.add_section("Pyami")

        if self._manager.domain:
            self._config.set('Pyami', 'server_sdb_domain', self._manager.domain.name)
            self._config.set("Pyami", 'server_sdb_name', self.name)

        cfg = StringIO.StringIO()
        self._config.write(cfg)
        cfg = cfg.getvalue()
        r = ami.run(min_count=1,
                    max_count=1,
                    key_name=self.key_name,
                    security_groups = groups,
                    instance_type = self.instance_type,
                    placement = self.zone,
                    user_data = cfg)
        i = r.instances[0]
        self.instance_id = i.id
        self.put()
        if self.elastic_ip:
            ec2.associate_address(self.instance_id, self.elastic_ip)

    def reboot(self):
        if self.instance:
            self.instance.reboot()

    def get_ssh_client(self, key_file=None, host_key_file='~/.ssh/known_hosts',
                       uname='root'):
        import paramiko
        if not self.instance:
            print 'No instance yet!'
            return
        if not self._ssh_client:
            if not key_file:
                iobject = IObject()
                key_file = iobject.get_filename('Path to OpenSSH Key file')
            self._pkey = paramiko.RSAKey.from_private_key_file(key_file)
            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._ssh_client.connect(self.instance.public_dns_name,
                                     username=uname, pkey=self._pkey)
        return self._ssh_client

    def get_file(self, remotepath, localpath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        sftp_client.get(remotepath, localpath)

    def put_file(self, localpath, remotepath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        sftp_client.put(localpath, remotepath)

    def listdir(self, remotepath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        return sftp_client.listdir(remotepath)

    def shell(self, key_file=None):
        ssh_client = self.get_ssh_client(key_file)
        channel = ssh_client.invoke_shell()
        interactive_shell(channel)

    def bundle_image(self, prefix, key_file, cert_file, size):
        print 'bundling image...'
        print '\tcopying cert and pk over to /mnt directory on server'
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        path, name = os.path.split(key_file)
        remote_key_file = '/mnt/%s' % name
        self.put_file(key_file, remote_key_file)
        path, name = os.path.split(cert_file)
        remote_cert_file = '/mnt/%s' % name
        self.put_file(cert_file, remote_cert_file)
        print '\tdeleting %s' % BotoConfigPath
        # delete the metadata.ini file if it exists
        try:
            sftp_client.remove(BotoConfigPath)
        except:
            pass
        command = 'ec2-bundle-vol '
        command += '-c %s -k %s ' % (remote_cert_file, remote_key_file)
        command += '-u %s ' % self._reservation.owner_id
        command += '-p %s ' % prefix
        command += '-s %d ' % size
        command += '-d /mnt '
        if self.instance.instance_type == 'm1.small' or self.instance_type == 'c1.medium':
            command += '-r i386'
        else:
            command += '-r x86_64'
        print '\t%s' % command
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print '\t%s' % response
        print '\t%s' % t[2].read()
        print '...complete!'

    def upload_bundle(self, bucket, prefix):
        print 'uploading bundle...'
        command = 'ec2-upload-bundle '
        command += '-m /mnt/%s.manifest.xml ' % prefix
        command += '-b %s ' % bucket
        command += '-a %s ' % self.ec2.aws_access_key_id
        command += '-s %s ' % self.ec2.aws_secret_access_key
        print '\t%s' % command
        ssh_client = self.get_ssh_client()
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print '\t%s' % response
        print '\t%s' % t[2].read()
        print '...complete!'

    def create_image(self, bucket=None, prefix=None, key_file=None, cert_file=None, size=None):
        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')
        self.bundle_image(prefix, key_file, cert_file, size)
        self.upload_bundle(bucket, prefix)
        print 'registering image...'
        self.image_id = self.ec2.register_image('%s/%s.manifest.xml' % (bucket, prefix))
        return self.image_id

    def attach_volume(self, volume, device="/dev/sdp"):
        """
        Attach an EBS volume to this server

        :param volume: EBS Volume to attach
        :type volume: boto.ec2.volume.Volume

        :param device: Device to attach to (default to /dev/sdp)
        :type device: string
        """
        if hasattr(volume, "id"):
            volume_id = volume.id
        else:
            volume_id = volume
        return self.ec2.attach_volume(volume_id=volume_id, instance_id=self.instance_id, device=device)

    def detach_volume(self, volume):
        """
        Detach an EBS volume from this server

        :param volume: EBS Volume to detach
        :type volume: boto.ec2.volume.Volume
        """
        if hasattr(volume, "id"):
            volume_id = volume.id
        else:
            volume_id = volume
        return self.ec2.detach_volume(volume_id=volume_id, instance_id=self.instance_id)

    def install_package(self, package_name):
        print 'installing %s...' % package_name
        command = 'yum -y install %s' % package_name
        print '\t%s' % command
        ssh_client = self.get_ssh_client()
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print '\t%s' % response
        print '\t%s' % t[2].read()
        print '...complete!'
Пример #7
0
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):
        super(Server, self).__init__(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, value):
        raise AttributeError

    def getInstance(self):
        if not self._instance:
            if self.instance_id:
                try:
                    rs = self.ec2.get_all_reservations([self.instance_id])
                except:
                    return None
                if len(rs) > 0:
                    self._reservation = rs[0]
                    self._instance = self._reservation.instances[0]
        return self._instance

    instance = property(getInstance, setReadOnly, None,
                        'The Instance for the server')

    def getAMI(self):
        if self.instance:
            return self.instance.image_id

    ami = property(getAMI, setReadOnly, None, 'The AMI for the server')

    def getStatus(self):
        if self.instance:
            self.instance.update()
            return self.instance.state

    status = property(getStatus, setReadOnly, None, 'The status of the server')

    def getHostname(self):
        if self.instance:
            return self.instance.public_dns_name

    hostname = property(getHostname, setReadOnly, None,
                        'The public DNS name of the server')

    def getPrivateHostname(self):
        if self.instance:
            return self.instance.private_dns_name

    private_hostname = property(getPrivateHostname, setReadOnly, None,
                                'The private DNS name of the server')

    def getLaunchTime(self):
        if self.instance:
            return self.instance.launch_time

    launch_time = property(getLaunchTime, setReadOnly, None,
                           'The time the Server was started')

    def getConsoleOutput(self):
        if self.instance:
            return self.instance.get_console_output()

    console_output = property(getConsoleOutput, setReadOnly, None,
                              'Retrieve the console output for server')

    def getGroups(self):
        if self._reservation:
            return self._reservation.groups
        else:
            return None

    groups = property(getGroups, setReadOnly, None,
                      'The Security Groups controlling access to this server')

    def getConfig(self):
        if not self._config:
            remote_file = BotoConfigPath
            local_file = '%s.ini' % self.instance.id
            self.get_file(remote_file, local_file)
            self._config = Config(local_file)
        return self._config

    def setConfig(self, config):
        local_file = '%s.ini' % self.instance.id
        fp = open(local_file)
        config.write(fp)
        fp.close()
        self.put_file(local_file, BotoConfigPath)
        self._config = config

    config = property(getConfig, setConfig, None,
                      'The instance data for this server')

    def set_config(self, config):
        """
        Set SDB based config
        """
        self._config = config
        self._config.dump_to_sdb("botoConfigs", self.id)

    def load_config(self):
        self._config = Config(do_load=False)
        self._config.load_from_sdb("botoConfigs", self.id)

    def stop(self):
        if self.instance:
            self.instance.stop()

    def start(self):
        self.stop()
        ec2 = boto.connect_ec2()
        ami = ec2.get_all_images(image_ids=[str(self.ami_id)])[0]
        groups = ec2.get_all_security_groups(
            groupnames=[str(self.security_group)])
        if not self._config:
            self.load_config()
        if not self._config.has_section("Credentials"):
            self._config.add_section("Credentials")
            self._config.set("Credentials", "aws_access_key_id",
                             ec2.aws_access_key_id)
            self._config.set("Credentials", "aws_secret_access_key",
                             ec2.aws_secret_access_key)

        if not self._config.has_section("Pyami"):
            self._config.add_section("Pyami")

        if self._manager.domain:
            self._config.set('Pyami', 'server_sdb_domain',
                             self._manager.domain.name)
            self._config.set("Pyami", 'server_sdb_name', self.name)

        cfg = StringIO()
        self._config.write(cfg)
        cfg = cfg.getvalue()
        r = ami.run(min_count=1,
                    max_count=1,
                    key_name=self.key_name,
                    security_groups=groups,
                    instance_type=self.instance_type,
                    placement=self.zone,
                    user_data=cfg)
        i = r.instances[0]
        self.instance_id = i.id
        self.put()
        if self.elastic_ip:
            ec2.associate_address(self.instance_id, self.elastic_ip)

    def reboot(self):
        if self.instance:
            self.instance.reboot()

    def get_ssh_client(self,
                       key_file=None,
                       host_key_file='~/.ssh/known_hosts',
                       uname='root'):
        import paramiko
        if not self.instance:
            print('No instance yet!')
            return
        if not self._ssh_client:
            if not key_file:
                iobject = IObject()
                key_file = iobject.get_filename('Path to OpenSSH Key file')
            self._pkey = paramiko.RSAKey.from_private_key_file(key_file)
            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._ssh_client.connect(self.instance.public_dns_name,
                                     username=uname,
                                     pkey=self._pkey)
        return self._ssh_client

    def get_file(self, remotepath, localpath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        sftp_client.get(remotepath, localpath)

    def put_file(self, localpath, remotepath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        sftp_client.put(localpath, remotepath)

    def listdir(self, remotepath):
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        return sftp_client.listdir(remotepath)

    def shell(self, key_file=None):
        ssh_client = self.get_ssh_client(key_file)
        channel = ssh_client.invoke_shell()
        interactive_shell(channel)

    def bundle_image(self, prefix, key_file, cert_file, size):
        print('bundling image...')
        print('\tcopying cert and pk over to /mnt directory on server')
        ssh_client = self.get_ssh_client()
        sftp_client = ssh_client.open_sftp()
        path, name = os.path.split(key_file)
        remote_key_file = '/mnt/%s' % name
        self.put_file(key_file, remote_key_file)
        path, name = os.path.split(cert_file)
        remote_cert_file = '/mnt/%s' % name
        self.put_file(cert_file, remote_cert_file)
        print('\tdeleting %s' % BotoConfigPath)
        # delete the metadata.ini file if it exists
        try:
            sftp_client.remove(BotoConfigPath)
        except:
            pass
        command = 'sudo ec2-bundle-vol '
        command += '-c %s -k %s ' % (remote_cert_file, remote_key_file)
        command += '-u %s ' % self._reservation.owner_id
        command += '-p %s ' % prefix
        command += '-s %d ' % size
        command += '-d /mnt '
        if self.instance.instance_type == 'm1.small' or self.instance_type == 'c1.medium':
            command += '-r i386'
        else:
            command += '-r x86_64'
        print('\t%s' % command)
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print('\t%s' % response)
        print('\t%s' % t[2].read())
        print('...complete!')

    def upload_bundle(self, bucket, prefix):
        print('uploading bundle...')
        command = 'ec2-upload-bundle '
        command += '-m /mnt/%s.manifest.xml ' % prefix
        command += '-b %s ' % bucket
        command += '-a %s ' % self.ec2.aws_access_key_id
        command += '-s %s ' % self.ec2.aws_secret_access_key
        print('\t%s' % command)
        ssh_client = self.get_ssh_client()
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print('\t%s' % response)
        print('\t%s' % t[2].read())
        print('...complete!')

    def create_image(self,
                     bucket=None,
                     prefix=None,
                     key_file=None,
                     cert_file=None,
                     size=None):
        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')
        self.bundle_image(prefix, key_file, cert_file, size)
        self.upload_bundle(bucket, prefix)
        print('registering image...')
        self.image_id = self.ec2.register_image('%s/%s.manifest.xml' %
                                                (bucket, prefix))
        return self.image_id

    def attach_volume(self, volume, device="/dev/sdp"):
        """
        Attach an EBS volume to this server

        :param volume: EBS Volume to attach
        :type volume: boto.ec2.volume.Volume

        :param device: Device to attach to (default to /dev/sdp)
        :type device: string
        """
        if hasattr(volume, "id"):
            volume_id = volume.id
        else:
            volume_id = volume
        return self.ec2.attach_volume(volume_id=volume_id,
                                      instance_id=self.instance_id,
                                      device=device)

    def detach_volume(self, volume):
        """
        Detach an EBS volume from this server

        :param volume: EBS Volume to detach
        :type volume: boto.ec2.volume.Volume
        """
        if hasattr(volume, "id"):
            volume_id = volume.id
        else:
            volume_id = volume
        return self.ec2.detach_volume(volume_id=volume_id,
                                      instance_id=self.instance_id)

    def install_package(self, package_name):
        print('installing %s...' % package_name)
        command = 'yum -y install %s' % package_name
        print('\t%s' % command)
        ssh_client = self.get_ssh_client()
        t = ssh_client.exec_command(command)
        response = t[1].read()
        print('\t%s' % response)
        print('\t%s' % t[2].read())
        print('...complete!')
Пример #8
0
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 = io.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()
Пример #9
0
class Item(IObject):
    
    def __init__(self, ec2_conn):
        self.name = None
        self.instance_type = None
        self.quantity = 0
        self.zone = None
        self.ami = None
        self.groups = []
        self.key = None
        self.ec2 = ec2_conn
        self.config = None

    def set_userdata(self, key, value):
        self.userdata[key] = value

    def get_userdata(self, key):
        return self.userdata[key]

    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.name)
            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.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()