diff --git a/windc/etc/windc-api-paste.ini b/windc/etc/windc-api-paste.ini index 46e1299bb..7c0deee89 100644 --- a/windc/etc/windc-api-paste.ini +++ b/windc/etc/windc-api-paste.ini @@ -1,3 +1,30 @@ +[DEFAULT] +# Show more verbose log output (sets INFO log level output) +verbose = True +# Show debugging output in logs (sets DEBUG log level output) +debug = True +# Address to bind the server to +bind_host = 0.0.0.0 +# Port the bind the server to +bind_port = 8082 +# Log to this file. Make sure the user running skeleton-api has +# permissions to write to this file! +log_file = /tmp/api.log +# Orchestration Adapter Section +# +#provider - Cloud provider to use (openstack, amazon, dummy) +provider = openstack + +# Heat specific parameters +#heat_url - url for the heat service +# [auto] - find in the keystone +heat_url = auto + +#heat_api_version - version of the API to use +# +heat_api_version = 1 + + [pipeline:windc-api] pipeline = apiv1app # NOTE: use the following pipeline for keystone diff --git a/windc/etc/windc/api-paste.ini b/windc/etc/windc/api-paste.ini deleted file mode 100644 index 46e1299bb..000000000 --- a/windc/etc/windc/api-paste.ini +++ /dev/null @@ -1,26 +0,0 @@ -[pipeline:windc-api] -pipeline = apiv1app -# NOTE: use the following pipeline for keystone -#pipeline = authtoken context apiv1app - -[app:apiv1app] -paste.app_factory = windc.common.wsgi:app_factory -windc.app_factory = windc.api.v1.router:API - -[filter:context] -paste.filter_factory = windc.common.wsgi:filter_factory -windc.filter_factory = windc.common.context:ContextMiddleware - -[filter:authtoken] -paste.filter_factory = keystone.middleware.auth_token:filter_factory -auth_host = 172.18.67.57 -auth_port = 35357 -auth_protocol = http -auth_uri = http://172.18.67.57:5000/v2.0/ -admin_tenant_name = service -admin_user = windc -admin_password = 000 - -[filter:auth-context] -paste.filter_factory = windc.common.wsgi:filter_factory -windc.filter_factory = keystone.middleware.balancer_auth_token:KeystoneContextMiddleware diff --git a/windc/etc/windc/windc.conf b/windc/etc/windc/windc.conf deleted file mode 100644 index 3f1381b59..000000000 --- a/windc/etc/windc/windc.conf +++ /dev/null @@ -1,34 +0,0 @@ -[DEFAULT] -# Show more verbose log output (sets INFO log level output) -verbose = True - -# Show debugging output in logs (sets DEBUG log level output) -debug = True - -# Address to bind the server to -bind_host = 0.0.0.0 - -# Port the bind the server to -bind_port = 8082 - -# Log to this file. Make sure the user running skeleton-api has -# permissions to write to this file! -log_file = /tmp/api.log - -[pipeline:windc-api] -pipeline = versionnegotiation context apiv1app - -[pipeline:versions] -pipeline = versionsapp - -[app:versionsapp] -paste.app_factory = windc.api.versions:app_factory - -[app:apiv1app] -paste.app_factory = windc.api.v1:app_factory - -[filter:versionnegotiation] -paste.filter_factory = windc.api.middleware.version_negotiation:filter_factory - -[filter:context] -paste.filter_factory = openstack.common.middleware.context:filter_factory diff --git a/windc/tests/manual/createDataCenter.sh b/windc/tests/manual/createDataCenter.sh new file mode 100755 index 000000000..2c1e53152 --- /dev/null +++ b/windc/tests/manual/createDataCenter.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +URL=http://localhost:8082/foo/datacenters +curl -v -H "Content-Type: application/json" -X POST -d@createDataCenterParameters$1 $URL diff --git a/windc/tests/manual/createDataCenterParameters b/windc/tests/manual/createDataCenterParameters new file mode 100644 index 000000000..6200231da --- /dev/null +++ b/windc/tests/manual/createDataCenterParameters @@ -0,0 +1,7 @@ +{ +"name": "Test Data Center 2", +"type": "SingleZone", +"version":"1.1", +"KMS":"172.16.1.2", +"WSUS":"172.16.1.3" +} diff --git a/windc/tests/manual/createService.sh b/windc/tests/manual/createService.sh new file mode 100755 index 000000000..7a508884f --- /dev/null +++ b/windc/tests/manual/createService.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +URL=http://localhost:8082/foo/datacenters/$1/services +curl -v -H "Content-Type: application/json" -X POST -d@createServiceParameters$2 $URL diff --git a/windc/tests/manual/createServiceParameters b/windc/tests/manual/createServiceParameters new file mode 100644 index 000000000..6e9817c93 --- /dev/null +++ b/windc/tests/manual/createServiceParameters @@ -0,0 +1,8 @@ +{ +"type": "active_directory_service", +"zones": ["zone1"], +"domain": "ACME.cloud", +"AdminUser": "Admin", +"AdminPassword": "StrongPassword", +"DomainControllerNames": ["APP-AD001","APP-AD002"] +} diff --git a/windc/tests/manual/listDataCenter.sh b/windc/tests/manual/listDataCenter.sh new file mode 100755 index 000000000..bb9568007 --- /dev/null +++ b/windc/tests/manual/listDataCenter.sh @@ -0,0 +1 @@ +curl -X GET http://localhost:8082/foo/datacenters diff --git a/windc/windc/api/v1/datacenters.py b/windc/windc/api/v1/datacenters.py index eab65e1b2..2b0e1f9ae 100644 --- a/windc/windc/api/v1/datacenters.py +++ b/windc/windc/api/v1/datacenters.py @@ -42,6 +42,8 @@ class Controller(object): def index(self, req, tenant_id): LOG.debug("Got index request. Request: %s", req) result = core_api.dc_get_index(self.conf, tenant_id) + LOG.debug("Got list of datacenters: %s", result) + result return {'datacenters': result} @utils.http_success_code(202) diff --git a/windc/windc/api/v1/services.py b/windc/windc/api/v1/services.py index 722c48d45..e635250b2 100644 --- a/windc/windc/api/v1/services.py +++ b/windc/windc/api/v1/services.py @@ -53,6 +53,7 @@ class Controller(object): LOG.debug("Headers: %s", req.headers) # We need to create Service object and return its id params['tenant_id'] = tenant_id + params['datacenter_id'] = datacenter_id service_id = core_api.create_service(self.conf, params) return {'service': {'id': service_id}} diff --git a/windc/windc/core/__init__.py b/windc/windc/core/__init__.py index d65c689a8..1e6d1b859 100644 --- a/windc/windc/core/__init__.py +++ b/windc/windc/core/__init__.py @@ -14,3 +14,8 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + +import builder_set + +builder_set.builders = builder_set.BuilderSet() +builder_set.builders.load() \ No newline at end of file diff --git a/windc/windc/core/api.py b/windc/windc/core/api.py index 65c209d5d..5c12a2b2b 100644 --- a/windc/windc/core/api.py +++ b/windc/windc/core/api.py @@ -15,32 +15,82 @@ # License for the specific language governing permissions and limitations # under the License. +from windc.db import api as db_api +from windc.core import change_events as events + def dc_get_index(conf, tenant_id): + dcs = db_api.datacenter_get_all(conf, tenant_id) + dc_list = [db_api.unpack_extra(dc) for dc in dcs] + return dc_list pass def create_dc(conf, params): + # We need to pack all attributes which are not defined by the model explicitly + dc_params = db_api.datacenter_pack_extra(params) + dc = db_api.datacenter_create(conf, dc_params) + event = events.Event(events.SCOPE_DATACENTER_CHANGE, events.ACTION_ADD) + events.change_event(conf, event, dc) + return dc.id pass -def delete_dc(conf, tenant_id, dc_id): +def delete_dc(conf, tenant_id, datacenter_id): + dc = db_api.datacenter_get(conf, tenant_id, datacenter_id) + event = events.Event(events.SCOPE_DATACENTER_CHANGE, events.ACTION_DELETE) + events.change_event(conf, event, dc) + db_api.datacenter_destroy(conf, datacenter_id) pass -def dc_get_data(conf, tenant_id, dc_id): +def dc_get_data(conf, tenant_id, datacenter_id): + dc = db_api.datacenter_get(conf, tenant_id, datacenter_id) + dc_data = db_api.unpack_extra(dc) + return dc_data pass -def update_dc(conf, tenant_id, dc_id, body): +def update_dc(conf, tenant_id, datacenter_id, body): + dc = db_api.datacenter_get(conf, tenant_id, datacenter_id) + old_dc = copy.deepcopy(dc) + db_api.pack_update(dc, body) + dc = db_api.datacenter_update(conf, datacenter_id, dc) + event = events.Event(events.SCOPE_DATACENTER_CHANGE, events.ACTION_MODIFY) + event.previous_state = old_dc + events.change_event(conf, event, dc) pass def service_get_index(conf, tenant_id, datacenter_id): + srvcs = db_api.service_get_all_by_datacenter_id(conf, tenant_id, dtacenter_id) + srv_list = [db_api.unpack_extra(srv) for srv in srvcs] + return srv_list pass def create_service(conf, params): + # We need to pack all attributes which are not defined by the model explicitly + srv_params = db_api.service_pack_extra(params) + srv = db_api.service_create(conf, srv_params) + event = events.Event(events.SCOPE_SERVICE_CHANGE, events.ACTION_ADD) + events.change_event(conf, event, srv) + return srv.id pass def delete_service(conf, tenant_id, datacenter_id, service_id): + srv = db_api.service_get(conf, service_id, tenant_id) + srv_data = db_api.unpack_extra(srv) + event = events.Event(events.SCOPE_SERVICE_CHANGE, events.ACTION_DELETE) + events.change_event(conf, event, srv) + db_api.service_destroy(conf,service_id) pass def service_get_data(conf, tenant_id, datacenter_id, service_id): + srv = db_api.service_get(conf,service_id, tenant_id) + srv_data = db_api.unpack_extra(srv) + return srv_data pass def update_service(conf, tenant_id, datacenter_id, service_id, body): + srv = db_api.service_get(conf, service_id, tenant_id) + old_srv = copy.deepcopy(srv) + db_api.pack_update(srv, body) + srv = db_api.service_update(conf, service_id, srv) + event = events.Event(events.SCOPE_SERVICE_CHANGE, events.ACTION_MODIFY) + event.previous_state = old_srv + events.change_event(conf, event, srv) pass \ No newline at end of file diff --git a/windc/windc/core/builder.py b/windc/windc/core/builder.py new file mode 100644 index 000000000..2dc68e8c5 --- /dev/null +++ b/windc/windc/core/builder.py @@ -0,0 +1,33 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# 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. + +class Builder: + name = "Abstract Builder" + type = "abstract" + version = 0 + + def __init__(self): + pass + + def __str__(self): + return self.name+' type: '+self.type+ ' version: ' + str(self.version) + + def build(self, context, event, data): + pass + + + diff --git a/windc/windc/core/builder_set.py b/windc/windc/core/builder_set.py new file mode 100644 index 000000000..99d481c13 --- /dev/null +++ b/windc/windc/core/builder_set.py @@ -0,0 +1,72 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# 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. + +from builder import Builder + +import imp +import os +import sys, glob +import logging +import traceback + +LOG = logging.getLogger(__name__) +global builders + +def load_from_file(filepath): + class_inst = None + + mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) + + if file_ext.lower() == '.py': + py_mod = imp.load_source(mod_name, filepath) + + elif file_ext.lower() == '.pyc': + py_mod = imp.load_compiled(mod_name, filepath) + + if hasattr(py_mod, mod_name): + callable = getattr(__import__(mod_name),mod_name) + class_inst = callable() + + return class_inst + + +class BuilderSet: + def __init__(self): + self.path = './windc/core/builders' + sys.path.append(self.path) + self.set = {} + + def load(self): + + files = glob.glob(self.path+'/*.py') + + for file in files: + LOG.debug("Trying to load builder from file: %s", file) + try: + builder = load_from_file(file) + LOG.info("Buider '%s' loaded.", builder.name) + self.set[builder.type] = builder + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + LOG.error('Can`t load builder from the file %s. Skip it.', file) + LOG.debug(repr(traceback.format_exception(exc_type, exc_value, + exc_traceback))) + + + def reload(self): + self.set = {} + self.load() diff --git a/windc/windc/core/builders/ActiveDirectory.py b/windc/windc/core/builders/ActiveDirectory.py new file mode 100644 index 000000000..7181329a8 --- /dev/null +++ b/windc/windc/core/builders/ActiveDirectory.py @@ -0,0 +1,53 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# 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. + + +import logging +LOG = logging.getLogger(__name__) + +from windc.core.builder import Builder +from windc.core import change_events as events +from windc.db import api as db_api + +class ActiveDirectory(Builder): + def __init__(self): + self.name = "Active Directory Builder" + self.type = "active_directory_service" + self.version = 1 + + def build(self, context, event, data): + dc = db_api.unpack_extra(data) + if event.scope == events.SCOPE_SERVICE_CHANGE: + LOG.info ("Got service change event. Analysing..") + if self.do_analysis(context, event, dc): + self.plan_changes(context, event, dc) + else: + LOG.debug("Not in my scope. Skip event.") + pass + + def do_analysis(self, context, event, data): + LOG.debug("Doing analysis for data: %s", data) + zones = data['zones'] + if data['type'] == self.type and len(zones) == 1: + LOG.debug("It is a service which I should build.") + return True + else: + return False + + def plan_changes(self, context, event, data): + pass + diff --git a/windc/windc/core/builders/DataCenter.py b/windc/windc/core/builders/DataCenter.py new file mode 100644 index 000000000..92bc1bfd4 --- /dev/null +++ b/windc/windc/core/builders/DataCenter.py @@ -0,0 +1,37 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# 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. + + +import logging +LOG = logging.getLogger(__name__) + +from windc.core.builder import Builder +from windc.core import change_events as events + +class DataCenter(Builder): + def __init__(self): + self.name = "Data Center Builder" + self.type = "datacenter" + self.version = 1 + + def build(self, context, event, data): + if event.scope == events.SCOPE_DATACENTER_CHANGE: + LOG.info ("Got Data Center change event. Analysing...") + else: + LOG.debug("Not in my scope. Skip event.") + pass + diff --git a/windc/windc/core/change_events.py b/windc/windc/core/change_events.py new file mode 100644 index 000000000..8324a7f73 --- /dev/null +++ b/windc/windc/core/change_events.py @@ -0,0 +1,53 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# 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. + + +import logging +LOG = logging.getLogger(__name__) + +from windc.core import builder_set +#Declare events types + +SCOPE_SERVICE_CHANGE = "Service" +SCOPE_DATACENTER_CHANGE = "Datacenter" +SCOPE_VM_CHANGE = "VMChange" + +ACTION_ADD = "Add" +ACTION_MODIFY = "Modify" +ACTION_DELETE = "Delete" + +class Event: + scope = None + action = None + previous_state = None + def __init__(self, scope, action): + self.scope = scope + self.action = action + +def change_event(conf, event, data): + LOG.info("Change event of type: %s ", event) + context = {} + context['conf'] = conf + for builder_type in builder_set.builders.set: + builder = builder_set.builders.set[builder_type] + builder.build(context, event, data) + pass + + + + + diff --git a/windc/windc/db/api.py b/windc/windc/db/api.py index ada8815cd..d01c3caa7 100644 --- a/windc/windc/db/api.py +++ b/windc/windc/db/api.py @@ -60,7 +60,7 @@ service_pack_extra = functools.partial(pack_extra, models.Service) # Datacenter -def datacenter_get(conf, datacenter_id, session=None): +def datacenter_get(conf, tenant_id, datacenter_id, session=None): session = session or get_session(conf) datacenter_ref = session.query(models.DataCenter).\ filter_by(id=datacenter_id).first() @@ -69,9 +69,10 @@ def datacenter_get(conf, datacenter_id, session=None): return datacenter_ref -def datacenter_get_all(conf): +def datacenter_get_all(conf, tenant_id): session = get_session(conf) - query = session.query(models.DataCenter) + query = session.query(models.DataCenter).\ + filter_by(tenant_id=tenant_id) return query.all() @@ -126,7 +127,7 @@ def service_get_all_by_vm_id(conf, tenant_id, vm_id): return query.all() -def service_get_all_by_datacenter_id(conf, datacenter_id): +def service_get_all_by_datacenter_id(conf, tenant_id, datacenter_id): session = get_session(conf) query = session.query(models.Service).filter_by(datacenter_id=datacenter_id) service_refs = query.all() diff --git a/windc/windc/db/migrate_repo/versions/001_Add_initial_tables.py b/windc/windc/db/migrate_repo/versions/001_Add_initial_tables.py index 9841db271..120032873 100644 --- a/windc/windc/db/migrate_repo/versions/001_Add_initial_tables.py +++ b/windc/windc/db/migrate_repo/versions/001_Add_initial_tables.py @@ -9,6 +9,7 @@ Table('datacenter', meta, Column('name', String(255)), Column('type', String(255)), Column('version', String(255)), + Column('tenant_id',String(100)), Column('KMS', String(80)), Column('WSUS', String(80)), Column('extra', Text()), diff --git a/windc/windc/db/models.py b/windc/windc/db/models.py index ae6c552d0..aa755ab9d 100644 --- a/windc/windc/db/models.py +++ b/windc/windc/db/models.py @@ -40,6 +40,7 @@ class DataCenter(DictBase, Base): name = Column(String(255)) type = Column(String(255)) version = Column(String(255)) + tenant_id = Column(String(100)) KMS = Column(String(80)) WSUS = Column(String(80)) extra = Column(JsonBlob()) diff --git a/windc/windc/drivers/__init__.py b/windc/windc/drivers/__init__.py new file mode 100644 index 000000000..e69de29bb