Exemple #1
0
    def upgrade_app(self, appname, to):
        """Upgrades the given app to the given version."""
        if "/" in appname or "\\" in appname:
            raise ValueError("Bad app name")

        self._check_appname(appname)

        log.info("Upgrading {0} to version {1}".format(
            appname, to))
        apppath = os.path.join(self.projectdir, appname)
        apptype = opus.lib.builder.sources.introspect_source(apppath)
        log.debug("apppath is %s", apppath)
        log.debug("apptype is %s", apptype)

        opus.lib.builder.sources.upgrade_functions[apptype](apppath, to)

        # If there isn't a media link and there should be, add one
        if os.path.exists(os.path.join(self.projectdir, appname, "media")) \
                and not os.path.exists(os.path.join(self.projectdir,
                    "media",appname)):
            os.symlink(os.path.join("..",appname,"media"),
                    os.path.join(self.projectdir, "media",appname))


        self._touch_wsgi()
Exemple #2
0
 def restart_celery(self, secureops="secureops"):
     """Call this after you're done adding, upgrading, or deleting apps to
     reload the celery daemon"""
     pidfile = os.path.join(self.projectdir, "run", "supervisord.pid")
     if os.path.exists(pidfile):
         log.info("Restarting supervisord/celery")
         proc = subprocess.Popen([secureops,"-s",
                 "opus"+self.projectname,
                 self.projectdir,
                 "-H",
                 ],
                 stdout=subprocess.PIPE,
                 stderr=subprocess.STDOUT)
         output = proc.communicate()[0]
         ret = proc.wait()
         if ret:
             raise BuildException("Could not restart supervisord. {0}".format(output))
Exemple #3
0
def create(request, projectname):
    """Create and deploy a new project. Displays the form to do so on GET, goes
    and does a create + deploy operation on POST.
    Also has the feature to pre-fill out the form from an incomming JSON token.

    """
    if request.method == "POST" and \
        request.META['CONTENT_TYPE'].find("application/x-www-form-urlencoded") != -1:
        # If the submitted type is not form encoded data, it's probably a json
        # spec of applications, which should instead go to populate and display
        # the forms.
        pform = forms.ProjectForm(request.POST)
        appsform = forms.AppFormSet(request.POST)
        dform = forms.DeploymentForm(request.POST, noactive=True)
        allforms = [pform, appsform, dform]
        # If forms aren't valid, fall through and display the (invalid) forms
        # with error text
        if all(f.is_valid() for f in allforms):
            log.info("Preparing to create+deploy %s", projectname)

            pdata = pform.cleaned_data

            # Create the deployment object to do some early validation checks
            deployment = models.DeployedProject()
            deployment.name = projectname
            deployment.owner = request.user
            deployment.full_clean()

            # Configure the new project. None of these actions actually execute
            # until we enter the try block below
            builder = opus.lib.builder.ProjectBuilder(projectname)
            for appdata in appsform.cleaned_data:
                if not appdata:
                    # Left blank, nothing to add
                    continue
                log.debug(" ... with app %r", appdata['apppath'])
                builder.add_app(appdata['appname'], appdata['apppath'],
                        appdata['apptype'])
            if pdata['idprovider'] != 'local':
                log.debug(" ... and the idp app %r", pdata['idprovider'])
                appname, apptype, apppath = \
                        settings.OPUS_ALLOWED_AUTH_APPS[pdata['idprovider']]
                builder.add_app(appname, apppath, apptype)

            # Now actually execute the tasks. This is done in a try block which
            # catches all exceptions so that we can roll back failed partial
            # deployments in any error cases.
            log.debug("Executing create action on %r...", projectname)
            try:
                # Create the project directory
                projectdir = builder.create(settings.OPUS_BASE_DIR)
                log.info("%r created, starting deploy process", projectname)

                # Prepare deployment parameters
                info = models.DeploymentInfo()
                info.dbengine = dform.cleaned_data['dbengine']
                # If requested, create a database for it
                if info.dbengine == "postgresql_psycopg2" and \
                        settings.OPUS_AUTO_POSTGRES_CONFIG:
                    autodb = opus.project.deployment.database.\
                            setup_postgres(projectname)
                    info.dbname, info.dbuser, info.dbpassword, \
                            info.dbhost, info.dbport = autodb
                elif info.dbengine == "sqlite3":
                    # SQLite database locations get set automatically by the
                    # deployment libraries. No other options are set.
                    # SQLite is handled differently (as far as the location of
                    # the code) since the file must be secured properly.  So
                    # the deployer handles that correctly along side its
                    # routines to change permissions on the directory.
                    pass
                else:
                    info.dbname = dform.cleaned_data['dbname']
                    info.dbuser = dform.cleaned_data['dbuser']
                    info.dbpassword = dform.cleaned_data['dbpassword']
                    info.dbhost = dform.cleaned_data['dbhost']
                    info.dbport = dform.cleaned_data['dbport']
                info.superusername = dform.cleaned_data['superusername']
                info.superemail = dform.cleaned_data['superemail']
                info.superpassword = dform.cleaned_data['superpassword']


                # Deploy it now! But don't activate it.
                deployment.deploy(info, False)

                deployment.set_debug(dform.cleaned_data['debug'])
                deployment.save()

            except Exception, e:
                # The project didn't deploy for whatever reason. Delete the
                # project directory and re-raise the exception
                # Careful that this method isn't called on an existing project,
                # since it could be tricked into deleting an existing project.
                # edit_or_create() ought to check that for us, this function
                # shouldn't be called on an existing project.
                log.error("Project didn't fully create or deploy, rolling back deployment. %s", e)
                # Schedule a task to delete the project
                tasks.destroy_project_by_name.delay(deployment.name)
                raise

            log.info("Project %r successfully deployed", projectname)

            return redirect("opus.project.deployment.views.set_app_settings", projectname)

        else:
            log.debug(request.POST)
            log.debug("Create view called, but forms didn't validate")
Exemple #4
0
def edit(request, project):
    """Configuration editor view for an already deployed project

    """
    initial = _get_initial_edit_data(project)

    if request.method == "POST":
        form = forms.DeploymentForm(request.POST, initial=initial)
        if form.is_valid():
            log.info("Edit form submitted and is valid. Editing project parameters")
            cd = form.cleaned_data
            # Go and modify the project/config parameters. Don't save yet
            for field in form.changed_data:
                if field == "dbengine":
                    database['ENGINE'] = 'django.db.backends.' + cd['dbengine']
                    log.debug("dbengine changed to %s", cd['dbengine'])
                elif field == "dbpassword":
                    database['PASSWORD'] = cd['dbpassword']
                    log.debug("dbpassword changed",)
                elif field == "dbhost":
                    database['HOST'] = cd['dbhost']
                    log.debug("dbhost changed to %s", cd['dbhost'])
                elif field == "dbport":
                    database['PORT'] = cd['dbport']
                    log.debug("dbport changed to %s", cd['dbport'])


            project.set_debug(cd['debug'])

            messages = []

            # Validate the modified model
            try:
                # This may error if there's a port conflict or something
                project.full_clean()
            except ValidationError, e:
                log.info("Project model didn't clean. %s", e)
                messages.extend(e.messages)
                # Re-load the project object with the old data, for the "Info"
                # section
                project = models.DeployedProject.objects.get(pk=project.pk)
            else:
                log.info("Model cleaned, saving")
                # save model and config, activate/deactivate if requested,
                # add new superuser if requested
                project.save()
                if "superusername" in form.changed_data:
                    # Should this code be offloaded to a method in the model?
                    log.debug("Adding new superuser")
                    deployer = opus.lib.deployer.ProjectDeployer(project.projectdir)
                    try:
                        deployer.create_superuser(cd['superusername'],
                                cd['superemail'],
                                cd['superpassword'],
                                )
                    except DeploymentException, e:
                        if "column username is not unique" in e.message:
                            messages.append("User with that name already exists!")
                        else:
                            raise e
                    else:
                        messages.append("New superuser created")
                        # Don't re-render the username and password in the form
                        # First make it mutable
                        form.data = form.data.copy()
                        # Then delete these properties
                        del form.data['superusername']
                        del form.data['superemail']
                        del form.data['superpassword']
                        del form.data['superpasswordconfirm']
                # Do this after everything else. If activate fails due to
                # missing app settings, it redirects. Everything else should
                # still be saved though.
                if 'active' in form.changed_data:
                    if cd['active']:
                        if not project.all_settings_set():
                            log.debug("Tried to activate, but still needs settings set. Rendering app settings page")

                            appforms = _get_app_settings_forms(project.get_app_settings(),
                                    project.config)
                            if messages:
                                messages.append("")
                                messages.append("BUT...")
                            messages.append("You asked me to activate the project, but you must set all the settings below first.")

                            return render("deployment/appsettings.html", dict(
                                    appforms=appforms,
                                    project=project,
                                    messages=messages,
                                    ), request)
                        log.debug("Activating")
                        project.activate()
                        messages.append("Project activated")
                    else:
                        log.debug("Deactivating")
                        project.deactivate()
                        messages.append("Project deactivated")
            return render("deployment/edit.html",
                    {'project': project,
                        'form': form,
                        'message': "<br />".join(messages),
                        'applist': _get_apps(project),
                        'appform': forms.AppForm(),
                        }, request)