Beispiel #1
0
    def update_instance_from_pr(self, pr):
        """
        Update/create the associated sandbox instance with settings from the given pull request.

        This will not spawn a new AppServer.
        This method will automatically save this WatchedPullRequest's 'instance' field.
        """
        # The following fields should never change:
        assert self.github_pr_url == pr.github_pr_url
        assert self.fork_name == pr.fork_name
        assert self.branch_name == pr.branch_name
        # Create an instance if necessary:
        instance = self.instance or OpenEdXInstance()
        instance.internal_lms_domain = generate_internal_lms_domain('pr{number}.sandbox'.format(number=pr.number))
        instance.edx_platform_repository_url = self.repository_url
        instance.edx_platform_commit = self.get_branch_tip()
        instance.name = (
            'PR#{pr.number}: {pr.truncated_title} ({pr.username}) - {i.reference_name} ({commit_short_id})'
            .format(pr=pr, i=self, commit_short_id=instance.edx_platform_commit[:7])
        )
        instance.configuration_extra_settings = yaml_merge(
            self.watched_fork.configuration_extra_settings,
            pr.extra_settings
        )
        if not instance.ref.creator or not instance.ref.owner:
            user = UserProfile.objects.get(github_username=pr.username)
            instance.ref.creator = user
            instance.ref.owner = user.organization
        # Configuration repo and version and edx release follow this precedence:
        # 1) PR settings. 2) WatchedFork settings. 3) instance model defaults
        instance.configuration_source_repo_url = pr.get_extra_setting(
            'edx_ansible_source_repo',
            default=(
                self.watched_fork.configuration_source_repo_url or
                instance.configuration_source_repo_url
            )
        )
        instance.configuration_version = pr.get_extra_setting(
            'configuration_version', default=(
                self.watched_fork.configuration_version or
                instance.configuration_version
            )
        )
        instance.openedx_release = pr.get_extra_setting(
            'openedx_release', default=(
                self.watched_fork.openedx_release or
                instance.openedx_release
            )
        )
        # Save atomically. (because if the instance gets created but self.instance failed to
        # update, then any subsequent call to update_instance_from_pr() would try to create
        # another instance, which would fail due to unique domain name constraints.)
        with transaction.atomic():
            instance.save()
            if not self.instance:
                self.instance = instance
                self.save(update_fields=["instance"])
Beispiel #2
0
 def vars_str(self):
     """
     The ansible vars (private configuration) as a string
     """
     template = loader.get_template('instance/ansible/vars.yml')
     vars_str = template.render({'instance': self})
     for attr_name in self.ANSIBLE_SETTINGS:
         additional_vars = getattr(self, attr_name)
         vars_str = ansible.yaml_merge(vars_str, additional_vars)
     self.log('debug', 'Vars.yml for instance {}:\n{}'.format(self, vars_str))
     return vars_str
Beispiel #3
0
def production_instance_factory(**kwargs):
    """
    Factory function for creating production instances.

    Returns a newly created OpenEdXInstance.

    Callers can use keyword arguments to pass in non-default values
    for any field that is defined on the OpenEdXInstance model.

    The only mandatory argument is `sub_domain`.

    When called without any additional arguments, the instance that is returned
    will have its fields set to default values that are appropriate
    for *production* instances.

    To create an instance with default settings that are suitable for sandboxes,
    use `instance_factory`.
    """
    # NOTE: The long-term goal is to eliminate differences between sandboxes
    # and production instances, and for this function to disappear.
    # Please do not add behavior that is specific to production instances here.

    # Ensure caller provided required arguments
    assert "sub_domain" in kwargs

    # Check environment and report potential problems
    environment_ready = _check_environment()

    if not environment_ready:
        logger.warning("Environment not ready. Please fix the problems above, then try again. Aborting.")
        return

    # Gather settings
    production_settings = loader.get_template('instance/ansible/prod-vars.yml').render({})
    configuration_extra_settings = kwargs.pop("configuration_extra_settings", "")
    extra_settings = ansible.yaml_merge(production_settings, configuration_extra_settings)
    instance_kwargs = dict(
        use_ephemeral_databases=False,
        edx_platform_repository_url=settings.STABLE_EDX_PLATFORM_REPO_URL,
        edx_platform_commit=settings.STABLE_EDX_PLATFORM_COMMIT,
        configuration_source_repo_url=settings.STABLE_CONFIGURATION_REPO_URL,
        configuration_version=settings.STABLE_CONFIGURATION_VERSION,
        openedx_release=settings.OPENEDX_RELEASE_STABLE_REF,
        configuration_extra_settings=extra_settings,
    )
    instance_kwargs.update(kwargs)

    # Create instance
    production_instance = OpenEdXInstance.objects.create(**instance_kwargs)
    return production_instance
Beispiel #4
0
def production_instance_factory(**kwargs):
    """
    Factory function for creating production instances.

    Returns a newly created OpenEdXInstance.

    Callers can use keyword arguments to pass in non-default values
    for any field that is defined on the OpenEdXInstance model.

    The only mandatory argument is `sub_domain`.

    When called without any additional arguments, the instance that is returned
    will have its fields set to default values that are appropriate
    for *production* instances.

    To create an instance with default settings that are suitable for sandboxes,
    use `instance_factory`.
    """
    # NOTE: The long-term goal is to eliminate differences between sandboxes
    # and production instances, and for this function to disappear.
    # Please do not add behavior that is specific to production instances here.

    # Ensure caller provided required arguments
    assert "sub_domain" in kwargs

    # Check environment and report potential problems
    environment_ready = _check_environment()

    if not environment_ready:
        logger.warning("Environment not ready. Please fix the problems above, then try again. Aborting.")
        return

    # Gather settings
    production_settings = loader.get_template('instance/ansible/prod-vars.yml').render({})
    configuration_extra_settings = kwargs.pop("configuration_extra_settings", "")
    extra_settings = ansible.yaml_merge(production_settings, configuration_extra_settings)
    instance_kwargs = dict(
        use_ephemeral_databases=False,
        edx_platform_repository_url=settings.STABLE_EDX_PLATFORM_REPO_URL,
        edx_platform_commit=settings.STABLE_EDX_PLATFORM_COMMIT,
        configuration_source_repo_url=settings.STABLE_CONFIGURATION_REPO_URL,
        configuration_version=settings.STABLE_CONFIGURATION_VERSION,
        openedx_release=settings.OPENEDX_RELEASE_STABLE_REF,
        configuration_extra_settings=extra_settings,
    )
    instance_kwargs.update(kwargs)

    # Create instance
    production_instance = OpenEdXInstance.objects.create(**instance_kwargs)
    return production_instance
    def create_configuration_settings(self):
        """
        Generate the configuration settings.

        This is a one-time thing, because configuration_settings, like all AppServer fields, is
        immutable once this AppServer is saved.
        """
        template = loader.get_template(self.CONFIGURATION_VARS_TEMPLATE)
        vars_str = template.render({
            'appserver': self,
            'instance': self.instance,
            'newrelic_license_key': settings.NEWRELIC_LICENSE_KEY,
        })
        for attr_name in self.CONFIGURATION_EXTRA_FIELDS:
            additional_vars = getattr(self, attr_name)
            vars_str = ansible.yaml_merge(vars_str, additional_vars)
        self.logger.debug('Vars.yml:\n%s', vars_str)
        return vars_str
Beispiel #6
0
 def reset_ansible_settings(self, commit=True):
     """
     Set the ansible_settings field from the Ansible vars template.
     """
     template = loader.get_template('instance/ansible/vars.yml')
     vars_str = template.render({
         'instance': self,
         # This proerty is needed twice in the template.  To avoid evaluating it twice (and
         # querying the Github API twice), we pass it as a context variable.
         'github_admin_username_list': self.github_admin_username_list,
     })
     for attr_name in self.ANSIBLE_SETTINGS:
         additional_vars = getattr(self, attr_name)
         vars_str = ansible.yaml_merge(vars_str, additional_vars)
     self.logger.debug('Vars.yml:\n%s', vars_str)
     self.ansible_settings = vars_str
     if commit:
         self.save()
Beispiel #7
0
 def test_yaml_merge(self):
     """
     Merge of two yaml strings with overlapping variables
     """
     yaml_result_str = ansible.yaml_merge(self.yaml_str1, self.yaml_str2)
     self.assertEquals(yaml.load(yaml_result_str), {
         'testa': 'firsta with unicode «ταБЬℓσ»',
         'testb': 'secondb with unicode «ταБЬℓσ2»',
         'testc': 'secondc',
         'test_dict': {
             'foo': 'secondfoo',
             'bar': 'firstbar',
             'other': 'secondother',
             'recursive': {
                 'a': 1,
                 'b': 2,
             },
         }
     })
Beispiel #8
0
 def test_yaml_merge(self):
     """
     Merge of two yaml strings with overlapping variables
     """
     yaml_result_str = ansible.yaml_merge(self.yaml_str1, self.yaml_str2)
     self.assertEqual(
         yaml.load(yaml_result_str), {
             'testa': 'firsta with unicode «ταБЬℓσ»',
             'testb': 'secondb with unicode «ταБЬℓσ2»',
             'testc': 'secondc',
             'test_dict': {
                 'foo': 'secondfoo',
                 'bar': 'firstbar',
                 'other': 'secondother',
                 'recursive': {
                     'a': 1,
                     'b': 2,
                 },
             }
         })
Beispiel #9
0
 def reset_ansible_settings(self, commit=True):
     """
     Set the ansible_settings field from the Ansible vars template.
     """
     template = loader.get_template('instance/ansible/vars.yml')
     vars_str = template.render({
         'instance':
         self,
         # This proerty is needed twice in the template.  To avoid evaluating it twice (and
         # querying the Github API twice), we pass it as a context variable.
         'github_admin_username_list':
         self.github_admin_username_list,
     })
     for attr_name in self.ANSIBLE_SETTINGS:
         additional_vars = getattr(self, attr_name)
         vars_str = ansible.yaml_merge(vars_str, additional_vars)
     self.logger.debug('Vars.yml:\n%s', vars_str)
     self.ansible_settings = vars_str
     if commit:
         self.save()
Beispiel #10
0
    def create_configuration_settings(self):
        """
        Generate the configuration settings.

        This is a one-time thing, because configuration_settings, like all AppServer fields, is
        immutable once this AppServer is saved.
        """
        template = loader.get_template(self.CONFIGURATION_VARS_TEMPLATE)
        vars_str = template.render({
            'appserver':
            self,
            'instance':
            self.instance,
            'newrelic_license_key':
            settings.NEWRELIC_LICENSE_KEY,
        })
        for attr_name in self.CONFIGURATION_EXTRA_FIELDS:
            additional_vars = getattr(self, attr_name)
            vars_str = ansible.yaml_merge(vars_str, additional_vars)
        self.logger.debug('Vars.yml:\n%s', vars_str)
        return vars_str
Beispiel #11
0
 def test_yaml_merge_with_none(self):
     """
     Merge of a yaml string with None
     """
     self.assertEqual(ansible.yaml_merge(self.yaml_str1, None),
                      self.yaml_str1)
Beispiel #12
0
 def test_yaml_merge_with_none(self):
     """
     Merge of a yaml string with None
     """
     self.assertEqual(ansible.yaml_merge(self.yaml_str1, None), self.yaml_str1)