zun/zun/db/etcd/models.py

293 lines
7.4 KiB
Python

# Copyright 2016 IBM, Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
etcd models
"""
import etcd
from oslo_serialization import jsonutils as json
from zun.common import exception
import zun.db.etcd as db
from zun import objects
class Base(object):
def __setitem__(self, key, value):
setattr(self, key, value)
def __getitem__(self, key):
return getattr(self, key)
def get(self, key):
return getattr(self, key)
def etcd_path(self, sub_path):
return self.path + '/' + sub_path
def as_dict(self):
d = {}
for f in self._fields:
d[f] = getattr(self, f, None)
return d
def path_already_exist(self, client, path):
try:
client.read(path)
except etcd.EtcdKeyNotFound:
return False
return True
def update(self, values):
"""Make the model object behave like a dict."""
for k, v in values.items():
setattr(self, k, v)
def save(self, session=None):
if session is None:
session = db.api.get_connection()
client = session.client
path = self.etcd_path(self.uuid)
if self.path_already_exist(client, path):
raise exception.ResourceExists(name=getattr(self, '__class__'))
client.write(path, json.dump_as_bytes(self.as_dict()))
return
def items(self):
"""Make the model object behave like a dict."""
return self.as_dict().items()
def iteritems(self):
"""Make the model object behave like a dict."""
return self.as_dict().items()
def keys(self):
"""Make the model object behave like a dict."""
return [key for key, value in self.iteritems()]
class ZunService(Base):
"""Represents health status of various zun services"""
_path = '/zun_services'
_fields = objects.ZunService.fields.keys()
def __init__(self, service_data):
self.path = ZunService.path()
for f in ZunService.fields():
setattr(self, f, None)
self.id = 1
self.disabled = False
self.forced_down = False
self.report_count = 0
self.update(service_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields
def save(self, session=None):
if session is None:
session = db.api.get_connection()
client = session.client
path = self.etcd_path(self.host + '_' + self.binary)
if self.path_already_exist(client, path):
raise exception.ZunServiceAlreadyExists(host=self.host,
binary=self.binary)
client.write(path, json.dump_as_bytes(self.as_dict()))
return
class Container(Base):
"""Represents a container."""
_path = '/containers'
_fields = objects.Container.fields.keys()
def __init__(self, container_data):
self.path = Container.path()
for f in Container.fields():
setattr(self, f, None)
self.id = 1
self.update(container_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields
class Image(Base):
"""Represents a container image."""
_path = '/images'
_fields = objects.Image.fields.keys()
def __init__(self, image_data):
self.path = Image.path()
for f in Image.fields():
setattr(self, f, None)
self.id = 1
self.update(image_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields
class ResourceClass(Base):
"""Represents a resource class."""
_path = '/resource_classes'
_fields = objects.ResourceClass.fields.keys()
def __init__(self, resource_class_data):
self.path = ResourceClass.path()
for f in ResourceClass.fields():
setattr(self, f, None)
self.id = 1
self.update(resource_class_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields
class Capsule(Base):
"""Represents a capsule."""
_path = '/capsules'
_fields = objects.Capsule.fields.keys()
def __init__(self, capsule_data):
self.path = Capsule.path()
for f in Capsule.fields():
setattr(self, f, None)
self.id = 1
self.update(capsule_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields
class ComputeNode(Base):
"""Represents a compute node. """
_path = '/compute_nodes'
# NOTE(kiennt): Use list(fields) instead of fields.keys()
# because in Python 3, the dict.keys() method
# returns a dictionary view object, which acts
# as a set. To do the replacement, _fields should
# be a list.
_fields = list(objects.ComputeNode.fields)
def __init__(self, compute_node_data):
self.path = ComputeNode.path()
for f in ComputeNode.fields():
setattr(self, f, None)
self.cpus = 0
self.cpu_used = 0
self.mem_used = 0
self.mem_total = 0
self.mem_free = 0
self.mem_available = 0
self.total_containers = 0
self.stopped_containers = 0
self.paused_containers = 0
self.running_containers = 0
self.update(compute_node_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
# NOTE(kiennt): The pci_device_pools field in object maps to the
# pci_stats field in the database. Therefore, need
# replace these fields.
for index, value in enumerate(cls._fields):
if value == 'pci_device_pools':
cls._fields.pop(index)
cls._fields.insert(index, 'pci_stats')
break
return cls._fields
def save(self, session=None):
if session is None:
session = db.api.get_connection()
client = session.client
path = self.etcd_path(self.uuid)
if self.path_already_exist(client, path):
raise exception.ComputeNodeAlreadyExists(
field='UUID', value=self.uuid)
client.write(path, json.dump_as_bytes(self.as_dict()))
return
class PciDevice(Base):
"""Represents a PciDevice. """
_path = '/pcidevices'
_fields = objects.PciDevice.fields.keys()
def __init__(self, pci_data):
self.path = PciDevice.path()
for f in PciDevice.fields():
setattr(self, f, None)
self.id = 1
self.update(pci_data)
@classmethod
def path(cls):
return cls._path
@classmethod
def fields(cls):
return cls._fields