コード例 #1
0
    def get_field(self, field):
        # Ensure field name is valid
        if field not in self.FIELDS:
            return None

        with no_print():
            # Find, parse and validate configs
            config = get_config(self._args)
            portal_spec, portal_name = get_portal_spec(self._args)

            if field == 'name':
                return portal_name
            if field == 'user':
                return portal_spec['spot_instance']['remote_user']
            if field == 'key':
                return portal_spec['spot_instance']['identity_file']

            # Create AWS client
            aws = AwsClient(config['aws_access_key'], config['aws_secret_key'],
                            config['aws_region'])

            # Get current user
            aws_user = aws.get_user_identity()

            # Get spot instance
            instance_info = aws.find_spot_instance(portal_name,
                                                   aws_user['Arn'])

            if field == 'status':
                return 'open' if instance_info is not None else 'close'

            # If portal is closed, we cannot provide any other information
            if instance_info is None:
                return None

            if field == 'id':
                return instance_info['InstanceId']
            if field == 'type':
                return instance_info['InstanceType']
            if field == 'host':
                return instance_info['PublicDnsName']
            if field == 'ip':
                return instance_info['PublicIpAddress']
            if field == 'remote':
                return '{}@{}'.format(
                    portal_spec['spot_instance']['remote_user'],
                    instance_info['PublicDnsName'])

        return None
コード例 #2
0
ファイル: ssh.py プロジェクト: serithemage/portal-gun
    def run(self):
        # Find, parse and validate configs
        with no_print():
            config = get_config(self._args)
            portal_spec, portal_name = get_portal_spec(self._args)

        # Create AWS client
        aws = AwsClient(config['aws_access_key'], config['aws_secret_key'],
                        config['aws_region'])

        # Get current user
        aws_user = aws.get_user_identity()

        # Get spot instance
        instance_info = aws.find_spot_instance(portal_name, aws_user['Arn'])

        if instance_info is None:
            raise CommandError(
                'Portal `{}` does not seem to be opened'.format(portal_name))

        # Get values for ssh
        key_file = portal_spec['spot_instance']['identity_file']
        user = portal_spec['spot_instance']['remote_user']
        host = instance_info['PublicDnsName']

        print('Connecting to the remote machine...')
        print('\tssh -i "{}" {}@{}'.format(key_file, user, host).expandtabs(4))

        # If requested, configure a preamble (a set of commands to be run automatically after connection)
        preamble = []
        if self._args.tmux is not None:
            preamble = [
                '-t',
                '""tmux attach-session -t {sess} || tmux new-session -s {sess}""'
                .format(sess=self._args.tmux)
            ]
            print('Upon connection will open tmux session `{}`.'.format(
                self._args.tmux))

        print('')

        # Ssh to remote host (effectively replace current process by ssh)
        os.execvp('ssh', ['ssh', '-i', key_file, '{}@{}'.format(user, host)] +
                  preamble)
コード例 #3
0
	def run(self):
		# Find, parse and validate configs
		with print_scope('Checking configuration:', 'Done.\n'):
			config = get_config(self._args)
			portal_spec, portal_name = get_portal_spec(self._args)

		# Create AWS client
		aws = AwsClient(config['aws_access_key'], config['aws_secret_key'], config['aws_region'])

		with print_scope('Retrieving data from AWS:', 'Done.\n'):
			# Get current user
			with step('Get user identity'):
				user = aws.get_user_identity()

			# Get spot instance
			with step('Get spot instance', error_message='Portal `{}` does not seem to be opened'.format(portal_name),
					  catch=[RuntimeError]):
				spot_instance = common.get_spot_instance(aws, portal_name, user['Arn'])

			spot_fleet_request_id = \
				filter(lambda tag: tag['Key'] == 'aws:ec2spot:fleet-request-id', spot_instance['Tags'])[0]['Value']

			# Get spot instance
			with step('Get spot request', error_message='Portal `{}` does not seem to be opened'.format(portal_name),
					  catch=[RuntimeError]):
				spot_fleet_request = common.get_spot_fleet_request(aws, spot_fleet_request_id)

		# TODO: print fleet and instance statistics

		# Cancel spot instance request
		aws.cancel_spot_fleet_request(spot_fleet_request_id)

		# Clean up volumes' tags
		volume_ids = [volume['Ebs']['VolumeId']
					  for volume in spot_instance['BlockDeviceMappings']
					  if not volume['Ebs']['DeleteOnTermination']]
		aws.remove_tags(volume_ids, 'mount-point')

		print('Portal `{}` has been closed.'.format(portal_name))
コード例 #4
0
    def run(self):
        # Find, parse and validate configs
        with print_scope('Checking configuration:', 'Done.\n'):
            config = get_config(self._args)
            portal_spec, portal_name = get_portal_spec(self._args)

            # Ensure there is at least one channel spec
            with step('Check specifications for channels',
                      error_message=
                      'Portal specification does not contain any channel'):
                channels = portal_spec['channels']
                if len(channels) == 0:
                    raise Exception()

        # Create AWS client
        aws = AwsClient(config['aws_access_key'], config['aws_secret_key'],
                        config['aws_region'])

        with print_scope('Retrieving data from AWS:', 'Done.\n'):
            # Get current user
            with step('Get user identity'):
                user = aws.get_user_identity()

            # Get spot instance
            with step('Get spot instance',
                      error_message='Portal `{}` does not seem to be opened'.
                      format(portal_name),
                      catch=[RuntimeError]):
                spot_instance = common.get_spot_instance(
                    aws, portal_name, user['Arn'])

        host_name = spot_instance['PublicDnsName']

        # Print information about the channels
        with print_scope(
                'Channels defined for portal `{}`:'.format(portal_name), ''):
            for i in range(len(channels)):
                channel = channels[i]
                with print_scope('Channel #{} ({}):'.format(
                        i, channel['direction'].upper())):
                    print('Local:   {}'.format(channel['local_path']))
                    print('Remote:  {}'.format(channel['remote_path']))

        # Specify remote host for ssh
        env.user = portal_spec['spot_instance']['remote_user']
        env.key_filename = [portal_spec['spot_instance']['identity_file']]
        env.hosts = [host_name]

        # Periodically sync files across all channels
        print('Syncing... (press ctrl+C to interrupt)')
        for channel in channels:
            is_upload = channel['direction'] == 'out'
            is_recursive = channel[
                'recursive'] if 'recursive' in channel else False
            delay = 1.0
            if 'delay' in channel:
                delay = channel['delay']
            run_periodically(sync_files, [
                channel['local_path'], channel['remote_path'], is_upload,
                is_recursive
            ], delay)
コード例 #5
0
    def run(self):
        # Find, parse and validate configs
        with print_scope('Checking configuration:', 'Done.\n'):
            config = get_config(self._args)
            portal_spec, portal_name = get_portal_spec(self._args)

        instance_spec = portal_spec['spot_instance']

        # Create AWS client
        aws = AwsClient(config['aws_access_key'], config['aws_secret_key'],
                        config['aws_region'])

        with print_scope('Retrieving data from AWS:', 'Done.\n'):
            # Get current user
            with step('Get user identity'):
                user = aws.get_user_identity()

            # Ensure that instance does not yet exist
            with step('Check already running instances',
                      error_message='Portal `{}` seems to be already opened'.
                      format(portal_name),
                      catch=[RuntimeError]):
                common.check_instance_not_exists(aws, portal_name, user['Arn'])

            # Ensure persistent volumes are available
            with step('Check volumes availability', catch=[RuntimeError]):
                volume_ids = [
                    volume_spec['volume_id']
                    for volume_spec in portal_spec['persistent_volumes']
                ]
                common.check_volumes_availability(aws, volume_ids)

            # If subnet Id is not provided, pick the default subnet of the availability zone
            if 'subnet_id' not in instance_spec or not instance_spec[
                    'subnet_id']:
                with step('Get subnet id', catch=[IndexError, KeyError]):
                    subnets = aws.get_subnets(
                        instance_spec['availability_zone'])
                    instance_spec['subnet_id'] = subnets[0]['SubnetId']

        # Make request for Spot instance
        instance_type = instance_spec['instance_type']
        with print_scope('Requesting a Spot instance of type {}:'.format(
                instance_type)):
            request_config = aws_helpers.single_instance_spot_fleet_request(
                portal_spec, portal_name, user['Arn'])
            response = aws.request_spot_fleet(request_config)
            spot_fleet_request_id = response['SpotFleetRequestId']

            # Wait for spot fleet request to be fulfilled
            print('Waiting for the Spot instance to be created...')
            print(
                '(usually it takes around a minute, but might take much longer)'
            )
            begin_time = datetime.datetime.now()
            next_time = begin_time
            try:
                while True:
                    # Repeat status request every N seconds
                    if datetime.datetime.now() > next_time:
                        spot_fleet_request = aws.get_spot_fleet_request(
                            spot_fleet_request_id)
                        next_time += datetime.timedelta(seconds=5)

                    # Compute time spend in waiting
                    elapsed = datetime.datetime.now() - begin_time

                    # Check request state and activity status
                    request_state = spot_fleet_request['SpotFleetRequestState']
                    if request_state == 'active':
                        spot_request_status = spot_fleet_request[
                            'ActivityStatus']
                        if spot_request_status == 'fulfilled':
                            break
                        else:
                            print(
                                'Elapsed {}s. Spot request is {} and has status `{}`'
                                .format(elapsed.seconds, request_state,
                                        spot_request_status),
                                end='\r')
                    else:
                        print('Elapsed {}s. Spot request is {}'.format(
                            elapsed.seconds, request_state),
                              end='\r')

                    sys.stdout.flush()  # ensure stdout is flushed immediately.
                    time.sleep(0.5)
            except KeyboardInterrupt:
                print('\n')
                print('Interrupting...')

                # Cancel spot instance request
                aws.cancel_spot_fleet_request(spot_fleet_request_id)

                raise CommandError('Spot request has been cancelled.')
        print('\nSpot instance is created in {} seconds.\n'.format(
            (datetime.datetime.now() - begin_time).seconds))

        # Get id of the created instance
        spot_fleet_instances = aws.get_spot_fleet_instances(
            spot_fleet_request_id)
        instance_id = spot_fleet_instances[0]['InstanceId']

        # Get information about the created instance
        instance_info = aws.get_instance(instance_id)

        # Make requests to attach persistent volumes
        with print_scope('Attaching persistent volumes:'):
            for volume_spec in portal_spec['persistent_volumes']:
                response = aws.attach_volume(instance_id,
                                             volume_spec['volume_id'],
                                             volume_spec['device'])

                # Check status code
                if response['State'] not in ['attaching', 'attached']:
                    raise CommandError(
                        'Could not attach persistent volume `{}`'.format(
                            volume_spec['volume_id']))

            # Wait for persistent volumes to be attached
            print('Waiting for the persistent volumes to be attached...')
            begin_time = datetime.datetime.now()
            next_time = begin_time
            while True:
                # Repeat status request every N seconds
                if datetime.datetime.now() > next_time:
                    volumes = aws.get_volumes_by_id(volume_ids)
                    next_time += datetime.timedelta(seconds=1)

                # Compute time spend in waiting
                elapsed = datetime.datetime.now() - begin_time

                if all([
                        volume['Attachments'][0]['State'] == 'attached'
                        for volume in volumes
                ]):
                    break
                else:
                    states = [
                        '{} - `{}`'.format(volume['VolumeId'],
                                           volume['Attachments'][0]['State'])
                        for volume in volumes
                    ]
                    print('Elapsed {}s. States: {}'.format(
                        elapsed.seconds, ', '.join(states)),
                          end='\r')

                sys.stdout.flush()  # ensure stdout is flushed immediately.
                time.sleep(0.5)
        print('\nPersistent volumes are attached in {} seconds.\n'.format(
            (datetime.datetime.now() - begin_time).seconds))

        # Configure ssh connection via fabric
        env.user = instance_spec['remote_user']
        env.key_filename = [instance_spec['identity_file']]
        env.hosts = instance_info['PublicDnsName']
        env.connection_attempts = self._fabric_retry_limit

        with print_scope('Preparing the instance:', 'Instance is ready.\n'):
            # Mount persistent volumes
            for i in range(len(portal_spec['persistent_volumes'])):
                with step('Mount volume #{}'.format(i),
                          error_message='Could not mount volume',
                          catch=[RuntimeError]):
                    volume_spec = portal_spec['persistent_volumes'][i]

                    # Mount volume
                    with hide('running', 'stdout'):
                        execute(self.mount_volume, volume_spec['device'],
                                volume_spec['mount_point'],
                                instance_spec['remote_group'],
                                instance_spec['remote_user'])

                    # Store extra information in volume's tags
                    aws.add_tags(volume_spec['volume_id'],
                                 {'mount-point': volume_spec['mount_point']})

            # TODO: consider importing and executing custom fab tasks instead
            # Install extra python packages, if needed
            if 'extra_python_packages' in instance_spec and len(
                    instance_spec['extra_python_packages']) > 0:
                with step('Install extra python packages',
                          error_message='Could not install python packages',
                          catch=[RuntimeError]):
                    python_packages = instance_spec['extra_python_packages']
                    virtual_env = instance_spec['python_virtual_env']
                    with hide('running', 'stdout'):
                        execute(self.install_python_packages, python_packages,
                                virtual_env)

        # Print summary
        print('Portal `{}` is now opened.'.format(portal_name))
        with print_scope('Summary:', ''):
            with print_scope('Instance:'):
                print('Id:              {}'.format(instance_id))
                print('Type:            {}'.format(
                    instance_info['InstanceType']))
                print('Public IP:       {}'.format(
                    instance_info['PublicIpAddress']))
                print('Public DNS name: {}'.format(
                    instance_info['PublicDnsName']))
            with print_scope('Persistent volumes:'):
                for volume_spec in portal_spec['persistent_volumes']:
                    print('{}: {}'.format(volume_spec['device'],
                                          volume_spec['mount_point']))

        # Print ssh command
        print('Use the following command to connect to the remote machine:')
        print('ssh -i "{}" {}@{}'.format(instance_spec['identity_file'],
                                         instance_spec['remote_user'],
                                         instance_info['PublicDnsName']))
コード例 #6
0
    def show_full_info(self):
        # Find, parse and validate configs
        with print_scope('Checking configuration:', 'Done.\n'):
            config = get_config(self._args)
            portal_spec, portal_name = get_portal_spec(self._args)

        # Create AWS client
        aws = AwsClient(config['aws_access_key'], config['aws_secret_key'],
                        config['aws_region'])

        volumes = []
        with print_scope('Retrieving data from AWS:', 'Done.\n'):
            # Get current user
            with step('Get user identity'):
                aws_user = aws.get_user_identity()

            # Get spot instance
            with step('Get spot instance',
                      error_message='Portal `{}` does not seem to be opened'.
                      format(portal_name),
                      catch=[RuntimeError]):
                instance_info = aws.find_spot_instance(portal_name,
                                                       aws_user['Arn'])

            # Get persistent volumes, if portal is opened
            if instance_info is not None:
                with step('Get volumes'):
                    volume_ids = [
                        volume['Ebs']['VolumeId']
                        for volume in instance_info['BlockDeviceMappings']
                        if not volume['Ebs']['DeleteOnTermination']
                    ]
                    volumes = aws.get_volumes_by_id(volume_ids)

        # Print status
        if instance_info is not None:
            with print_scope('Summary:', ''):
                print('Name:              {}'.format(portal_name))
                print('Status:            open')

            with print_scope('Instance:', ''):
                print('Id:                {}'.format(
                    instance_info['InstanceId']))
                print('Type:              {}'.format(
                    instance_info['InstanceType']))
                print('Public IP:         {}'.format(
                    instance_info['PublicIpAddress']))
                print('Public DNS name:   {}'.format(
                    instance_info['PublicDnsName']))
                print('User:              {}'.format(
                    portal_spec['spot_instance']['remote_user']))

            with print_scope('Persistent volumes:', ''):
                for i in range(len(volumes)):
                    volume = volumes[i]
                    with print_scope('Volume #{}:'.format(i), ''):
                        self.print_volume_info(volume)

            # Print ssh command
            with print_scope(
                    'Use the following command to connect to the remote machine:'
            ):
                print('ssh -i "{}" {}@{}'.format(
                    portal_spec['spot_instance']['identity_file'],
                    portal_spec['spot_instance']['remote_user'],
                    instance_info['PublicDnsName']))
        else:
            with print_scope('Summary:'):
                print('Name:              {}'.format(portal_name))
                print('Status:            close')