From b2ca5412ee0d1c3a205bef693ef136828f3b27da Mon Sep 17 00:00:00 2001 From: Stan Lagun Date: Mon, 25 Feb 2013 04:00:09 +0400 Subject: [PATCH] windc iteration2 --- WindowsAgent/WindowsAgent/Program.cs | 4 +- WindowsAgent/WindowsAgent/RabbitMqClient.cs | 3 +- WindowsAgent/WindowsAgent/WindowsAgent.csproj | 1 + windc/bin/windc-api | 4 +- windc/data/CreatePrimaryDC.json | 29 +++ windc/data/Windows.template | 61 +++++ windc/etc/windc-api-paste.ini | 4 + windc/tools/pip-requires | 1 + windc/windc/core/__init__.py | 2 +- windc/windc/core/builder.py | 2 +- windc/windc/core/builder_set.py | 8 +- windc/windc/core/builders/ActiveDirectory.py | 246 ++++++++++++------ windc/windc/core/builders/DataCenter.py | 4 +- windc/windc/core/change_events.py | 29 +-- windc/windc/core/commands.py | 3 +- windc/windc/drivers/command_executor.py | 19 +- windc/windc/drivers/openstack_heat.py | 9 +- windc/windc/drivers/windows_agent.py | 66 +++++ 18 files changed, 378 insertions(+), 117 deletions(-) create mode 100644 windc/data/CreatePrimaryDC.json create mode 100644 windc/data/Windows.template create mode 100644 windc/windc/drivers/windows_agent.py diff --git a/WindowsAgent/WindowsAgent/Program.cs b/WindowsAgent/WindowsAgent/Program.cs index d228f921..32041aed 100644 --- a/WindowsAgent/WindowsAgent/Program.cs +++ b/WindowsAgent/WindowsAgent/Program.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.IO; +using System.Net; using System.Threading; using NLog; @@ -60,14 +61,13 @@ namespace Mirantis.Keero.WindowsAgent } if (doReboot) { - Console.WriteLine("Rebooting..."); try { System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0"); } catch (Exception ex) { - Console.WriteLine(ex); + Log.ErrorException("Cannot execute shutdown.exe", ex); } } diff --git a/WindowsAgent/WindowsAgent/RabbitMqClient.cs b/WindowsAgent/WindowsAgent/RabbitMqClient.cs index 0ce1a77f..c927bd86 100644 --- a/WindowsAgent/WindowsAgent/RabbitMqClient.cs +++ b/WindowsAgent/WindowsAgent/RabbitMqClient.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Configuration; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; using RabbitMQ.Client; @@ -32,7 +33,7 @@ namespace Mirantis.Keero.WindowsAgent public MqMessage GetMessage() { - var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Environment.MachineName.ToLower(); + var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Dns.GetHostName().ToLower(); try { IConnection connection = null; diff --git a/WindowsAgent/WindowsAgent/WindowsAgent.csproj b/WindowsAgent/WindowsAgent/WindowsAgent.csproj index 60247a26..f467e1dc 100644 --- a/WindowsAgent/WindowsAgent/WindowsAgent.csproj +++ b/WindowsAgent/WindowsAgent/WindowsAgent.csproj @@ -30,6 +30,7 @@ TRACE prompt 4 + false diff --git a/windc/bin/windc-api b/windc/bin/windc-api index d3c15ff3..6c8adc03 100755 --- a/windc/bin/windc-api +++ b/windc/bin/windc-api @@ -38,6 +38,7 @@ from windc.common import cfg from windc.common import config from windc.common import wsgi from windc.db import session +from windc.core import builder_set gettext.install('balancer', unicode=1) @@ -50,10 +51,11 @@ if __name__ == '__main__': conf.register_cli_opt(dbsync_opt) conf() + config.setup_logging(conf) if conf.dbsync: - config.setup_logging(conf) session.sync(conf) else: + builder_set.builders.load(conf) app = config.load_paste_app(conf) server = wsgi.Server() server.start(app, conf, default_port=8181) diff --git a/windc/data/CreatePrimaryDC.json b/windc/data/CreatePrimaryDC.json new file mode 100644 index 00000000..fb74fbbc --- /dev/null +++ b/windc/data/CreatePrimaryDC.json @@ -0,0 +1,29 @@ +{ + "Scripts": [ + "RnVuY3Rpb24gU2V0LUxvY2FsVXNlclBhc3N3b3JkIHsNCiAgICBwYXJhbSAoDQogICAgICAgIFtTdHJpbmddICRVc2VyTmFtZSwNCiAgICAgICAgW1N0cmluZ10gJFBhc3N3b3JkLA0KICAgICAgICBbU3dpdGNoXSAkRm9yY2UNCiAgICApDQogICAgDQogICAgdHJhcCB7IFN0b3AtRXhlY3V0aW9uICRfIH0NCiAgICANCiAgICBpZiAoKEdldC1XbWlPYmplY3QgV2luMzJfVXNlckFjY291bnQgLUZpbHRlciAiTG9jYWxBY2NvdW50ID0gJ1RydWUnIEFORCBOYW1lPSckVXNlck5hbWUnIikgLWVxICRudWxsKSB7DQogICAgICAgIHRocm93ICJVbmFibGUgdG8gZmluZCBsb2NhbCB1c2VyIGFjY291bnQgJyRVc2VyTmFtZSciDQogICAgfQ0KICAgIA0KICAgIGlmICgkRm9yY2UpIHsNCiAgICAgICAgV3JpdGUtTG9nICJDaGFuZ2luZyBwYXNzd29yZCBmb3IgdXNlciAnJFVzZXJOYW1lJyB0byAnKioqKionIiAjIDopDQogICAgICAgIChbQURTSV0gIldpbk5UOi8vLi8kVXNlck5hbWUiKS5TZXRQYXNzd29yZCgkUGFzc3dvcmQpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBXcml0ZS1Mb2dXYXJuaW5nICJZb3UgYXJlIHRyeWluZyB0byBjaGFuZ2UgcGFzc3dvcmQgZm9yIHVzZXIgJyRVc2VyTmFtZScuIFRvIGRvIHRoaXMgcGxlYXNlIHJ1biB0aGUgY29tbWFuZCBhZ2FpbiB3aXRoIC1Gb3JjZSBwYXJhbWV0ZXIuIg0KICAgICAgICAkVXNlckFjY291bnQNCiAgICB9DQp9DQoNCg0KDQpGdW5jdGlvbiBJbnN0YWxsLVJvbGVQcmltYXJ5RG9tYWluQ29udHJvbGxlcg0Kew0KPCMNCi5TWU5PUFNJUw0KQ29uZmlndXJlIG5vZGUncyBuZXR3b3JrIGFkYXB0ZXJzLg0KQ3JlYXRlIGZpcnN0IGRvbWFpbiBjb250cm9sbGVyIGluIHRoZSBmb3Jlc3QuDQoNCi5FWEFNUExFDQpQUz4gSW5zdGFsbC1Sb2xlUHJpbWFyeURvbWFpbkNvbnRyb2xsZXIgLURvbWFpbk5hbWUgYWNtZS5sb2NhbCAtU2FmZU1vZGVQYXNzd29yZCAiUEBzc3cwcmQiDQoNCkluc3RhbGwgRE5TIGFuZCBBRERTLCBjcmVhdGUgZm9yZXN0IGFuZCBkb21haW4gJ2FjbWUubG9jYWwnLg0KU2V0IERDIHJlY292ZXJ5IG1vZGUgcGFzc3dvcmQgdG8gJ1BAc3N3MHJkJy4NCiM+DQoJDQoJcGFyYW0NCgkoDQoJCVtTdHJpbmddDQoJCSMgTmV3IGRvbWFpbiBuYW1lLg0KCQkkRG9tYWluTmFtZSwNCgkJDQoJCVtTdHJpbmddDQoJCSMgRG9tYWluIGNvbnRyb2xsZXIgcmVjb3ZlcnkgbW9kZSBwYXNzd29yZC4NCgkJJFNhZmVNb2RlUGFzc3dvcmQNCgkpDQoNCgl0cmFwIHsgU3RvcC1FeGVjdXRpb24gJF8gfQ0KDQogICAgICAgICMgQWRkIHJlcXVpcmVkIHdpbmRvd3MgZmVhdHVyZXMNCglBZGQtV2luZG93c0ZlYXR1cmVXcmFwcGVyIGANCgkJLU5hbWUgIkROUyIsIkFELURvbWFpbi1TZXJ2aWNlcyIsIlJTQVQtREZTLU1nbXQtQ29uIiBgDQoJCS1JbmNsdWRlTWFuYWdlbWVudFRvb2xzIGANCiAgICAgICAgLU5vdGlmeVJlc3RhcnQNCg0KDQoJV3JpdGUtTG9nICJDcmVhdGluZyBmaXJzdCBkb21haW4gY29udHJvbGxlciAuLi4iDQoJCQ0KCSRTTUFQID0gQ29udmVydFRvLVNlY3VyZVN0cmluZyAtU3RyaW5nICRTYWZlTW9kZVBhc3N3b3JkIC1Bc1BsYWluVGV4dCAtRm9yY2UNCgkJDQoJSW5zdGFsbC1BRERTRm9yZXN0IGANCgkJLURvbWFpbk5hbWUgJERvbWFpbk5hbWUgYA0KCQktU2FmZU1vZGVBZG1pbmlzdHJhdG9yUGFzc3dvcmQgJFNNQVAgYA0KCQktRG9tYWluTW9kZSBEZWZhdWx0IGANCgkJLUZvcmVzdE1vZGUgRGVmYXVsdCBgDQoJCS1Ob1JlYm9vdE9uQ29tcGxldGlvbiBgDQoJCS1Gb3JjZSBgDQoJCS1FcnJvckFjdGlvbiBTdG9wIHwgT3V0LU51bGwNCg0KCVdyaXRlLUhvc3QgIldhaXRpbmcgZm9yIHJlYm9vdCAuLi4iCQkNCiMJU3RvcC1FeGVjdXRpb24gLUV4aXRDb2RlIDMwMTAgLUV4aXRTdHJpbmcgIkNvbXB1dGVyIG11c3QgYmUgcmVzdGFydGVkIHRvIGZpbmlzaCBkb21haW4gY29udHJvbGxlciBwcm9tb3Rpb24uIg0KIwlXcml0ZS1Mb2cgIlJlc3RhcmluZyBjb21wdXRlciAuLi4iDQojCVJlc3RhcnQtQ29tcHV0ZXIgLUZvcmNlDQp9DQo=" + ], + "Commands": [ + { + "Name": "Import-Module", + "Arguments": { + "Name": "CoreFunctions" + } + }, + { + "Name": "Set-LocalUserPassword", + "Arguments": { + "UserName": "Administrator", + "Password": "@adm_password", + "Force": true + } + }, + { + "Name": "Install-RolePrimaryDomainController", + "Arguments": { + "DomainName": "@dc_name", + "SafeModePassword": "@recovery_password" + } + } + ], + "RebootOnCompletion": 1 +} \ No newline at end of file diff --git a/windc/data/Windows.template b/windc/data/Windows.template new file mode 100644 index 00000000..66d650d6 --- /dev/null +++ b/windc/data/Windows.template @@ -0,0 +1,61 @@ +{ + "AWSTemplateFormatVersion" : "2010-09-09", + + "Description" : "", + + "Parameters" : { + "KeyName" : { + "Description" : "Name of an existing Amazon EC2 key pair for RDP access", + "Type" : "String", + "Default" : "keero_key" + }, + "InstanceType" : { + "Description" : "Amazon EC2 instance type", + "Type" : "String", + "Default" : "m1.medium", + "AllowedValues" : [ "m1.small", "m1.medium", "m1.large" ] + }, + "ImageName" : { + "Description" : "Image name", + "Type" : "String", + "Default" : "ws-2012-full-agent", + "AllowedValues" : [ "ws-2012-full", "ws-2012-core", "ws-2012-full-agent" ] + } + }, + + "Resources" : { + "IAMUser" : { + "Type" : "AWS::IAM::User", + "Properties" : { + "Path": "/", + "Policies": [{ + "PolicyName": "root", + "PolicyDocument": { "Statement":[{ + "Effect": "Allow", + "Action": "CloudFormation:DescribeStackResource", + "Resource": "*" + }]} + }] + } + }, + + "IAMUserAccessKey" : { + "Type" : "AWS::IAM::AccessKey", + "Properties" : { + "UserName" : {"Ref": "IAMUser"} + } + }, + + "InstanceTemplate": { + "Type" : "AWS::EC2::Instance", + "Properties": { + "InstanceType" : { "Ref" : "InstanceType" }, + "ImageId" : { "Ref" : "ImageName" }, + "KeyName" : { "Ref" : "KeyName" } + } + } + }, + + "Outputs" : { + } +} \ No newline at end of file diff --git a/windc/etc/windc-api-paste.ini b/windc/etc/windc-api-paste.ini index 7c0deee8..8dbdc8c2 100644 --- a/windc/etc/windc-api-paste.ini +++ b/windc/etc/windc-api-paste.ini @@ -51,3 +51,7 @@ admin_password = 000 [filter:auth-context] paste.filter_factory = windc.common.wsgi:filter_factory windc.filter_factory = keystone.middleware.balancer_auth_token:KeystoneContextMiddleware + +[rabbitmq] +host = 10.0.0.1 +vhost = keero \ No newline at end of file diff --git a/windc/tools/pip-requires b/windc/tools/pip-requires index d860a56e..20109d9f 100644 --- a/windc/tools/pip-requires +++ b/windc/tools/pip-requires @@ -20,3 +20,4 @@ PyChef Paste passlib +puka diff --git a/windc/windc/core/__init__.py b/windc/windc/core/__init__.py index 1e6d1b85..1d3eb572 100644 --- a/windc/windc/core/__init__.py +++ b/windc/windc/core/__init__.py @@ -18,4 +18,4 @@ import builder_set builder_set.builders = builder_set.BuilderSet() -builder_set.builders.load() \ No newline at end of file +#builder_set.builders.load() \ No newline at end of file diff --git a/windc/windc/core/builder.py b/windc/windc/core/builder.py index 15a14e6b..77088485 100644 --- a/windc/windc/core/builder.py +++ b/windc/windc/core/builder.py @@ -20,7 +20,7 @@ class Builder: type = "abstract" version = 0 - def __init__(self): + def __init__(self, conf): pass def __str__(self): diff --git a/windc/windc/core/builder_set.py b/windc/windc/core/builder_set.py index 99d481c1..0f366018 100644 --- a/windc/windc/core/builder_set.py +++ b/windc/windc/core/builder_set.py @@ -26,7 +26,7 @@ import traceback LOG = logging.getLogger(__name__) global builders -def load_from_file(filepath): +def load_from_file(filepath, conf): class_inst = None mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) @@ -39,7 +39,7 @@ def load_from_file(filepath): if hasattr(py_mod, mod_name): callable = getattr(__import__(mod_name),mod_name) - class_inst = callable() + class_inst = callable(conf) return class_inst @@ -50,14 +50,14 @@ class BuilderSet: sys.path.append(self.path) self.set = {} - def load(self): + def load(self, conf): 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) + builder = load_from_file(file, conf) LOG.info("Buider '%s' loaded.", builder.name) self.set[builder.type] = builder except: diff --git a/windc/windc/core/builders/ActiveDirectory.py b/windc/windc/core/builders/ActiveDirectory.py index db0dcf17..2bae2a01 100644 --- a/windc/windc/core/builders/ActiveDirectory.py +++ b/windc/windc/core/builders/ActiveDirectory.py @@ -19,6 +19,8 @@ import logging import uuid import os +from sphinx.ext.autosummary import generate + LOG = logging.getLogger(__name__) from windc.core.builder import Builder @@ -26,95 +28,183 @@ from windc.core import change_events as events from windc.db import api as db_api from windc.core.templates import Template from windc.core import commands as command_api +import json +from windc.common import cfg +from random import choice + +chars = 'abcdefghklmnopqrstvwxyz2345689' + class ActiveDirectory(Builder): - def __init__(self): - self.name = "Active Directory Builder" - self.type = "active_directory_service" - self.version = 1 + def __init__(self, conf): + self.name = "Active Directory Builder" + self.type = "active_directory_service" + self.version = 1 + self.conf = conf - 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) + conf.register_group(cfg.OptGroup(name="rabbitmq")) + conf.register_opts([ + cfg.StrOpt('host', default='10.0.0.1'), + cfg.StrOpt('vhost', default='keero'), + ], group="rabbitmq") - self.submit_commands(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) - print data + def build(self, context, event, data, executor): + 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) - context['zones'] = ['a1'] - if data['type'] == self.type: - LOG.debug("It is a service which I should build.") - datacenter_id = data['datacenter_id'] - dc = db_api.datacenter_get(context['conf'],data['tenant_id'], - data['datacenter_id']) - datacenter = db_api.unpack_extra(dc) - context['stack_name']=datacenter['name'] - return True - else: - return False + self.submit_commands(context, event, dc, executor) + else: + LOG.debug("Not in my scope. Skip event.") + pass - def plan_changes(self, context, event, data): - # Here we can plan multiple command execution. - # It might be Heat call command, then chef call command and other - # - LOG.debug("Plan changes...") - self.prepare_template(context, event, data) - self.chef_configuration(context, event, data) - context['commands'].append(self.deploy_template_command(context, event, data)) - context['commands'].append(self.chef_configuration_command(context, event, data)) - pass + def generate(self, length): + return ''.join(choice(chars) for _ in range(length)) - def prepare_template(self, context, event, data): - LOG.debug("Prepare CloudFormation Template...") - template = Template() - template.add_description('Base template for Active Directory deployment') - sec_grp = template.create_security_group('Security group for AD') - rule = template.create_securitygroup_rule('tcp','3389','3389','0.0.0.0/0') - template.add_rule_to_securitygroup(sec_grp, rule) - template.add_resource('ADSecurityGroup', sec_grp) + def do_analysis(self, context, event, data): + LOG.debug("Doing analysis for data: %s", data) + print data - instance = template.create_instance() - instance_name= 'AD-DC001' - template.add_security_group(instance, 'ADSecurityGroup') - template.add_resource(instance_name, instance) + context['zones'] = ['a1'] + if data['type'] == self.type: + LOG.debug("It is a service which I should build.") + datacenter_id = data['datacenter_id'] + dc = db_api.datacenter_get(context['conf'],data['tenant_id'], + data['datacenter_id']) + datacenter = db_api.unpack_extra(dc) + context['stack_name']=datacenter['name'] + return True + else: + return False - template.add_output_value(instance_name+'-IP',{"Fn::GetAtt" : [instance_name,'PublicIp']}, - 'Public IP for the domain controller.') - context['template']=template - pass + def plan_changes(self, context, event, data): + # Here we can plan multiple command execution. + # It might be Heat call command, then chef call command and other + # + LOG.debug("Plan changes...") + self.prepare_template(context, event, data) + # self.chef_configuration(context, event, data) + # context['commands'].append(self.deploy_template_command(context, event, data)) + # context['commands'].append(self.chef_configuration_command(context, event, data)) + pass - def deploy_template_command(self, context, event, data): - LOG.debug("Creating CloudFormation Template deployment command...") - print context['template'].to_json() - LOG.debug(context['template']) - print os.system('pwd') - fname = "templates/"+str(uuid.uuid4()) - f=open(fname, "w") - f.write(context['template'].to_json()) - f.close() - context['template_name']=fname - command = command_api.Command(command_api.TEMPLATE_DEPLOYMENT_COMMAND, context) - return command - pass + def prepare_template(self, context, event, data): + LOG.debug("Prepare CloudFormation Template...") + # template = Template() + # template.add_description('Base template for Active Directory deployment') + # sec_grp = template.create_security_group('Security group for AD') + # rule = template.create_securitygroup_rule('tcp','3389','3389','0.0.0.0/0') + # template.add_rule_to_securitygroup(sec_grp, rule) + # template.add_resource('ADSecurityGroup', sec_grp) + # + # instance = template.create_instance() + # instance_name= 'AD-DC001' + # template.add_security_group(instance, 'ADSecurityGroup') + # template.add_resource(instance_name, instance) + # + # template.add_output_value(instance_name+'-IP',{"Fn::GetAtt" : [instance_name,'PublicIp']}, + # 'Public IP for the domain controller.') - def chef_configuration(self, context, event, data): - LOG.debug("Creating Chef configuration...") - context['Role'] = 'pdc' - pass + print "-------------------" + print data + print "-------------------" + print context + print "********" + try: + print self.conf.rabbitmq.vhost + except Exception, ex: + print ex + print "********" - def chef_configuration_command(self, context, event, data): - LOG.debug("Creating Chef configuration command...") - command = command_api.Command(command_api.CHEF_COMMAND, context) - return command + with open('data/Windows.template', 'r') as f: + read_data = f.read() - def submit_commands(self, context, event, data): - LOG.debug("Submit commands for execution...") - pass + template = json.loads(read_data) + + instance_template = template['Resources']['InstanceTemplate'] + + del template['Resources']['InstanceTemplate'] + context['instances'] = [] + context['template_arguments'] = { + "KeyName": "keero-linux-keys", + "InstanceType": "m1.medium", + "ImageName": "ws-2012-full-agent" + } + + for i in range(data['dc_count']): + instance_name = 'dc' + str(i) + "x" + self.generate(9) + context['instances'].append(instance_name) + template['Resources'][instance_name] = instance_template + + context['template']=template + pass + + def deploy_template_command(self, context, event, data, executor): + LOG.debug("Creating CloudFormation Template deployment command...") + #print context['template'].to_json() + LOG.debug(context['template']) + if not os.path.exists("templates"): + os.mkdir("templates") + fname = "templates/"+str(uuid.uuid4()) + print "Saving template to", fname + f=open(fname, "w") + f.write(json.dumps(context['template'])) + f.close() + context['template_name']=fname + command = command_api.Command(command_api.TEMPLATE_DEPLOYMENT_COMMAND, context) + executor.execute(command) + + def chef_configuration(self, context, event, data): + LOG.debug("Creating Chef configuration...") + context['Role'] = 'pdc' + pass + + def transform(self, path, map): + with open(path, 'r') as f: + read_data = f.read() + + template = json.loads(read_data) + if 'Commands' in template: + for command in template['Commands']: + if 'Arguments' in command: + for argument, argument_value in command['Arguments'].items(): + if isinstance(argument_value, (str, unicode)) and argument_value.startswith("@"): + command['Arguments'][argument] = map[argument_value[1:]] + + return json.dumps(template) + + def deploy_execution_plan(self, context, event, data, executor): + i = 0 + for instance in context['instances']: + i += 1 + if i == 1: + files = ["data/CreatePrimaryDC.json"] + else: + files = [] + + for file in files: + queueData = { + "queueName" : str("%s-%s" % (context['stack_name'], instance)), + "resultQueueName": "-execution-results", + "body": self.transform(file, data) + } + command = command_api.Command(command_api.EXECUTION_PLAN_DEPLOYMENT_COMMAND, context, queueData) + executor.execute(command) + + + + + def chef_configuration_command(self, context, event, data): + LOG.debug("Creating Chef configuration command...") + command = command_api.Command(command_api.CHEF_COMMAND, context) + return command + + def submit_commands(self, context, event, data, executor): + LOG.debug("Submit commands for execution...") + self.deploy_template_command(context, event, data, executor) + self.deploy_execution_plan(context, event, data, executor) + print "Commands submitted" + pass diff --git a/windc/windc/core/builders/DataCenter.py b/windc/windc/core/builders/DataCenter.py index 92bc1bfd..d425bae7 100644 --- a/windc/windc/core/builders/DataCenter.py +++ b/windc/windc/core/builders/DataCenter.py @@ -23,12 +23,12 @@ from windc.core.builder import Builder from windc.core import change_events as events class DataCenter(Builder): - def __init__(self): + def __init__(self, conf): self.name = "Data Center Builder" self.type = "datacenter" self.version = 1 - def build(self, context, event, data): + def build(self, context, event, data, executor): if event.scope == events.SCOPE_DATACENTER_CHANGE: LOG.info ("Got Data Center change event. Analysing...") else: diff --git a/windc/windc/core/change_events.py b/windc/windc/core/change_events.py index 8955b58d..c73ea29e 100644 --- a/windc/windc/core/change_events.py +++ b/windc/windc/core/change_events.py @@ -33,24 +33,21 @@ 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 + 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 = builder.create_context() - context['conf'] = conf - for builder_type in builder_set.builders.set: - builder_instance = builder_set.builders.set[builder_type] - builder_instance.build(context, event, data) - - executor = command_executor.Executor() - executor.execute(context['commands']) - pass + LOG.info("Change event of type: %s ", event) + context = builder.create_context() + context['conf'] = conf + executor = command_executor.Executor(conf) + for builder_type in builder_set.builders.set: + builder_instance = builder_set.builders.set[builder_type] + builder_instance.build(context, event, data, executor) diff --git a/windc/windc/core/commands.py b/windc/windc/core/commands.py index f15105c8..06af49c9 100644 --- a/windc/windc/core/commands.py +++ b/windc/windc/core/commands.py @@ -16,13 +16,14 @@ # under the License. TEMPLATE_DEPLOYMENT_COMMAND = "Template" +EXECUTION_PLAN_DEPLOYMENT_COMMAND = "EPlan" CHEF_COMMAND = "Chef" CHEF_OP_CREATE_ENV = "Env" CHEF_OP_CREATE_ROLE = "Role" CHEF_OP_ASSIGN_ROLE = "AssignRole" CHEF_OP_CREATE_NODE = "CRNode" -class Command: +class Command(object): type = "Empty" context = None diff --git a/windc/windc/drivers/command_executor.py b/windc/windc/drivers/command_executor.py index c7c0d2f1..f675a0ab 100644 --- a/windc/windc/drivers/command_executor.py +++ b/windc/windc/drivers/command_executor.py @@ -20,18 +20,21 @@ from windc.core import commands as commands_api from windc.drivers import openstack_heat +from windc.drivers import windows_agent class Executor: - map = {commands_api.TEMPLATE_DEPLOYMENT_COMMAND : openstack_heat.Heat} + map = {commands_api.TEMPLATE_DEPLOYMENT_COMMAND : openstack_heat.Heat} - def __init__(self): - pass + def __init__(self, conf): + self._conf = conf - def execute(self, commands): - for command in commands: - if command.type == commands_api.TEMPLATE_DEPLOYMENT_COMMAND: - executor = openstack_heat.Heat() - executor.execute(command) + def execute(self, command): + if command.type == commands_api.TEMPLATE_DEPLOYMENT_COMMAND: + executor = openstack_heat.Heat() + return executor.execute(command) + elif command.type == commands_api.EXECUTION_PLAN_DEPLOYMENT_COMMAND: + executor = windows_agent.Agent(self._conf) + return executor.execute(command) diff --git a/windc/windc/drivers/openstack_heat.py b/windc/windc/drivers/openstack_heat.py index 6d584a76..dd50fda8 100644 --- a/windc/windc/drivers/openstack_heat.py +++ b/windc/windc/drivers/openstack_heat.py @@ -32,7 +32,12 @@ class Heat: def execute(self, command): # client = Client('1',OS_IMAGE_ENDPOINT, OS_TENANT_ID) LOG.debug('Calling heat script to execute template') - call(["./heat_run","stack-create","-f"+command.context['template_name'], - command.context['stack_name']]) + arguments = ";".join(['%s=%s' % (key, value) for (key, value) in command.context['template_arguments'].items()]) + call([ + "./heat_run","stack-create", + "-f" + command.context['template_name'], + "-P" + arguments, + command.context['stack_name'] + ]) pass diff --git a/windc/windc/drivers/windows_agent.py b/windc/windc/drivers/windows_agent.py new file mode 100644 index 00000000..e446b05e --- /dev/null +++ b/windc/windc/drivers/windows_agent.py @@ -0,0 +1,66 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Piston Cloud Computing, Inc. +# 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 traceback + +import puka + +import logging +import sys + +LOG = logging.getLogger(__name__) + +class Agent(object): + + def __init__(self, conf): + self._conf = conf + + def execute(self, command): + try: + client = puka.Client("amqp://keero:keero@%s/%s" % ( + self._conf.rabbitmq.host, self._conf.rabbitmq.vhost)) + promise = client.connect() + client.wait(promise) + + + promise = client.queue_declare(queue=command.data['queueName'], durable=True) + client.wait(promise) + + promise = client.queue_declare(queue=command.data['resultQueueName'], durable=True) + client.wait(promise) + + promise = client.basic_publish(exchange='', routing_key=command.data['queueName'], + body=command.data['body']) + client.wait(promise) + + consume_promise = client.basic_consume(queue=command.data['resultQueueName']) + result = client.wait(consume_promise) + + result_msg = result['body'] + client.basic_ack(result) + client.basic_cancel(consume_promise) + + promise = client.close() + client.wait(promise) + + return result_msg + except Exception: + exc_type, exc_value, exc_traceback = sys.exc_info() + print exc_type, exc_value, exc_traceback + print traceback.format_exc()