def create_schema(self, check_if_exists=False, sync_schema=True,
                      verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        """

        # safety check
        _check_schema_name(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)

        if sync_schema:
            call_command('migrate_schemas',
                         schema_name=self.schema_name,
                         interactive=False,
                         verbosity=verbosity)

        connection.set_schema_to_public()
Esempio n. 2
0
def clone_schema(schema_name, clone_schema_name, set_connection=True):
    """
    Creates a full clone of an existing schema.
    """
    # check the clone_schema_name like we usually would
    _check_schema_name(clone_schema_name)
    if schema_exists(clone_schema_name):
        raise ValidationError("Schema name already exists")

    # The schema is changed to public because the clone function should live there.
    if set_connection:
        connection.set_schema_to_public()
    cursor = connection.cursor()

    # check if the clone_schema function already exists in the db
    try:
        cursor.execute("SELECT 'clone_schema'::regproc")
    except ProgrammingError:
        _create_clone_schema_function()
        transaction.commit()

    sql = 'SELECT clone_schema(%(schema_name)s, %(clone_schema_name)s, true, false)'
    cursor.execute(sql, {
        'schema_name': schema_name,
        'clone_schema_name': clone_schema_name
    })
    cursor.close()
Esempio n. 3
0
    def create_schema(self,
                      check_if_exists=False,
                      sync_schema=True,
                      verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        """

        # safety check
        _check_schema_name(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)

        if sync_schema:
            call_command('migrate_schemas',
                         schema_name=self.schema_name,
                         interactive=False,
                         verbosity=verbosity)

        connection.set_schema_to_public()
Esempio n. 4
0
    def create_schema(self,
                      check_if_exists=False,
                      sync_schema=True,
                      verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        """

        # safety check
        _check_schema_name(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)

        if sync_schema:
            if django.VERSION >= (
                    1,
                    7,
                    0,
            ):
                call_command('migrate_schemas',
                             schema_name=self.schema_name,
                             interactive=False,
                             verbosity=verbosity)
            else:
                # default is faking all migrations and syncing directly to the current models state
                fake_all_migrations = getattr(
                    settings, 'TENANT_CREATION_FAKES_MIGRATIONS', True)
                call_command('sync_schemas',
                             schema_name=self.schema_name,
                             tenant=True,
                             public=False,
                             interactive=False,
                             migrate_all=fake_all_migrations,
                             verbosity=verbosity)

                # run/fake all migrations
                if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode(
                ):
                    call_command('migrate_schemas',
                                 fake=fake_all_migrations,
                                 schema_name=self.schema_name,
                                 verbosity=verbosity)

        connection.set_schema_to_public()
        post_schema_sync.send(sender=TenantMixin, tenant=self)
Esempio n. 5
0
    def create_schema(self,
                      check_if_exists=True,
                      sync_schema=True,
                      verbosity=1):
        """
        If schema is "public" or matches _TEMPLATE_SCHEMA, then use the superclass' create_schema() method.
        Else, verify the template and inputs and use the database clone function.
        """
        if self.schema_name in ("public", self._TEMPLATE_SCHEMA):
            LOG.info(
                f'Using superclass for "{self.schema_name}" schema creation')
            return super().create_schema(check_if_exists=True,
                                         sync_schema=sync_schema,
                                         verbosity=verbosity)

        # Verify name structure
        _check_schema_name(self.schema_name)

        # Make sure all of our special pieces are in play
        ret = self._check_clone_func()
        if not ret:
            errmsg = "Missing clone_schema function even after re-applying the function SQL file."
            LOG.critical(errmsg)
            raise CloneSchemaFuncMissing(errmsg)

        ret = self._verify_template(verbosity=verbosity)
        if not ret:
            errmsg = f'Template schema "{self._TEMPLATE_SCHEMA}" does not exist'
            LOG.critical(errmsg)
            raise CloneSchemaTemplateMissing(errmsg)

        # Always check to see if the schema exists!
        if schema_exists(self.schema_name):
            LOG.warning(f'Schema "{self.schema_name}" already exists.')
            return False

        # Clone the schema. The database function will check
        # that the source schema exists and the destination schema does not.
        self._clone_schema()
        LOG.info(
            f'Successful clone of "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}"'
        )

        return True
Esempio n. 6
0
    def create_schema(self, check_if_exists=False, sync_schema=True,
                      verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        """

        # safety check
        _check_schema_name(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)

        if sync_schema:
            if django.VERSION >= (1, 7, 0,):
                call_command('migrate_schemas',
                             schema_name=self.schema_name,
                             interactive=False,
                             verbosity=verbosity)
            else:
                # default is faking all migrations and syncing directly to the current models state
                fake_all_migrations = getattr(settings, 'TENANT_CREATION_FAKES_MIGRATIONS', True)
                call_command('sync_schemas',
                             schema_name=self.schema_name,
                             tenant=True,
                             public=False,
                             interactive=False,
                             migrate_all=fake_all_migrations,
                             verbosity=verbosity)

                # run/fake all migrations
                if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode():
                    call_command('migrate_schemas',
                                 fake=fake_all_migrations,
                                 schema_name=self.schema_name,
                                 verbosity=verbosity)

        connection.set_schema_to_public()
        post_schema_sync.send(sender=TenantMixin, tenant=self)
Esempio n. 7
0
    def create_schema(self,
                      check_if_exists=True,
                      sync_schema=True,
                      verbosity=1):
        """
        If schema is "public" or matches _TEMPLATE_SCHEMA, then use the superclass' create_schema() method.
        Else, verify the template and inputs and use the database clone function.
        """
        if self.schema_name in ("public", self._TEMPLATE_SCHEMA):
            LOG.info(
                f'Using superclass for "{self.schema_name}" schema creation')
            return super().create_schema(check_if_exists=True,
                                         sync_schema=sync_schema,
                                         verbosity=verbosity)

        db_exc = None
        with transaction.atomic():
            # Verify name structure
            _check_schema_name(self.schema_name)

            # Make sure all of our special pieces are in play
            ret = self._check_clone_func()
            if not ret:
                errmsg = "Missing clone_schema function even after re-applying the function SQL file."
                LOG.critical(errmsg)
                raise CloneSchemaFuncMissing(errmsg)

            ret = self._verify_template(verbosity=verbosity)
            if not ret:
                errmsg = f'Template schema "{self._TEMPLATE_SCHEMA}" does not exist'
                LOG.critical(errmsg)
                raise CloneSchemaTemplateMissing(errmsg)

            # Always check to see if the schema exists!
            if schema_exists(self.schema_name):
                LOG.warning(f'Schema "{self.schema_name}" already exists.')
                return False

            # Clone the schema. The database function will check
            # that the source schema exists and the destination schema does not.
            try:
                self._clone_schema()
            except DBError as dbe:
                db_exc = dbe
                LOG.error(
                    f"""Exception {dbe.__class__.__name__} cloning""" +
                    f""" "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}": {str(dbe)}"""
                )
                transaction.set_rollback(
                    True
                )  # Set this transaction context to issue a rollback on exit
            else:
                LOG.info(
                    f'Successful clone of "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}"'
                )

        # Set schema to public (even if there was an exception)
        with transaction.atomic():
            conn.set_schema_to_public()

        if db_exc:
            raise db_exc

        return True