rubick/ostack_validator/resource.py
2013-10-17 13:59:19 +04:00

208 lines
6.6 KiB
Python

import glob
import os.path
import json
from ostack_validator.common import Error, Version
class Resource(object):
HOST = 'host'
FILE = 'file'
DIRECTORY = 'directory'
SERVICE = 'service'
def __init__(self, name):
super(Resource, self).__init__()
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return '<%s name=%s>' % (str(self.__class__).split('.')[-1], self.name)
def get_contents(self):
raise Error('Not implemented')
class ResourceLocator(object):
def find_resource(self, resource_type, name, host=None, **kwargs):
return None
class HostResource(Resource):
def __init__(self, name, resource_locator, interfaces=[]):
super(HostResource, self).__init__(name)
self.resource_locator = resource_locator
self.interfaces = interfaces
def find_resource(self, resource_type, name=None, **kwargs):
return (
self.resource_locator.find_resource(
resource_type,
name,
host=self,
**kwargs)
)
class DirectoryResource(Resource):
def __init__(self, name, owner=None, group=None, permissions=None):
super(DirectoryResource, self).__init__(name)
self.owner = owner
self.group = group
self.permissions = permissions
class FileResource(Resource):
def __init__(self, name, path, owner=None, group=None, permissions=None):
super(FileResource, self).__init__(name)
self.path = path
self.owner = owner
self.group = group
self.permissions = permissions
def get_contents(self):
with open(self.path) as f:
return f.read()
class ServiceResource(Resource):
def __init__(self, name, version, metadata={}):
super(ServiceResource, self).__init__(name)
self.version = Version(version)
self.metadata = metadata
class FilesystemSnapshot(object):
def __init__(self, path):
super(FilesystemSnapshot, self).__init__()
self.path = path
self.basedir = os.path.join(os.path.dirname(self.path), 'root')
self._parse_snapshot()
def get_resource(self, path):
if path in self._resources:
return self._resources[path]
return None
def _parse_snapshot(self):
self._resources = {}
if not os.path.isfile(self.path):
return
with open(self.path) as f:
for line in f.readlines():
line = line.lstrip()
if line == '' or line.startswith('#'):
continue
resource_type = line.split('|')[0]
if resource_type == 'dir':
source_path, owner, group, permissions = line.split(
'|')[1:]
self._resources[source_path] = DirectoryResource(
source_path,
owner=owner,
group=group,
permissions=permissions)
elif resource_type == 'file':
source_path, local_path, owner, group, permissions = line.split('|')[1:]
self._resources[source_path] = FileResource(
os.path.basename(source_path),
path=os.path.join(self.basedir,
local_path),
owner=owner,
group=group,
permissions=permissions)
else:
self.logger.warn(
'Unknown resource "%s" in line "%s"' %
(resource_type, line))
class ConfigSnapshotResourceLocator(object):
def __init__(self, basedir):
super(ConfigSnapshotResourceLocator, self).__init__()
self.basedir = basedir
if not os.path.isdir(self.basedir):
raise Error('Invalid argument: base directory does not exist')
self._services = None
self._filesystem_snapshots = {}
def find_resource(self, resource_type, name=None, host=None, **kwargs):
if resource_type == Resource.HOST:
if name:
host_path = os.path.join(self.basedir, name)
if not os.path.isdir(host_path):
return None
return HostResource(name, self)
else:
return (
[HostResource(os.path.basename(host_path), self)
for host_path in glob.glob(os.path.join(self.basedir, '*')) if os.path.isdir(host_path)]
)
if resource_type == Resource.FILE:
if not host:
raise Error('Invalid argument: "host" need to be specified')
if isinstance(host, HostResource):
host = host.name
if name:
return self._get_filesystem_snapshot(host).get_resource(name)
else:
return []
elif resource_type == Resource.SERVICE:
if not host:
raise Error('Invalid argument: "host" need to be specified')
if isinstance(host, HostResource):
host = host.name
self._ensure_services_loaded()
if name:
if name in self._services:
return self._services[host][name]
else:
return None
else:
return self._services[host].values()
else:
return None
def _ensure_services_loaded(self):
if self._services:
return
self._services = {}
for host_path in glob.glob(os.path.join(self.basedir, '*')):
if not os.path.isdir(host_path):
continue
services_json_path = os.path.join(host_path, 'services.json')
if not os.path.isfile(services_json_path):
continue
host_name = os.path.basename(host_path)
self._services[host_name] = {}
with open(services_json_path) as f:
for service_name, metadata in json.loads(f.read()).items():
version = metadata.pop('version')
self._services[host_name][service_name] = ServiceResource(
service_name, str(version), metadata)
def _get_filesystem_snapshot(self, host):
if not host in self._filesystem_snapshots:
self._filesystem_snapshots[host] = FilesystemSnapshot(
os.path.join(self.basedir, host, 'filesystem'))
return self._filesystem_snapshots[host]