208 lines
6.6 KiB
Python
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]
|