Exemple #1
0
    def __init__(self, environment_name, nova_descriptor_file=None):
        self._nova_descriptor_file = nova_descriptor_file or 'nova.yml'
        self._environment_name = environment_name
        self._environment = None
        self._codedeploy_app = None

        self.templates_used = dict()
        yaml.add_constructor("!include", yaml_include)

        with open(os.path.join(spec.__path__[0], 'nova_service_schema.yml'),
                  'r') as schemaYaml:
            schema = yaml.load(schemaYaml)

        v = Validator(schema)
        try:
            with open(self._nova_descriptor_file, 'r') as novaYaml:
                self.service_spec = yaml.safe_load(novaYaml)

            # Validate loaded dictionary
            valid = v.validate(self.service_spec)
            if not valid:
                raise NovaError(
                    "Invalid nova service descriptor file '%s': %s" %
                    (self._nova_descriptor_file, v.errors))
            else:
                self.service = Service.load(self.service_spec)
                self.service_name = self.service.name
                self.service_port = self.service.port
                self.service_healthcheck_url = self.service.healthcheck_url
        except IOError:
            raise NovaError("No nova service descriptor found at '%s'" %
                            self._nova_descriptor_file)
Exemple #2
0
    def __init__(self, stash_key, manager_provider, aws_profile=None, aws_region=None, aws_bucket=None):
        check_latest_version()

        self._aws_manager = manager_provider.aws_manager(aws_profile, aws_region or 'us-east-1')

        if aws_bucket is None:
            deployment_bucket_name = 'novastash_%s' % self._aws_manager.account_alias
        else:
            deployment_bucket_name = aws_bucket

        key = "%s.txt.enc" % stash_key
        existing_stash = self._aws_manager.s3_get(deployment_bucket_name, key)

        if existing_stash is None:
            raise NovaError("No stash '%s' found!" % stash_key)
        else:
            contents = existing_stash['Body'].read()
            metadata = existing_stash['Metadata']
            encryption_key = metadata['encryption-key']
            kms_response = self._aws_manager.kms_decrypt(b64decode(encryption_key), {})

            key = kms_response['Plaintext'][:32]
            hmac_key = kms_response['Plaintext'][32:]
            hmac = HMAC(hmac_key, msg=b64decode(contents), digestmod=SHA256)

            if hmac.hexdigest() != metadata['hmac']:
                raise NovaError("Computed HMAC on '%s' does not match stored HMAC" % stash_key)

            dec_ctr = Counter.new(128)
            decryptor = AES.new(key, AES.MODE_CTR, counter=dec_ctr)
            print(decryptor.decrypt(b64decode(contents)).decode("utf-8"))
Exemple #3
0
    def default(self):
        profile = self.app.pargs.profile
        deploy_args = self.app.pargs.deploy_args
        nova_descriptor_file = self.app.pargs.file
        manager_provider = ManagerProvider()
        deploy = not self.app.pargs.no_deploy
        if len(deploy_args) == 2:
            deployer = DeployStack(deploy_args[0],
                                   deploy_args[1],
                                   profile,
                                   manager_provider,
                                   deploy=deploy,
                                   nova_descriptor_file=nova_descriptor_file)
        elif len(deploy_args) == 3:
            deployer = DeployStack(deploy_args[0],
                                   deploy_args[1],
                                   profile,
                                   manager_provider,
                                   version=deploy_args[2],
                                   deploy=deploy,
                                   nova_descriptor_file=nova_descriptor_file)
        else:
            raise NovaError(INCORRECT_ARGS_USAGE)

        deployer.deploy()
Exemple #4
0
    def __init__(self,
                 environment_name,
                 stack_name,
                 aws_profile,
                 manager_provider,
                 version=None,
                 deploy=True,
                 nova_descriptor_file=None):
        self._environment_name = environment_name
        self._stack_name = stack_name
        self._deploy = deploy
        self._version_manager = manager_provider.version_manager()
        self._docker_manager = manager_provider.docker_manager()
        self._service_manager = NovaServiceLoader(environment_name,
                                                  nova_descriptor_file)
        self._aws_manager = manager_provider.aws_manager(
            aws_profile or self._service_manager.environment.aws_profile,
            self._service_manager.environment.aws_region)
        self._build_id = self._version_manager.current_version(version)
        self._stack = self._service_manager.get_stack(self._stack_name)
        self._code_deploy_app = self._service_manager.code_deploy_app
        if self._stack.deployment_group is None:
            raise NovaError(
                "Environment '%s' stack '%s' does not have 'deployment_group' set!"
                % (self._environment_name, self._stack.name))

        self._nova_deploy_dir = None
        self._custom_scripts = CustomScripts()
Exemple #5
0
 def __cleanup(self):
     try:
         if os.path.exists(self._nova_deploy_dir):
             print(
                 colored("Cleaning up deployment bundle...", color='green'))
             shutil.rmtree(self._nova_deploy_dir)
     except Exception as e:
         raise NovaError(e)
Exemple #6
0
 def get_stack(self, stack_name):
     stack = next((item for item in self.stacks if item.name == stack_name),
                  None)
     if stack is not None:
         return stack
     else:
         raise NovaError("Stack '%s' was not found in the configuration" %
                         stack_name)
Exemple #7
0
    def create(self):
        try:
            self._aws_manager.create_and_upload_stack_template(self._s3_bucket, self._service_manager.service, self._service_manager.environment)

            self._aws_manager.create_stack(
                self._service_manager.service_name,
                self.cloudformation_template
            )

            stack = self._aws_manager.get_stack(self._service_manager.service_name)

            if stack.stack_status == "CREATE_COMPLETE":
                if stack.outputs is not None:
                    for output in stack.outputs:
                        if output.get('OutputKey') == 'CodeDeployApp':
                            code_deploy_app_id = output.get('OutputValue')
                            print(colored("Found code-deploy app: %s" % code_deploy_app_id, color='green'))
                            self._service_manager.service.set_code_deploy_app(self._environment_name, code_deploy_app_id)
                            print(colored("Please update nova.yml environment with 'deployment_application_id' manually.", color='yellow'))
                            break

                        for stack in self._service_manager.environment.stacks:
                            if output.get('OutputKey') == stack.name.title() + 'DeploymentGroup':
                                code_deploy_app_id = output.get('OutputValue')
                                print(colored("Found code-deploy deployment group for stack '%s': %s" % (stack.name, code_deploy_app_id), color='green'))
                                self._service_manager.service.set_code_deploy_app(self._environment_name, code_deploy_app_id)
                                print(colored("Please update nova.yml environment with 'deployment_application_id' manually.", color='yellow'))
                            else:
                                print(colored("Unable to find code-deploy deployment group for stack '%s' in the stack output" % stack.name, 'yellow'))
                                print(colored("Please update nova.yml stack with the 'deployment_group' manually.", color='yellow'))

                    else:
                        print(colored('Unable to find code-deploy application in the stack output', 'yellow'))
                        print(colored("Please update nova.yml environment with 'deployment_application_id'", color='yellow'))
                        print(colored("and your stacks with their respective 'deployment_group' manually.", color='yellow'))
                else:
                    print(colored("Please update nova.yml environment with 'deployment_application_id'", color='yellow'))
                    print(colored("and your stacks with their respective 'deployment_group' manually.", color='yellow'))

            else:
                raise NovaError("Stack creation was un-successful: %s" % stack.stack_status_reason)
        except ClientError as e:
            raise NovaError(str(e))
        except WaiterError as e:
            raise NovaError(str(e))
Exemple #8
0
    def code_deploy_app(self):
        if self.environment.deployment_application_id is None:
            raise NovaError(
                "Environment '%s' does not have 'deployment_application_id' set!"
                % self._environment_name)

        if self._codedeploy_app is None:
            self._codedeploy_app = self.environment.deployment_application_id
        return self._codedeploy_app
Exemple #9
0
 def get_environment(self, environment_name):
     environment = next(
         (item
          for item in self.environments if item.name == environment_name),
         None)
     if environment is not None:
         return environment
     else:
         raise NovaError(
             "Environment '%s' was not found in the configuration" %
             environment_name)
Exemple #10
0
 def update(self):
     cf_template_out = self.app.pargs.output
     include_docker = self.app.pargs.include_docker
     if self.app.pargs.environment:
         profile = self.app.pargs.profile
         UpdateStack(aws_profile=profile,
                     environment_name=self.app.pargs.environment[0],
                     manager_provider=ManagerProvider(),
                     cf_template_out=cf_template_out,
                     include_docker=include_docker).update()
     else:
         raise NovaError(INCORRECT_UPDATE_ARGS_USAGE)
Exemple #11
0
 def create(self):
     cf_template_out = self.app.pargs.output
     nova_descriptor_file = self.app.pargs.file
     include_docker = self.app.pargs.include_docker
     if self.app.pargs.environment:
         profile = self.app.pargs.profile
         CreateStack(aws_profile=profile,
                     environment_name=self.app.pargs.environment[0],
                     manager_provider=ManagerProvider(),
                     cf_template_out=cf_template_out,
                     nova_descriptor_file=nova_descriptor_file,
                     include_docker=include_docker).create()
     else:
         raise NovaError(INCORRECT_CREATE_ARGS_USAGE)
Exemple #12
0
 def __read_extra_resources(self):
     if self.resources:
         try:
             with open(self.resources, 'r') as extra_resources_file:
                 rjson = json.load(extra_resources_file)
                 return [
                     JSONableDict(update_dict=r[1], name=r[0])
                     for r in iter(rjson.items())
                 ]
         except IOError:
             raise NovaError("Environment resources '%s' not found." %
                             self.resources)
     else:
         return None
Exemple #13
0
 def get(self):
     if len(self.app.pargs.stash_args) == 1:
         profile = self.app.pargs.profile
         region = self.app.pargs.region
         bucket = self.app.pargs.bucket
         key = self.app.pargs.stash_args[0]
         manager_provider = ManagerProvider()
         Decrypt(stash_key=key,
                 manager_provider=manager_provider,
                 aws_profile=profile,
                 aws_region=region,
                 aws_bucket=bucket)
     else:
         raise NovaError(INCORRECT_GET_ARGS_USAGE)
Exemple #14
0
    def update(self):
        self._aws_manager.create_and_upload_stack_template(self._s3_bucket, self._service_manager.service,
                                                           self._service_manager.environment)
        changeset_id = "cs%s" % VersionManager().current_version().replace(".", "x")
        cf_stack = self._aws_manager.get_stack(self._service_manager.service_name)
        performed_update = self._aws_manager.update_stack(
            self._service_manager.service_name,
            self.cloudformation_template,
            changeset_id,
            cf_stack
        )

        if performed_update:
            stack = self._aws_manager.get_stack(self._service_manager.service_name)
            if stack.stack_status == "UPDATE_COMPLETE":
                if stack.outputs is not None:
                    for output in stack.outputs:
                        if output.get('OutputKey') == 'CodeDeployApp':
                            code_deploy_app_id = output.get('OutputValue')
                            print("Found code-deploy app: %s" % code_deploy_app_id)
                            self._service_manager.service.set_code_deploy_app(self.environment_name, code_deploy_app_id)
                            print(green("Please update nova.yml environment with 'deployment_application_id' manually."))
                            break

                        for stack in self._service_manager.environment.stacks:
                            if output.get('OutputKey') == stack.name.title() + 'DeploymentGroup':
                                code_deploy_app_id = output.get('OutputValue')
                                print(colored("Found code-deploy deployment group for stack '%s': %s" % (
                                    stack.name, code_deploy_app_id), color='green'))
                                self._service_manager.service.set_code_deploy_app(self.environment_name, code_deploy_app_id)
                                print(green("Please update nova.yml environment with 'deployment_application_id' manually."))
                            else:
                                print(colored(
                                    "Unable to find code-deploy deployment group for stack '%s' in the stack output" % stack.name,
                                    'yellow'))
                                print(colored("Please update nova.yml stack with the 'deployment_group' manually.",
                                              color='yellow'))

                    else:
                        print(colored('Unable to find code-deploy application in the stack output', 'yellow'))
                        print(colored("Please update nova.yml environment with 'deployment_application_id' manually.",
                                      color='yellow'))
                else:
                    print(colored("Please update nova.yml environment with 'deployment_application_id' manually.",
                                  color='yellow'))
                    print(colored("and your stacks with their respective 'deployment_group' manually.", color='yellow'))

            else:
                raise NovaError("Stack update was un-successful: %s - %s" % (stack.stack_status, stack.stack_status_reason))
Exemple #15
0
 def put(self):
     if len(self.app.pargs.stash_args) == 2:
         profile = self.app.pargs.profile
         region = self.app.pargs.region
         bucket = self.app.pargs.bucket
         kms_key_alias = self.app.pargs.key or 'novastash'
         key = self.app.pargs.stash_args[0]
         value = self.app.pargs.stash_args[1]
         manager_provider = ManagerProvider()
         Encrypt(stash_key=key,
                 value=value,
                 manager_provider=manager_provider,
                 aws_profile=profile,
                 aws_region=region,
                 aws_bucket=bucket,
                 kms_key="alias/%s" % kms_key_alias)
     else:
         raise NovaError(INCORRECT_PUT_ARGS_USAGE)
Exemple #16
0
def check_latest_version():
    try:
        current = pkg_resources.require("gilt-nova")[0].version
        pypi = six.moves.xmlrpc_client.ServerProxy(
            'http://pypi.python.org/pypi')
        available = pypi.package_releases('gilt-nova')
        major_available = available[0].split('.')[0]
        major_current = current.split('.')[0]
        if available[0] != current:
            print(
                colored("The latest version of nova is '%s', please upgrade!" %
                        available[0],
                        color='yellow'))

        if major_available != major_current:
            raise NovaError(
                'There has been a breaking change, please upgrade before continuing!'
            )
    except Exception:
        pass
Exemple #17
0
    def __init__(self,
                 stash_key,
                 value,
                 manager_provider,
                 aws_profile=None,
                 aws_region=None,
                 aws_bucket=None,
                 kms_key='alias/novastash'):
        check_latest_version()

        self._aws_manager = manager_provider.aws_manager(
            aws_profile, aws_region or 'us-east-1')

        if aws_bucket is None:
            deployment_bucket_name = 'novastash_%s' % self._aws_manager.account_alias
        else:
            deployment_bucket_name = aws_bucket

        if not self._aws_manager.kms_key_exists(kms_key):
            raise NovaError("Please setup the novastash KMS key.")

        self._aws_manager.create_bucket(
            deployment_bucket_name,
            "Creating novastash bucket '%s'" % deployment_bucket_name)

        # generate a a 64 byte key.
        # Half will be for data encryption, the other half for HMAC
        kms_response = self._aws_manager.kms_generate_data_key(kms_key, {})

        data_key = tobytes(kms_response['Plaintext'][:32])
        hmac_key = tobytes(kms_response['Plaintext'][32:])
        wrapped_key = tobytes(kms_response['CiphertextBlob'])

        enc_ctr = Counter.new(128)
        encryptor = AES.new(data_key, AES.MODE_CTR, counter=enc_ctr)

        c_text = encryptor.encrypt(tobytes(value))
        # compute an HMAC using the hmac key and the ciphertext
        hmac = HMAC(hmac_key, msg=c_text, digestmod=SHA256)
        b64hmac = hmac.hexdigest()

        key = "%s.txt.enc" % stash_key
        existing_stash = self._aws_manager.s3_head(deployment_bucket_name, key)

        if existing_stash is None:
            print(colored("Stashing '%s'" % stash_key))
            self._aws_manager.s3_put(
                deployment_bucket_name,
                b64encode(c_text).decode('utf-8'), key, {
                    'encryption-key': b64encode(wrapped_key).decode('utf-8'),
                    'hmac': b64hmac
                })
        else:
            perform_overwrite = query_yes_no(
                "Stash '%s' already exists, want to overwrite?" % stash_key,
                default="no")
            if perform_overwrite:
                self._aws_manager.s3_put(
                    deployment_bucket_name,
                    b64encode(c_text).decode('utf-8'), key, {
                        'encryption-key':
                        b64encode(wrapped_key).decode('utf-8'),
                        'hmac': b64hmac
                    })
            else:
                print(colored("Not stashing anything for key '%s'" %
                              stash_key))