1. Added builders support. Each builder is a class dynamically loaded from
./windc/core/builders folder. The class name should be the same as module file name. 2. Updated core/api.py to support datacenter and service creation with extra parameters which are not defined by model explicitly. 3. Added event based approach for the windows environment change. Now when user submits a request to API the core updates database and initiates a new event which defined scope (datacenter, service, VM) and action (add, modify, delete). This event and data will be iterated over all registered builders. Each builder can use this event and data to plan some modification.
This commit is contained in:
parent
8994ffcab1
commit
c138dd8f40
@ -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
|
||||
|
@ -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
|
@ -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
|
4
windc/tests/manual/createDataCenter.sh
Executable file
4
windc/tests/manual/createDataCenter.sh
Executable file
@ -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
|
7
windc/tests/manual/createDataCenterParameters
Normal file
7
windc/tests/manual/createDataCenterParameters
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Test Data Center 2",
|
||||
"type": "SingleZone",
|
||||
"version":"1.1",
|
||||
"KMS":"172.16.1.2",
|
||||
"WSUS":"172.16.1.3"
|
||||
}
|
4
windc/tests/manual/createService.sh
Executable file
4
windc/tests/manual/createService.sh
Executable file
@ -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
|
8
windc/tests/manual/createServiceParameters
Normal file
8
windc/tests/manual/createServiceParameters
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "active_directory_service",
|
||||
"zones": ["zone1"],
|
||||
"domain": "ACME.cloud",
|
||||
"AdminUser": "Admin",
|
||||
"AdminPassword": "StrongPassword",
|
||||
"DomainControllerNames": ["APP-AD001","APP-AD002"]
|
||||
}
|
1
windc/tests/manual/listDataCenter.sh
Executable file
1
windc/tests/manual/listDataCenter.sh
Executable file
@ -0,0 +1 @@
|
||||
curl -X GET http://localhost:8082/foo/datacenters
|
@ -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)
|
||||
|
@ -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}}
|
||||
|
||||
|
@ -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()
|
@ -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
|
33
windc/windc/core/builder.py
Normal file
33
windc/windc/core/builder.py
Normal file
@ -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
|
||||
|
||||
|
||||
|
72
windc/windc/core/builder_set.py
Normal file
72
windc/windc/core/builder_set.py
Normal file
@ -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()
|
53
windc/windc/core/builders/ActiveDirectory.py
Normal file
53
windc/windc/core/builders/ActiveDirectory.py
Normal file
@ -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
|
||||
|
37
windc/windc/core/builders/DataCenter.py
Normal file
37
windc/windc/core/builders/DataCenter.py
Normal file
@ -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
|
||||
|
53
windc/windc/core/change_events.py
Normal file
53
windc/windc/core/change_events.py
Normal file
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()),
|
||||
|
@ -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())
|
||||
|
0
windc/windc/drivers/__init__.py
Normal file
0
windc/windc/drivers/__init__.py
Normal file
Loading…
x
Reference in New Issue
Block a user