Exemple #1
0
    def handle(self, *args, **options):
        opsworks = OpsWorksConnection()
        stack_resp = opsworks.describe_stacks()
        stack_id = None
        stack_name = None

        for stack in stack_resp['Stacks']:
            if stack['Name'].startswith('web') and stack['Name'].endswith(
                    options['environment']):
                stack_id = stack['StackId']
                stack_name = stack['Name']
                break
        if not stack_id:
            raise CommandError('Stack does not exist.' %
                               options['environment'])

        # get application
        app_resp = opsworks.describe_apps(stack_id=stack_id)
        app_id = app_resp['Apps'][0]['AppId']
        app_name = app_resp['Apps'][0]['Name']

        # get layer
        for layers in opsworks.describe_layers(stack_id=stack_id)['Layers']:
            if layers['Name'] == 'bots':

                # deploy to the instances of particular layer
                for instance in opsworks.describe_instances(
                        layer_id=layers['LayerId'])['Instances']:
                    custom_json = json.dumps(get_json())
                    comment = "Deploying %s from %s@%s at %s to %s on %s" % (
                        app_name, getpass.getuser(), socket.gethostname(),
                        datetime.now().isoformat(' '), instance['Hostname'],
                        stack_name)

                    deployment = opsworks.create_deployment(
                        stack_id, {'Name': 'deploy'},
                        app_id=app_id,
                        instance_ids=[instance['InstanceId']],
                        custom_json=custom_json,
                        comment=comment)

                    print "https://console.aws.amazon.com/opsworks/home?#/stack/%s/deployments/%s" % (
                        stack_id, deployment['DeploymentId'])
    def run(self, *args, **options):
        opsworks = OpsWorksConnection()
        stack_resp = opsworks.describe_stacks()
        stack_id = None
        stack_name = None

        # get web production stack
        for stack in stack_resp['Stacks']:
            if stack['Name'].startswith('web') and stack['Name'].endswith(self.environment):
                stack_id = stack['StackId']
                stack_name = stack['Name']
                break
        if not stack_id:
            raise Exception('Stack does not exist.' % options['environment'])

        # get application
        app_resp = opsworks.describe_apps(stack_id=stack_id)
        app_id = app_resp['Apps'][0]['AppId']
        app_name = app_resp['Apps'][0]['Name']

        # get layer
        for layers in opsworks.describe_layers(stack_id=stack_id)['Layers']:
            if layers['Name'] == 'bots':

                # deploy to the instances of particular layer
                for instance in opsworks.describe_instances(layer_id=layers['LayerId'])['Instances']:
                    custom_json = json.dumps(get_json())
                    comment = "Deploying %s from %s@%s at %s to %s on %s" % (
                        app_name,
                        getpass.getuser(),
                        socket.gethostname(),
                        datetime.now().isoformat(' '),
                        instance['Hostname'],
                        stack_name)

                    deployment = opsworks.create_deployment(stack_id, {'Name': 'deploy'}, app_id=app_id,
                        instance_ids=[instance['InstanceId']], custom_json=custom_json, comment=comment)

                    print "https://console.aws.amazon.com/opsworks/home?#/stack/%s/deployments/%s" % (stack_id, deployment['DeploymentId'])
Exemple #3
0
class OpsWorksInstanceManager:

    def __init__(self, aws_access_key_id=None,
                 aws_secret_access_key=None,
                 layer_id=None,
                 offline=False):
        self.connection = OpsWorksConnection(
            aws_access_key_id=aws_access_key_id,
            aws_secret_access_key=aws_secret_access_key)
        self.layer_id = layer_id
        self.show_offline = offline

        self.instances = []

    def get_instance(self, instance_index):
        return self.instances[instance_index]

    def list_instances(self):
        instances = self.connection.describe_instances(
            layer_id=self.layer_id)['Instances']

        counter = 0
        for instance in instances:
            if self.show_offline or instance['Status'] == 'online':
                self.instances.append(instance)
                counter += 1

        self.instances = sorted(self.instances, key=itemgetter(u'Hostname'))

        return self.instances

    def print_instances(self):
        instances = self.list_instances()

        for counter, instance in enumerate(instances):
            print "%d) %s" % (counter + 1, instance[u'Hostname'])
def main(args):
  global ops

  if len(args) < 2:
    usage()
    return

  ops = OpsWorksConnection()
  stack_name = args[0]
  stack_id = select_stack_id(stack_name)

  app = AttrDict()
  app_list = []
  for arg in args[1:]:
    if "=" not in arg:
      if app:
        app_list.append(app)
      app = AttrDict(name=arg, params={})
    else:
      k, v = arg.split("=", 1)
      app.params[k] = v
  if app.name:
    app_list.append(app)

  all_instances = []
  must_start_instances = []
  must_stop_instances = []
  for app in app_list:
    app.info = select_app(stack_id, app.name)
    app.layers = [AttrDict(l) for l in find_layers_for_app(stack_id, app.info["Shortname"])]
    if not app.layers:
      raise InvalidNumberOfLayers("no layers available for app '%(Name)s' (%(Shortname)s)" % app.info)
    app.json = {
      "deploy": {
        app.info["Shortname"]: {
          }
        }
      }
    root = app.json["deploy"][app.info["Shortname"]]
    for k, v in app.params.iteritems():
      path = k.split(".")
      attr = path[-1]
      path = path[:-1]
      descend_dict(root, path)[attr] = v

    if len(app.layers) > 1:
      app.elb = select_elb_for_layers(stack_id, app.layers)
      active_layer = [l["LayerId"] for l in app.layers].index(app.elb["LayerId"])
      app.old_layer = app.layers[active_layer]
      app.new_layer = app.layers[1 - active_layer]
    else:
      app.new_layer = app.layers[0]

    for l in app.layers:
      l.instances = find_layer_instances(l["LayerId"])
      all_instances.extend(l.instances)
      must_start_instances.extend(i for i in l.instances if l == app.new_layer and i["Status"] == "stopped" and "AutoScalingType" not in i)
      must_stop_instances.extend(i for i in l.instances if l != app.new_layer and i["Status"] != "stopped" and "AutoScalingType" not in i)

    if not app.new_layer.instances:
      raise NoInstanceAvailable("no instances available for layer '%(Name)s'" % app.new_layer)

  # INFO
  for app in app_list:
    print "Application '%(Name)s' to be deployed on layers '%(LayerName)s' with instances" % dict(app.info, LayerName=app.new_layer["Name"])
    for i in app.new_layer.instances:
      print "\t%(Hostname)s - %(Architecture)s - %(InstanceType)s - %(Status)s" % i
    print "with custom JSON: %s" % pformat(app.json)
  # ^ INFO

  pending_instance_ids = [i["instanceId"] for i in must_start_instances]
  for id in pending_instance_ids:
    ops.start_instance(id)

  while pending_instance_ids:
    ins = [i for i in ops.describe_instances(instance_ids=pending_instance_ids)["Instances"] if i["Status"] != "online"]
    pending_instance_ids = [i["InstanceId"] for i in ins]
    if pending_instance_ids:
      print "Waiting 30 sec for instances to start: %s" % ", ".join(i["Hostname"] for i in ins)
      time.sleep(30)

  for app in app_list:
    print "Deploying '%(Name)s' (%(Shortname)s)" % app.info
    instance_ids = [i["InstanceId"] for i in app.new_layer.instances]
    prev_dep = find_last_deployment(app.info["AppId"], instance_ids)
    if prev_dep and "CustomJson" in prev_dep:
      print "\tprevious deployment (type '%s') done by %s on %s" % (
        prev_dep["Command"]["Name"], prev_dep["IamUserArn"].split(":user/")[-1], prev_dep["CreatedAt"])
    dep_id = deploy_app(stack_id, app.info["AppId"], instance_ids, app.json)

    # wait for deployment to be complete
    while True:
      dep = ops.describe_deployments(deployment_ids=[dep_id])["Deployments"][0]
      if dep["Status"] != "running":
        break
      print "\twaiting 60 sec for completion of deployment..."
      time.sleep(30)

    print "\tcompleted with status: %s" % dep["Status"]

    if len(app.layers) > 1:
      print "Attaching ELB '%(DnsName)s' to layer '%(Name)s'" % dict(app.elb, Name=app.new_layer["Name"])
      attach_elb_to_layer(app.elb, app.old_layer, app.new_layer)

  pending_instance_ids = [i["InstanceId"] for i in must_stop_instances]
  for id in pending_instance_ids:
    ops.stop_instance(id)

  while pending_instance_ids:
    ins = [i for i in ops.describe_instances(instance_ids=pending_instance_ids)["Instances"] if i["Status"] != "stopped"]
    pending_instance_ids = [i["InstanceId"] for i in ins]
    if pending_instance_ids:
      print "Waiting 30 sec for instances to stop: %s" % ", ".join(i["Hostname"] for i in ins)
      time.sleep(30)