Beispiel #1
0
    def create_gem(
        self, 
        gem_name, 
        initial_content = 'empty', 
        enable = False, 
        asset_only = False, 
        version = '1.0.0', 
        relative_directory_path = None,
        lmbr_exe_path_override = None,
        no_sln_change = False):

        # Validate arguments

        try:
            util.validate_stack_name(gem_name)
        except HandledError as e:
            raise HandledError('The gem name is not valid for use as a Cloud Gem. {}.'.format(e))

        if initial_content not in self.initial_content_list:
            raise HandledError('Invalid initial content: {}. Valid initial content values are {}.'.format(initial_content, ', '.join(self.initial_content_list)))

        # Validate files are writable

        writable_file_list = []

        if enable:
            writable_file_list.append(self.get_gems_file_path())

        if writable_file_list:
            if not util.validate_writable_list(self.__context, writable_file_list):
                return

        # Create the gem...

        root_directory_path = self.__do_lmbr_gems_create(lmbr_exe_path_override, gem_name, relative_directory_path, asset_only, version)

        # Add the framework dependency
        
        self.__add_framework_gem_dependency(root_directory_path)

        # Copy initial gem content...

        self.__copy_initial_gem_content(gem_name, root_directory_path, initial_content, no_sln_change)

        # Set the c++ build configuration for the gem.

        if not asset_only:
            self.__setup_cloud_gem_cpp_build(root_directory_path, gem_name, initial_content) 

        # Add gem to collections...

        gem = self.__add_gem(root_directory_path, enable)

        # Tell them about it, then go on to enable if requested...

        self.__context.view.gem_created(gem_name, root_directory_path)

        if enable:
            self.enable_gem(gem_name, lmbr_exe_path_override)
    def add_resource_group(self, resource_group):
        if resource_group.name in self.__dict__.keys():
            raise HandledError(
                'Multiple resource groups named {} are enabled for the project.'
                .format(resource_group.name))

        try:
            util.validate_stack_name(resource_group.name)
        except HandledError as e:
            raise HandledError(
                'The resource group name \'{}\' is not a valid name. '.format(
                    e))

        self.__dict__[resource_group.name] = resource_group
Beispiel #3
0
    def gem_enabled(self, gem):

        if gem.has_aws_file(constant.RESOURCE_GROUP_TEMPLATE_FILENAME):

            if gem.name in self.__resource_groups.keys():
                if self.__resource_groups[gem.name].gem is not gem:
                    raise HandledError(
                        'Multiple cloud gems named {} are enabled for the project. Cloud gems must have unique names within a project.'
                        .format(gem.name))

            try:
                util.validate_stack_name(gem.name)
            except HandledError as e:
                raise HandledError(
                    'The gem name is not valid for use as a Cloud Gem. {}. You need to rename or disable the gem, or remove the gem\s AWS\resource-group-template.json file.'
                    .format(e))

            self.__resource_groups[gem.name] = ResourceGroup(
                self.__context, gem.name, gem.aws_directory_path,
                gem.cpp_base_directory_path, gem.cpp_aws_directory_path, gem)
Beispiel #4
0
def create_stack(context, args):
    '''Implements the lmbr_aws initialze-project command.'''

    # Supported region?
    supported_regions = __get_region_list()
    if args.region not in supported_regions:
        raise HandledError('Region {} is not supported.'.format(args.region))

    # Initialize AWS directory if needed.
    context.config.initialize_aws_directory()
    if (args.files_only):
        return

    # Already initialized?
    if context.config.project_stack_id is not None:
        raise HandledError(
            'The project has already been initialized and is using the {} AWS Cloud Formation stack.'
            .format(context.config.project_stack_id))

    # Project settings writable?
    context.config.validate_writable(
        context.config.local_project_settings.path)

    # Is it ok to do this?
    pending_resource_status = __get_pending_resource_status(context)
    capabilities = context.stack.confirm_stack_operation(
        context.config.get_pending_project_stack_id(
        ),  # may be None, which is ok
        'project',
        args,
        pending_resource_status)

    # Skip creating the stack if we have already done so.
    if not context.config.get_pending_project_stack_id():

        # Use game directory name as stack name by default.
        if args.stack_name is None:
            args.stack_name = context.config.game_directory_name

        # Does a stack with the name already exist?
        if context.stack.name_exists(args.stack_name, args.region):
            raise HandledError(
                'An AWS Cloud Formation stack with the name {} already exists in region {}. Use the --stack-name option to provide a different name.'
                .format(args.stack_name, args.region))

        # Is the stack name valid?
        util.validate_stack_name(args.stack_name)

        # Create stack using the boostrapping template.
        context.stack.create_using_template(
            args.stack_name,
            bootstrap_template,
            args.region,
            created_callback=lambda id: context.config.
            set_pending_project_stack_id(id),
            capabilities=capabilities)

    # Create initial project settings.
    context.config.init_project_settings()

    # Temporarily set the config's project_stack_id property to the pending stack
    # id so the project uploader can find it later.
    context.config.project_stack_id = context.config.get_pending_project_stack_id(
    )

    # Do the initial update...
    __update_project_stack(context, pending_resource_status, capabilities)
Beispiel #5
0
def create_stack(context, args):

    # Has the project been initialized?
    if not context.config.project_initialized:
        raise HandledError('The project has not been initialized.')

    # Does a deployment with that name already exist?
    if context.config.deployment_stack_exists(args.deployment):
        raise HandledError('The project already has a {} deployment.'.format(args.deployment))

    # Does deployment-template.json include resource group from a gem which isn't enabled for the project?
    for resource_group_name in context.resource_groups.keys():
         __check_resource_group_gem_status(context, resource_group_name)

    # Is the project settings file writable?
    context.config.validate_writable(context.config.local_project_settings_path)

    # Is the deployment name valid?
    util.validate_stack_name(args.deployment)

    # If there is no project default deployment, make this the project default deployment
    if context.config.project_default_deployment is None:
        args.make_project_default = True

    # If there is no release deployment, make this the release deployment
    if context.config.release_deployment is None:
        args.make_release_deployment = True

    # Need to handle situations where the deployment and/or access stack were
    # not successfully created on previous attempts.

    pending_deployment_stack_id = context.config.get_pending_deployment_stack_id(args.deployment)
    pending_deployment_access_stack_id = context.config.get_pending_deployment_access_stack_id(args.deployment)

    pending_deployment_stack_status = context.stack.get_stack_status(pending_deployment_stack_id)
    pending_deployment_access_stack_status = context.stack.get_stack_status(pending_deployment_access_stack_id)

    # Does a stack with the name already exist? It's ok if a previous attempt
    # at creation left a stack with this name behind, we'll deal with that later.
    deployment_stack_name = args.stack_name or context.config.get_default_deployment_stack_name(args.deployment)
    deployment_region = util.get_region_from_arn(context.config.project_stack_id)
    if pending_deployment_stack_id is None or deployment_stack_name != util.get_stack_name_from_arn(pending_deployment_stack_id):
        if context.stack.name_exists(deployment_stack_name, deployment_region):
            raise HandledError('An AWS Cloud Formation stack with the name {} already exists in region {}. Use the --stack-name option to provide a different name.'.format(deployment_stack_name, deployment_region))

    # Resource group (and other) file write checks
    create_and_validate_writable_list(context)

    # Is it ok to use AWS?

    pending_resource_status = __get_pending_combined_resource_status(context, args.deployment)

    capabilities = context.stack.confirm_stack_operation(
        None, # stack id
        'deployment {}'.format(args.deployment),
        args,
        pending_resource_status,
        ignore_resource_types = [ 'Custom::EmptyDeployment' ]
    )

    # We have the following scenerios to deal with:
    #
    # 1) This is the first attempt to create the deployment, or previous attempts didn't
    #    get as far as creating any stacks.
    #
    # 2) The previous attempt failed to create or update the deployment stack, which was
    # left in a ROLLBACK_COMPLETED, UPDATE_ROLLBACK_FAILED, or ROLLBACK_FAILED state. This
    # stack must be deleted and a new one created.
    #
    # 3) The previous attempt created the deployment stack but failed to create the access
    # stack, leaving it in the ROLLBACK_COMPLETED state. In this case we update the deployment
    # stack (to make sure it reflects any changes that may have been made), delete the access
    # stack and attempt to create a new one.
    #
    # 4) Both the deployment and access stacks were created successfully, but the pending
    # stack id properites in the config were not replaced with the non-pending properties
    # (this could happen if someone kills the client during the access stack creation
    # process, which then runs to a successful completion). In this case we update both
    # stacks to make sure they reflect any changes, then replace the "pending" stack id
    # properties.

    project_uploader = ProjectUploader(context)
    deployment_uploader = project_uploader.get_deployment_uploader(args.deployment)

    template_url = before_update(context, deployment_uploader)

    deployment_stack_parameters = __get_deployment_stack_parameters(context, args.deployment, uploader = deployment_uploader)

    # wait a bit for S3 to help insure that templates can be read by cloud formation
    time.sleep(constant.STACK_UPDATE_DELAY_TIME)

    try:

        if pending_deployment_stack_status not in [None, context.stack.STATUS_ROLLBACK_COMPLETE, context.stack.STATUS_DELETE_COMPLETE, context.stack.STATUS_UPDATE_ROLLBACK_FAILED, context.stack.STATUS_ROLLBACK_FAILED]:

            # case 3 or 4 - deployment stack was previously created successfully, update it

            context.stack.update(
                pending_deployment_stack_id, 
                template_url, 
                deployment_stack_parameters,
                capabilities = capabilities
            )
            deployment_stack_id = pending_deployment_stack_id

        else:

            if pending_deployment_stack_status in [context.stack.STATUS_ROLLBACK_COMPLETE, context.stack.STATUS_ROLLBACK_FAILED, context.stack.STATUS_UPDATE_ROLLBACK_FAILED]:

                # case 2 - deployment stack failed to create previously, delete it

                context.stack.delete(pending_deployment_stack_id)

            # case 1 and 2 - deployment stack wasn't creatred previously or was just
            # deleted, attempt to create it

            deployment_stack_id = context.stack.create_using_url(
                deployment_stack_name,
                template_url,
                deployment_region,
                deployment_stack_parameters,
                created_callback=lambda id: context.config.set_pending_deployment_stack_id(args.deployment, id),
                capabilities = capabilities)

        # Now create or update the access stack...

        context.view.processing_template('{} deployment'.format(args.deployment))

        access_template_url = deployment_uploader.upload_content(
            constant.DEPLOYMENT_ACCESS_TEMPLATE_FILENAME, 
            json.dumps(context.config.deployment_access_template_aggregator.effective_template, indent=4, sort_keys=True),
            'processed deployment access temmplate')

        access_stack_parameters = __get_access_stack_parameters(
            context, 
            args.deployment, 
            deployment_stack_id = deployment_stack_id, 
            uploader = deployment_uploader
        )
        
        if pending_deployment_access_stack_status not in [None, context.stack.STATUS_ROLLBACK_COMPLETE, context.stack.STATUS_DELETE_COMPLETE]:

            # case 4 - access stack was previously created successfully but the pending
            # stack id properties were not replaced. Update the stack.

            context.stack.update(
                pending_deployment_access_stack_id, 
                access_template_url, 
                deployment_stack_parameters,
                capabilities = capabilities
            )

            deployment_access_stack_id = pending_deployment_access_stack_id

        else:

            if pending_deployment_access_stack_status == context.stack.STATUS_ROLLBACK_COMPLETE:

                # case 3 - access stack failed to create previously, delete it

                context.stack.delete(pending_deployment_access_stack_id)

            # case 1 or 3 - access stack wasn't created before, or was just deleted. Attempt
            # to create.

            deployment_access_stack_name = deployment_stack_name + '-Access'

            deployment_access_stack_id = context.stack.create_using_url(
                deployment_access_stack_name,
                access_template_url,
                deployment_region,
                parameters = access_stack_parameters,
                created_callback=lambda id: context.config.set_pending_deployment_access_stack_id(args.deployment, id),
                capabilities = capabilities)

    except:
        context.config.force_gui_refresh()
        raise

    context.config.force_gui_refresh()

    context.config.finalize_deployment_stack_ids(args.deployment)

    context.view.deployment_stack_created(args.deployment, deployment_stack_id, deployment_access_stack_id)

    # Should the new deployment become the project default deployment or the release deployment?

    if args.make_project_default:
        context.config.set_project_default_deployment(args.deployment)
        mappings.update(context, util.Args())
        context.view.default_deployment(context.config.user_default_deployment, context.config.project_default_deployment)

    if args.make_release_deployment:
        context.config.set_release_deployment(args.deployment)
        temp_args = util.Args()
        temp_args.release = True
        mappings.update(context, temp_args)
        context.view.release_deployment(context.config.release_deployment)
    
    after_update(context, deployment_uploader)