Beispiel #1
0
    def creating(self, model: Zone):
        defer(model.save)

        with self.vmware.client_session() as vmware_client:
            datacenter = self.vmware.get_datacenter(vmware_client,
                                                    model.region.datacenter)

            datastore = self.vmware.get_datastore(vmware_client,
                                                  model.vm_datastore,
                                                  datacenter)
            if datastore is None:
                model.error_message = "Could not find VMWare datastore."
                return

            cluster = self.vmware.get_cluster(vmware_client, model.vm_cluster,
                                              datacenter)
            if cluster is None:
                model.error_message = "Could not find VMWare cluster."
                return

            if model.vm_folder is not None:
                folder = self.vmware.get_folder(vmware_client, model.vm_folder,
                                                datacenter)
                if folder is None:
                    model.error_message = "Could not find VMWare VM & Templates folder."
                    return

        model.state = ResourceState.Created
Beispiel #2
0
    def find_best_zone(self, vmware_client, datacenter, region, model):
        """
        Currently this just finds a zone that can host the instances and returns that.
        We may want a better way to balance instances across zones in the future
        """
        zones = Zone.list(label_selector=REGION_LABEL + '=' + str(region.name))

        for zone in zones:
            if zone.schedulable is False:
                continue
            if self.can_zone_host(vmware_client, datacenter, zone, model):
                return zone

        return None
Beispiel #3
0
    def create(self):
        """Create a volume
        ---
        post:
            description: Create a volume
            tags:
                - compute
                - volume
            requestBody:
                description: Volume to create
            responses:
                200:
                    description: The created volume
        """
        request: RequestCreateVolume = cherrypy.request.model
        project: Project = cherrypy.request.project

        volume = Volume.get(project, request.name)
        if volume is not None:
            raise cherrypy.HTTPError(
                409, 'A volume with the requested name already exists.')

        zone = Zone.get(request.zone_name)
        if zone is None:
            raise cherrypy.HTTPError(
                404, 'A zone with the requested name does not exist.')
        if zone.state != ResourceState.Created:
            raise cherrypy.HTTPError(
                400,
                'Can only create a volume with a zone in the following state: {0}'
                .format(ResourceState.Created.value))

        quota: ProjectQuota = ProjectQuota.get(project.name)
        used_disk = quota.used_disk + request.size
        if quota.disk != -1:
            if used_disk > quota.disk:
                raise QuotaError("Disk", request.size, quota.used_disk,
                                 quota.disk)

        quota.used_disk = used_disk
        quota.save()

        volume = Volume()
        volume.project = project
        volume.name = request.name
        volume.zone = zone
        volume.size = request.size
        volume.create()

        return ResponseVolume.from_database(volume)
Beispiel #4
0
    def can_delete(self, model):
        # These resources need the region to exist to successfully delete
        zones = Zone.list(label_selector=REGION_LABEL + "=" + model.name)
        if len(zones) > 0:
            return False

        images = Image.list_all(label_selector=REGION_LABEL + "=" + model.name)
        if len(images) > 0:
            return False

        instances = Instance.list_all(label_selector=REGION_LABEL + "=" + model.name)
        if len(instances) > 0:
            return False

        return True
Beispiel #5
0
    def list(self, image_name, region_name, zone_name, limit: int, marker: uuid.UUID):
        """List instances
        ---
        get:
            description: List instances
            tags:
                - compute
                - instance
            responses:
                200:
                    description: List of instances
        """
        kwargs = {
            'project': cherrypy.request.project,
            'label_selector': [],
        }

        if image_name is not None:
            image: Image = Image.get(cherrypy.request.project, image_name)
            if image is None:
                raise cherrypy.HTTPError(404, "An image with the requested name does not exist.")
            kwargs['label_selector'].append(IMAGE_LABEL + '=' + image.name)

        if region_name is not None:
            region: Region = Region.get(region_name)
            if region is None:
                raise cherrypy.HTTPError(404, "A region with the requested name does not exist.")
            kwargs['label_selector'].append(REGION_LABEL + '=' + region.name)

        if zone_name is not None:
            zone: Zone = Zone.get(zone_name)
            if zone is None:
                raise cherrypy.HTTPError(404, 'A zone with the requested name does not exist.')
            kwargs['label_selector'].append(ZONE_LABEL + '=' + zone.name)

        if len(kwargs['label_selector']) > 0:
            kwargs['label_selector'] = ",".join(kwargs['label_selector'])
        else:
            del kwargs['label_selector']

        return self.paginate(Instance, ResponseInstance, limit, marker, **kwargs)
Beispiel #6
0
 def zone(self):
     zone_name = self.zone_name
     if zone_name is None:
         return None
     return Zone.get(zone_name)
Beispiel #7
0
    def run(self, args) -> int:
        cache_client.connect(url=args.redis_url)

        if args.kube_config != "" or args.kube_master != "":
            self.logger.info("Using kube-config configuration")
            Configuration.set_default(Configuration())
            if args.kube_config != "":
                config.load_kube_config(config_file=args.kube_config)
            if args.kube_master != "":
                Configuration._default.host = args.kube_master

        else:
            self.logger.info("Using in-cluster configuration")
            config.load_incluster_config()

        while True:
            try:
                client.CoreV1Api().list_namespace()
                break
            except urllib3.exceptions.HTTPError as e:
                self.logger.error("Error connecting to the Kubernetes API. Trying again in 5 seconds. Error: " + str(e))
                time.sleep(5)

        old_json_encoder = json.JSONEncoder.default

        def json_encoder(self, o):  # pragma: no cover
            if isinstance(o, uuid.UUID):
                return str(o)
            if isinstance(o, arrow.Arrow):
                return o.isoformat()
            if isinstance(o, ipaddress.IPv4Network):
                return str(o)
            if isinstance(o, ipaddress.IPv4Address):
                return str(o)
            if isinstance(o, enum.Enum):
                return o.value
            if isinstance(o, datetime.datetime):
                return str(o.isoformat())

            return old_json_encoder(self, o)

        json.JSONEncoder.default = json_encoder

        self.logger.info("Creating CRDs")
        IAMSystemRole.create_crd()
        IAMSystemRole.wait_for_crd()
        IAMProjectRole.create_crd()
        IAMProjectRole.wait_for_crd()

        IAMPolicy.create_crd()
        IAMPolicy.wait_for_crd()
        IAMPolicy.create_system_policy()

        SystemServiceAccount.create_crd()
        SystemServiceAccount.wait_for_crd()
        ProjectServiceAccount.create_crd()
        ProjectServiceAccount.wait_for_crd()

        IAMSystemRole.create_default_roles()
        SystemServiceAccount.create_admin_sa()

        ProjectQuota.create_crd()
        ProjectQuota.wait_for_crd()

        Region.create_crd()
        Region.wait_for_crd()
        Zone.create_crd()
        Zone.wait_for_crd()
        Network.create_crd()
        Network.wait_for_crd()
        NetworkPort.create_crd()
        NetworkPort.wait_for_crd()
        Image.create_crd()
        Image.wait_for_crd()
        Flavor.create_crd()
        Flavor.wait_for_crd()
        Volume.create_crd()
        Volume.wait_for_crd()
        Instance.create_crd()
        Instance.wait_for_crd()
        Keypair.create_crd()
        Keypair.wait_for_crd()
        self.logger.info("CRDs have been created")

        self.menu_url = args.menu_url
        self.vmware = VMWare(args.vcenter_host, args.vcenter_port, args.vcenter_username, args.vcenter_password)

        self.leader_elector = LeaderElector("sandwich-controller", "kube-system", self.on_started_leading,
                                            self.on_stopped_leading)
        self.leader_elector.start()

        return 0
Beispiel #8
0
    def create(self):
        """Create an instance
        ---
        post:
            description: Create an instance
            tags:
                - compute
                - instance
            requestBody:
                description: Instance to create
            responses:
                200:
                    description: The created instance
        """
        request: RequestCreateInstance = cherrypy.request.model
        project: Project = cherrypy.request.project

        instance = Instance.get(project, request.name)
        if instance is not None:
            raise cherrypy.HTTPError(409, 'An instance with the requested name already exists.')

        region = Region.get(request.region_name)
        if region is None:
            raise cherrypy.HTTPError(404, 'A region with the requested name does not exist.')
        if region.state != ResourceState.Created:
            raise cherrypy.HTTPError(400, 'Can only create a instance with a region in the following state: {0}'.format(
                ResourceState.Created.value))

        zone = None
        if request.zone_name is not None:
            zone = Zone.get(request.zone_name)
            if zone is None:
                raise cherrypy.HTTPError(404, 'A zone with the requested name does not exist.')
            if zone.region.name != region.name:
                raise cherrypy.HTTPError(409, 'The requested zone is not within the requested region')
            if zone.state != ResourceState.Created:
                raise cherrypy.HTTPError(400,
                                         'Can only create a instance with a zone in the following state: {0}'.format(
                                             ResourceState.Created.value))

        network = Network.get(request.network_name)
        if network is None:
            raise cherrypy.HTTPError(404, 'A network with the requested name does not exist.')
        if network.region.name != region.name:
            raise cherrypy.HTTPError(409, 'The requested network is not within the requested region')
        if network.state != ResourceState.Created:
            raise cherrypy.HTTPError(400,
                                     'Can only create a instance with a network in the following state: {0}'.format(
                                         ResourceState.Created.value))

        # TODO: User inputs image url instead of id
        # projectId/imageId
        image: Image = Image.get(project, request.image_name)
        if image is None:
            raise cherrypy.HTTPError(404, 'An image with the requested name does not exist.')
        if image.region.name != region.name:
            raise cherrypy.HTTPError(409, 'The requested image is not within the requested region')
        if image.state != ResourceState.Created:
            raise cherrypy.HTTPError(400, 'Can only create a instance with a image in the following state: {0}'.format(
                ResourceState.Created.value))

        flavor: Flavor = Flavor.get(request.flavor_name)
        if flavor is None:
            raise cherrypy.HTTPError(404, 'A flavor with the requested name does not exist.')

        keypairs = []
        for keypair_name in request.keypair_names:
            keypair = Keypair.get(project, keypair_name)
            if keypair is None:
                raise cherrypy.HTTPError(404,
                                         'A keypair with the requested name of {0} does not exist.'.format(
                                             keypair_name))
            keypairs.append(keypair)

        # TODO: User inputs service account email instead of id
        # Only project service accounts are allowed
        if request.service_account_name is not None:
            service_account = ProjectServiceAccount.get(project, request.service_account_name)
            if service_account is None:
                raise cherrypy.HTTPError(404, 'A service account with the requested name of {0} does not exist.'.format(
                    request.service_account_name))
        else:
            service_account = ProjectServiceAccount.get(project, 'default')
            if service_account is None:
                raise cherrypy.HTTPError(500, 'Could not find a default service account to attach to the instance.')

        quota: ProjectQuota = ProjectQuota.get(project.name)
        used_vcpu = quota.used_vcpu + flavor.vcpus
        used_ram = quota.used_ram + flavor.ram
        requested_disk = flavor.disk
        if request.disk is not None:
            requested_disk = request.disk
        used_disk = quota.used_disk + requested_disk

        if quota.vcpu != -1:
            if used_vcpu > quota.vcpu:
                raise QuotaError("VCPU", flavor.vcpus, quota.used_vcpu, quota.vcpu)

        if quota.ram != -1:
            if used_ram > quota.ram:
                raise QuotaError("Ram", flavor.ram, quota.used_ram, quota.ram)

        if quota.disk != -1:
            if used_disk > quota.disk:
                raise QuotaError("Disk", requested_disk, quota.used_disk, quota.disk)

        quota.used_vcpu = used_vcpu
        quota.used_ram = used_ram
        quota.used_disk = used_disk
        quota.save()

        network_port = NetworkPort()
        network_port.name = str(uuid.uuid4())  # We don't care about the network port's name, just that it's unique
        network_port.project = project
        network_port.network = network
        network_port.create()

        instance = Instance()
        instance.name = request.name
        instance.project = project
        instance.region = region
        if zone is not None:
            instance.zone = zone
        instance.image = image
        instance.service_account = service_account
        instance.network_port = network_port
        instance.keypairs = keypairs
        if request.user_data is not None:
            if len(request.user_data) > 0:
                instance.user_data = request.user_data
        for k, v in request.tags.items():
            instance.add_tag(k, v)

        instance.flavor = flavor
        if request.disk is not None:
            instance.disk = request.disk
        if request.initial_volumes is not None:
            initial_volumes = []
            for initial_volume in request.initial_volumes:
                initial_volumes.append(initial_volume.to_native())
            instance.initial_volumes = initial_volumes

        instance.create()

        return ResponseInstance.from_database(instance)
Beispiel #9
0
 def created(self, model: Zone):
     region = model.region
     if region.state == ResourceState.Deleting:
         model.delete()
         return