def setup_cloud_service(self, sctx):
        # get context from super context
        ctx = sctx.job_ctxs[sctx.current_job_index]
        adapter = self.__get_adapter_from_sctx(sctx, CloudServiceAdapter)

        try:
            if not adapter.cloud_service_exists(ctx.cloud_service_name):
                if not adapter.create_cloud_service(
                        name=ctx.cloud_service_name,
                        label=ctx.cloud_service_label,
                        location=ctx.cloud_service_host):
                    self.log.error(
                        "azure virtual environment %d create remote cloud service failed via creation"
                        % sctx.current_job_index)
                    self._on_virtual_environment_failed(sctx)
                    return

                # create the cloud service remote successfully, record
                sctx.remote_created.append(
                    Context(type=REMOTE_CREATED_RECORD.TYPE_CLOUD_SERVICE,
                            name=ctx.cloud_service_name))

            self.log.debug(
                "azure virtual environment %d cloud service setup done" %
                sctx.current_job_index)
            # next step: setup storage
            self.scheduler.add_once("azure_vm",
                                    "setup_storage",
                                    id="setup_storage_" +
                                    str(sctx.experiment_id),
                                    context=sctx,
                                    seconds=0)
        except Exception as e:
            self.log.error(
                "azure virtual environment %d create remote cloud service failed: %r"
                % (sctx.current_job_index, str(e)))
            self._on_virtual_environment_failed(sctx)
    def upload_files(self):
        """Handle uploaded files from http request"""
        self.__validate_upload_files()

        images = []
        storage = RequiredFeature("storage")
        for file_name in request.files:
            file_storage = request.files[file_name]
            self.log.debug("upload image file : " + file_name)
            context = Context(hackathon_name=g.hackathon.name,
                              file_name=file_storage.filename,
                              file_type=FILE_TYPE.HACK_IMAGE,
                              content=file_storage)
            context = storage.save(context)
            image = {
                "name": file_storage.filename,
                "url": context.url,
                "thumbnailUrl": context.url,
                "deleteUrl": '/api/admin/file?key=' + context.file_name
            }
            # context.file_name is a random name created by server, file.filename is the original name
            images.append(image)

        return {"files": images}
Example #3
0
    def __stop_virtual_machine_done(self, sctx):
        self.log.debug("azure virtual environment %d stop vm done" %
                       sctx.current_job_index)

        try:
            # update the status of virtual environment
            expr = Experiment.objects(id=sctx.experiment_id).first()
            ve = expr.virtual_environments[sctx.current_job_index]

            self._on_virtual_environment_stopped(
                Context(experiment_id=expr.id,
                        virtual_environment_name=ve.name))

            self.log.debug(
                "azure virtual environment %d vm success callback done, step to next"
                % sctx.current_job_index)
            # step to config next unit
            sctx.current_job_index += 1
            self.__schedule_setup(sctx)
        except Exception as e:
            self.log.error(
                "azure virtual environment %d error while stopping vm: %r" %
                (sctx.current_job_index, e.message))
            self.__on_stop_virtual_machine_failed(sctx)
    def create_certificate(self, subscription_id, management_host, hackathon):
        """Create certificate for specific subscription and hackathon

        1. check certificate dir
        2. generate pem file
        3. generate cert file
        4. add azure key to db
        5. add hackathon azure key to db
        :param subscription_id:
        :param management_host:
        :param hackathon:
        :return:
        """

        base_url = '%s/%s' % (self.CERT_BASE, subscription_id)
        pem_url = base_url + '.pem'

        # avoid duplicate pem generation
        if not os.path.isfile(pem_url):
            pem_command = 'openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout %s -out %s -batch' % \
                          (pem_url, pem_url)
            commands.getstatusoutput(pem_command)
        else:
            self.log.debug('%s exists' % pem_url)

        cert_url = base_url + '.cer'
        # avoid duplicate cert generation
        if not os.path.isfile(cert_url):
            cert_command = 'openssl x509 -inform pem -in %s -outform der -out %s' % (
                pem_url, cert_url)
            commands.getstatusoutput(cert_command)
        else:
            self.log.debug('%s exists' % cert_url)

        azure_key = self.db.find_first_object_by(
            AzureKey,
            cert_url=cert_url,
            pem_url=pem_url,
            subscription_id=subscription_id,
            management_host=management_host)
        # avoid duplicate azure key
        if azure_key is None:
            azure_key = self.db.add_object_kwargs(
                AzureKey,
                cert_url=cert_url,
                pem_url=pem_url,
                subscription_id=subscription_id,
                management_host=management_host)
            self.db.commit()
        else:
            self.log.debug('azure key exists')

        hackathon_azure_key = self.db.find_first_object_by(
            HackathonAzureKey,
            hackathon_id=hackathon.id,
            azure_key_id=azure_key.id)
        # avoid duplicate hackathon azure key
        if hackathon_azure_key is None:
            self.db.add_object_kwargs(HackathonAzureKey,
                                      hackathon_id=hackathon.id,
                                      azure_key_id=azure_key.id)
            self.db.commit()
        else:
            self.log.debug('hackathon azure key exists')

        file_name = subscription_id + '.cer'
        context = Context(hackathon_name=hackathon.name,
                          file_name=file_name,
                          file_type=FILE_TYPE.AZURE_CERT,
                          content=file(cert_url))
        self.log.debug("saving cerf file [%s] to azure" % file_name)
        context = self.storage.save(context)
        azure_key.cert_url = context.url
        self.db.commit()
        return azure_key.cert_url
Example #5
0
 def test_start_expr(self):
     #TODO: mock record in db
     ctx = Context(template="test_template",
                   user="******",
                   hackathon="test_hackathon")
     self.assertTrue(self.service.start_expr(ctx))
    def create_certificate(self, subscription_id, management_host, hackathon):
        """Create certificate for specific subscription and hackathon

        1. check certificate dir
        2. generate pem file
        3. generate cert file
        4. add azure key to db
        5. add hackathon azure key to db
        :param subscription_id:
        :param management_host:
        :param hackathon:
        :return:
        """

        base_url = '%s/%s' % (self.CERT_BASE, subscription_id)
        pem_url = base_url + '.pem'
        cert_url = base_url + '.cer'

        # avoid duplicate pem generation
        if not os.path.isfile(pem_url):
            pem_command = 'openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout %s -out %s -batch' % \
                          (pem_url, pem_url)
            commands.getstatusoutput(pem_command)
        else:
            self.log.debug('%s exists' % pem_url)

        # avoid duplicate cert generation
        if not os.path.isfile(cert_url):
            cert_command = 'openssl x509 -inform pem -in %s -outform der -out %s' % (pem_url, cert_url)
            commands.getstatusoutput(cert_command)
        else:
            self.log.debug('%s exists' % cert_url)

        azure_key = AzureKey.objects(subscription_id=subscription_id, management_host=management_host).first()

        if azure_key is None:
            azure_key = AzureKey(
                cert_url=base_url + '.cer',
                pem_url=base_url + '.pem',
                subscription_id=subscription_id,
                management_host=management_host,
                verified=False
            )

            azure_key.save()

            hackathon.azure_keys.append(azure_key)
            hackathon.save()
        else:
            self.log.debug('azure key exists')

        if not (azure_key in hackathon.azure_keys):
            hackathon.azure_keys.append(azure_key)
            hackathon.save()
        else:
            self.log.debug('hackathon azure key exists')

        # store cer file
        cer_context = Context(
            hackathon_name=hackathon.name,
            file_name=subscription_id + '.cer',
            file_type=FILE_TYPE.AZURE_CERT,
            content=file(cert_url)
        )
        self.log.debug("saving cerf file [%s] to azure" % cer_context.file_name)
        cer_context = self.storage.save(cer_context)
        azure_key.cert_url = cer_context.url

        # store pem file
        # encrypt certification file before upload to storage
        encrypted_pem_url = self.__encrypt_content(pem_url)
        pem_contex = Context(
            hackathon_name=hackathon.name,
            file_name=subscription_id + '.pem',
            file_type=FILE_TYPE.AZURE_CERT,
            content=file(encrypted_pem_url)
        )
        self.log.debug("saving pem file [%s] to azure" % pem_contex.file_name)
        pem_contex = self.storage.save(pem_contex)
        os.remove(encrypted_pem_url)
        azure_key.pem_url = pem_contex.url

        azure_key.save()

        return azure_key.dic()
Example #7
0
    def start_new_docker_host_vm(self, hackathon):
        """
        create docker host VM for hackathon whose id is hackathon_id

        :param hackathon: hackathon
        :type hackathon: Hackathon

        :return: True if send an creating VM request via API successfully after validating storage, container and
         service
         Otherwise, False
        :rtype: bool
        """
        # todo debug this logic and make sure DON'T start two or more VM at the same time
        return False

        hackathon_id = hackathon.id
        sms = self.__get_sms_object(hackathon_id)
        if sms is None:
            self.log.error('No account found for Hackathon:%d' % hackathon_id)
            return False
        # get storage and container
        res, storage_account_name, container_name = self.__get_available_storage_account_and_container(
            hackathon_id)
        if not res:
            return False
        # get service
        res, service_name = self.__get_available_cloud_service(hackathon_id)
        if not res:
            return False
        # set host_name to ensure its uniqueness
        host_name = str(uuid1())[0:9] + strftime("%Y%m%d%H%M%S")
        # set vm os image and hard disk storage
        image_name_default = 'b549f4301d0b4295b8e76ceb65df47d4__Ubuntu-14_04-LTS-amd64-server-20140606.1-en-us-30GB'
        image_name = self.util.safe_get_config(
            'dockerhostserver.vm.image_name', image_name_default)
        media_link = 'https://%s.blob.core.chinacloudapi.cn/%s/%s.vhd' % (
            storage_account_name, container_name, host_name)
        os_hd = OSVirtualHardDisk(image_name, media_link)
        # set linux_config and endpoint_config
        customdata = self.__get_customdata_from_local_file()
        linux_config = LinuxConfigurationSet(
            host_name,
            self.util.safe_get_config('dockerhostserver.vm.username',
                                      'opentech'),
            self.util.safe_get_config('dockerhostserver.vm.password',
                                      'Password01!'),
            False,
            custom_data=customdata)
        endpoint_config = self.__set_endpoint_config(service_name,
                                                     hackathon_id)
        deployment_exist = True
        deployment_slot = ServiceDeploymentSlot.PRODUCTION
        try:
            deployment_exist = self.__deployment_exists(
                service_name, deployment_slot, hackathon_id)
        except Exception as e:
            self.log.error(e)
            return False
        if not deployment_exist:
            try:
                result = sms.create_virtual_machine_deployment(
                    service_name=service_name,
                    network_config=endpoint_config,
                    deployment_name=service_name,
                    deployment_slot=deployment_slot,
                    label=service_name,
                    role_name=host_name,
                    system_config=linux_config,
                    os_virtual_hard_disk=os_hd,
                    role_size=0)
                self.log.debug('To create VM:%s in service:%s.(deployment)' %
                               (host_name, service_name))
            except Exception as e:
                self.log.error(e)
                return False
        else:
            try:
                result = sms.add_role(service_name=service_name,
                                      deployment_name=service_name,
                                      role_name=host_name,
                                      system_config=linux_config,
                                      os_virtual_hard_disk=os_hd,
                                      network_config=endpoint_config,
                                      role_size=0)
                self.log.debug('To create VM:%s in service:%s.(add role)' %
                               (host_name, service_name))
            except Exception as e:
                self.log.error(e)
                return False
        # storage parameters in context
        context = Context(hackathon_id=hackathon_id,
                          request_id=result.request_id,
                          service_name=service_name,
                          role_name=host_name,
                          deployment_name=service_name,
                          deployment_slot=deployment_slot,
                          host_name=host_name)
        # start schedule
        self.sche.add_once('docker_host_manager',
                           'check_vm_status',
                           context=context,
                           minutes=5)
        return True
 def __generate_base_context(self, azure_key_id, experiment_id,
                             template_unit):
     return Context(azure_key_id=azure_key_id,
                    experiment_id=experiment_id,
                    template_unit=template_unit)
    def start_virtual_machine(self, context):
        """
        0. Prerequisites: a. virtual machine exist in both azure and database
                          b. input parameters are correct
        :param context : contains azure_key_id, experiment_id, template_unit

        :return:
        """
        commit_azure_log(context.experiment_id,
                         ALOperation.START_VIRTUAL_MACHINE, ALStatus.START)
        cloud_service_name = context.template_unit.get_cloud_service_name()
        deployment_slot = context.template_unit.get_deployment_slot()
        deployment_name = self.azure_adapter.get_deployment_name(
            cloud_service_name, deployment_slot)
        deployment = self.azure_adapter.get_deployment_by_name(
            cloud_service_name, deployment_name)
        virtual_machine_name = '%s-%d' % (
            context.template_unit.get_virtual_machine_name(),
            context.experiment_id)
        status = self.azure_adapter.get_virtual_machine_instance_status(
            deployment, virtual_machine_name)
        if status == AVMStatus.READY_ROLE:
            db_status = get_azure_virtual_machine_status(
                cloud_service_name, deployment_name, virtual_machine_name)
            if db_status == status:
                m = '%s [%s] started by %s before' % (
                    AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE, virtual_machine_name,
                    AZURE_FORMATION)
                commit_azure_log(context.experiment_id,
                                 ALOperation.START_VIRTUAL_MACHINE,
                                 ALStatus.END, m, 1)
            else:
                m = '%s [%s] started but not by %s before' % (
                    AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE, virtual_machine_name,
                    AZURE_FORMATION)
                self.__start_virtual_machine_helper(context.experiment_id,
                                                    context.template_unit)
                commit_azure_log(context.experiment_id,
                                 ALOperation.START_VIRTUAL_MACHINE,
                                 ALStatus.END, m, 2)
            self.log.debug(m)
        else:
            try:
                result = self.azure_adapter.start_virtual_machine(
                    cloud_service_name, deployment_name, virtual_machine_name)
            except Exception as e:
                m = '%s [%s] %s' % (AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE,
                                    virtual_machine_name, e.message)
                commit_azure_log(context.experiment_id,
                                 ALOperation.START_VIRTUAL_MACHINE,
                                 ALStatus.FAIL, 0)
                self.log.error(e)
                self.log.error(m)
                return False

            # query async operation status
            query_context = Context(
                request_id=result.id,
                azure_key_id=context.azure_key_id,
                feature='azure_vm_service',
                true_method='start_virtual_machine_async_true',
                false_method='start_virtual_machine_async_false',
                method_args_context=context)
            self.scheduler.add_once(feature='azure_service',
                                    method='query_async_operation_status',
                                    context=query_context,
                                    seconds=3)
        return True
 def stop_virtual_machine(self, context):
     """
     0. Prerequisites: a. virtual machine exist in both azure and database
                       b. input parameters are correct
     :param context :
                     azure_key_id,
                     experiment_id,
                     template_unit,
                     action: AVMStatus.STOPPED or AVMStatus.STOPPED_DEALLOCATED
     :return:
     """
     commit_azure_log(context.experiment_id,
                      ALOperation.STOP_VIRTUAL_MACHINE, ALStatus.START)
     # need_status: AVMStatus.STOPPED_VM or AVMStatus.STOPPED_DEALLOCATED
     need_status = AVMStatus.STOPPED_VM if context.action == AVMStatus.STOPPED else AVMStatus.STOPPED_DEALLOCATED
     cloud_service_name = context.template_unit.get_cloud_service_name()
     deployment_slot = context.template_unit.get_deployment_slot()
     deployment_name = self.azure_adapter.get_deployment_name(
         cloud_service_name, deployment_slot)
     deployment = self.azure_adapter.get_deployment_by_name(
         cloud_service_name, deployment_name)
     virtual_machine_name = '%s-%d' % (
         context.template_unit.get_virtual_machine_name(),
         context.experiment_id)
     now_status = self.azure_adapter.get_virtual_machine_instance_status(
         deployment, virtual_machine_name)
     if need_status == AVMStatus.STOPPED_VM and now_status == AVMStatus.STOPPED_DEALLOCATED:
         m = '%s [%s] need status %s but now status %s' % (
             AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE, virtual_machine_name,
             AVMStatus.STOPPED_VM, AVMStatus.STOPPED_DEALLOCATED)
         commit_azure_log(context.experiment_id,
                          ALOperation.STOP_VIRTUAL_MACHINE, ALStatus.FAIL,
                          m, 1)
         self.log.error(m)
         return False
     elif need_status == now_status:
         db_status = get_azure_virtual_machine_status(
             cloud_service_name, deployment_name, virtual_machine_name)
         if db_status == need_status:
             m = '%s [%s] %s and by %s before' % (
                 AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE, virtual_machine_name,
                 need_status, AZURE_FORMATION)
             commit_azure_log(context.experiment_id,
                              ALOperation.STOP_VIRTUAL_MACHINE,
                              ALStatus.END, m, 1)
         else:
             m = '%s [%s] %s but not by %s before' % (
                 AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE, virtual_machine_name,
                 need_status, AZURE_FORMATION)
             self.__stop_virtual_machine_helper(context.experiment_id,
                                                context.template_unit,
                                                need_status)
             commit_azure_log(context.experiment_id,
                              ALOperation.STOP_VIRTUAL_MACHINE,
                              ALStatus.END, m, 2)
         self.log.debug(m)
     else:
         try:
             result = self.azure_adapter.stop_virtual_machine(
                 cloud_service_name, deployment_name, virtual_machine_name,
                 context.action)
         except Exception as e:
             m = '%s [%s] %s' % (AZURE_RESOURCE_TYPE.VIRTUAL_MACHINE,
                                 virtual_machine_name, e.message)
             commit_azure_log(context.experiment_id,
                              ALOperation.STOP_VIRTUAL_MACHINE,
                              ALStatus.FAIL, 0)
             self.log.error(m)
             self.log.error(e)
             return False
         # query async operation status
         method_args_context = self.__generate_base_context(
             context.azure_key_id, context.experiment_id,
             context.template_unit)
         method_args_context.need_status = need_status
         query_context = Context(
             request_id=result.id,
             azure_key_id=context.azure_key_id,
             feature='azure_vm_service',
             true_method='stop_virtual_machine_async_true',
             false_method='stop_virtual_machine_async_false',
             method_args_context=method_args_context)
         self.scheduler.add_once(feature='azure_service',
                                 method='query_async_operation_status',
                                 context=query_context,
                                 seconds=3)
     return True
Example #11
0
    def __setup_virtual_machine_done(self, sctx):
        try:
            self.log.debug("azure virtual environment %d vm setup done" %
                           sctx.current_job_index)
            ctx = sctx.job_ctxs[sctx.current_job_index]

            # update the status of virtual environment
            expr = Experiment.objects(id=sctx.experiment_id).first()
            ve = expr.virtual_environments[sctx.current_job_index]
            adapter = self.__get_adapter_from_sctx(sctx, VirtualMachineAdapter)

            ve.status = VEStatus.RUNNING
            expr.save()

            self._on_virtual_environment_success(
                Context(experiment_id=expr.id))

            azure_resource = AzureVirtualMachine(
                name=ctx.virtual_machine_name,
                label=ctx.virtual_machine_label,
                dns="%s.chinacloudapp.cn" % ctx.cloud_service_name,
                end_points=[])
            # todo record AzureDeployment, AzureCloudService and so on in db for roll back

            vm_role = adapter.get_virtual_machine_role(
                ctx.cloud_service_name, ctx.deployment_name,
                ctx.virtual_machine_name)

            if (not vm_role) or (not vm_role.instance_endpoints):
                self.log.warn(
                    "unable to find vm %s, cannot update virtual env config like guacamole"
                    % ctx.virtual_machine_name)
            else:
                for endpoint in vm_role.instance_endpoints:
                    azure_resource.public_ip = endpoint.vip
                    if endpoint.name == ctx.remote_endpoint_name:  # endpoint for remote desktop
                        ve.remote_provider = VERemoteProvider.Guacamole
                        ve.remote_paras = get_remote_parameters(
                            ctx.raw_system_config, ctx.remote,
                            ctx.virtual_machine_name, endpoint.vip,
                            endpoint.public_port)
                    else:
                        try:
                            aep = self.__get_persistable_endpoint(
                                endpoint, ctx.raw_network_config)
                            azure_resource.end_points.append(aep)
                        except Exception as e:
                            self.log.error(e)

            ve.azure_resource = azure_resource
            azure_resource.save()
            expr.save()

            self.log.debug(
                "azure virtual environment %d vm success callback done, step to next"
                % sctx.current_job_index)
            # step to config next unit
            sctx.current_job_index += 1
            self.__schedule_setup(sctx)
        except Exception as e:
            self.log.error(
                "azure virtual environment %d failed on vm_done: %r" %
                (sctx.current_job_index, e.message))
            self._on_virtual_environment_failed(sctx)
Example #12
0
    def start_vm(self, resource_id, azure_key, template_units,
                 virtual_environments):
        """setup the resources needed by the template unit and start the virtual machine

        this will create the missed VirtualMachine, CloudService and Storages
        this function is not blocked, it will run in the background and return immediatly

        :param resouce_id: a integer that can indentify the creation of azure resource, is reusable to checkout created virtual machine name
        :param template_units: the azure template units, contains the data need by azure formation
        :param azure_key: the azure_key object, use to access azure
        :param virtual_environments: the virtual envrionments associated with this setup NOTE: this is a workaround
        """
        # the setup of each unit must be SERLIALLY EXECUTED
        # to avoid the creation of same resource in same time
        # TODO: we still have't avoid the parrallel excution of the setup of same template
        job_ctxs = []
        ctx = Context(
            job_ctxs=job_ctxs,
            current_job_index=0,
            resource_id=resource_id,
            subscription_id=azure_key.subscription_id,
            pem_url=azure_key.pem_url,
            management_host=azure_key.management_host,

            # remote_created is used to store the resources we create we create remote
            # so we can do rollback
            # TODO: if the user create a virtual machine with vm_image, we have to config the network of it
            #       but so far we have no way to rollback the network settings of it
            remote_created=[])

        assert len(template_units) == len(virtual_environments)

        for i in xrange(0, len(template_units)):
            unit = template_units[i]
            ve = virtual_environments[i]

            name = self.get_virtual_machine_name(
                unit.get_virtual_machine_name(), resource_id)

            # construct current virutal envrionment's context
            job_ctxs.append(
                Context(
                    cloud_service_name=unit.get_cloud_service_name(),
                    cloud_service_label=unit.get_cloud_service_label(),
                    cloud_service_host=unit.get_cloud_service_location(),
                    storage_account_name=unit.get_storage_account_name(),
                    storage_account_description=unit.
                    get_storage_account_description(),
                    storage_account_label=unit.get_storage_account_label(),
                    storage_account_location=unit.get_storage_account_location(
                    ),
                    virtual_machine_name=name,
                    virtual_machine_label=unit.get_virtual_machine_label(),
                    deployment_name=unit.get_deployment_name(),
                    deployment_slot=unit.get_deployment_slot(),
                    system_config=unit.get_system_config(),
                    raw_system_config=unit.get_raw_system_config(),
                    os_virtual_hard_disk=unit.get_os_virtual_hard_disk(),
                    virtual_machine_size=unit.get_virtual_machine_size(),
                    image_name=unit.get_image_name(),
                    raw_network_config=unit.get_raw_network_config(),
                    is_vm_image=unit.is_vm_image(),
                    remote=unit.get_remote(),
                    endpoint_name=unit.get_remote_port_name(),

                    # NOTE: ONLY callback purpose functions can depend on virutal_environment_id
                    virtual_environment_id=ve.id,

                    # TODO: this part of info should move to super context
                    subscription_id=azure_key.subscription_id,
                    pem_url=azure_key.pem_url,
                    management_host=azure_key.management_host))

        # execute from first job context
        self.__schedule_setup(ctx)