Merge branch 'master' of ssh://gerrit:29418/keero/keero

This commit is contained in:
Dmitry Teselkin 2013-02-25 15:58:34 +04:00
commit ad95b0b6f4
23 changed files with 441 additions and 138 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Net;
using System.Threading; using System.Threading;
using NLog; using NLog;
@ -60,14 +61,13 @@ namespace Mirantis.Keero.WindowsAgent
} }
if (doReboot) if (doReboot)
{ {
Console.WriteLine("Rebooting...");
try try
{ {
System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0"); System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0");
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(ex); Log.ErrorException("Cannot execute shutdown.exe", ex);
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Configuration; using System.Configuration;
using System.Linq; using System.Linq;
using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using RabbitMQ.Client; using RabbitMQ.Client;
@ -32,7 +33,7 @@ namespace Mirantis.Keero.WindowsAgent
public MqMessage GetMessage() public MqMessage GetMessage()
{ {
var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Environment.MachineName.ToLower(); var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Dns.GetHostName().ToLower();
try try
{ {
IConnection connection = null; IConnection connection = null;

View File

@ -30,6 +30,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json"> <Reference Include="Newtonsoft.Json">

View File

@ -49,7 +49,7 @@ def datacenters_list(request):
return windcclient(request).datacenters.list() return windcclient(request).datacenters.list()
def services_create(request, datacenter, parameters): def services_create(request, datacenter, parameters):
name = parameters.get('name', '') name = parameters.get('dc_name', '')
return windcclient(request).services.create(datacenter, name) return windcclient(request).services.create(datacenter, name)
def services_list(request, datacenter): def services_list(request, datacenter):

View File

@ -87,7 +87,7 @@ class DeleteDataCenter(tables.BatchAction):
class EditService(tables.LinkAction): class EditService(tables.LinkAction):
name = "edit" name = "edit"
verbose_name = _("Edit Service") verbose_name = _("Edit")
url = "horizon:project:windc:update" url = "horizon:project:windc:update"
classes = ("ajax-modal", "btn-edit") classes = ("ajax-modal", "btn-edit")
@ -95,6 +95,16 @@ class EditService(tables.LinkAction):
return True return True
class DeleteService(tables.LinkAction):
name = "delete"
verbose_name = _("Delete")
url = "horizon:project:windc:delete"
classes = ("ajax-modal", "btn-edit")
def allowed(self, request, instance):
return True
class ShowDataCenterServices(tables.LinkAction): class ShowDataCenterServices(tables.LinkAction):
name = "edit" name = "edit"
verbose_name = _("Services") verbose_name = _("Services")
@ -128,13 +138,17 @@ class WinDCTable(tables.DataTable):
class WinServicesTable(tables.DataTable): class WinServicesTable(tables.DataTable):
name = tables.Column("name", name = tables.Column('name',
link=("horizon:project:windc"), link=('horizon:project:windc'),
verbose_name=_("Name")) verbose_name=_('Name'))
_type = tables.Column('type',
verbose_name=_('Type'))
status = tables.Column('status',
verbose_name=_('Status'))
class Meta: class Meta:
name = "services" name = "services"
verbose_name = _("Services") verbose_name = _("Services")
row_class = UpdateRow row_class = UpdateRow
table_actions = (CreateService,) table_actions = (CreateService,)
row_actions = (EditService,) row_actions = (EditService, DeleteService)

View File

@ -20,6 +20,7 @@
import json import json
import logging import logging
import re
from django.utils.text import normalize_newlines from django.utils.text import normalize_newlines
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@ -71,11 +72,11 @@ class ConfigureDCAction(workflows.Action):
class ConfigureDC(workflows.Step): class ConfigureDC(workflows.Step):
action_class = ConfigureDCAction action_class = ConfigureDCAction
contibutes = ("name",) contibutes = ('name',)
def contribute(self, data, context): def contribute(self, data, context):
if data: if data:
context['name'] = data.get("name", "") context['name'] = data.get('name', '')
return context return context
@ -83,9 +84,9 @@ class ConfigureWinDCAction(workflows.Action):
dc_name = forms.CharField(label=_("Domain Name"), dc_name = forms.CharField(label=_("Domain Name"),
required=False) required=False)
dc_net_name = forms.CharField(label=_("Domain NetBIOS Name"), #dc_net_name = forms.CharField(label=_("Domain NetBIOS Name"),
required=False, # required=False,
help_text=_("A NetBIOS name of new domain.")) # help_text=_("A NetBIOS name of new domain."))
dc_count = forms.IntegerField(label=_("Domain Controllers Count"), dc_count = forms.IntegerField(label=_("Domain Controllers Count"),
required=True, required=True,
@ -113,6 +114,16 @@ class ConfigureWinDCAction(workflows.Action):
class ConfigureWinDC(workflows.Step): class ConfigureWinDC(workflows.Step):
action_class = ConfigureWinDCAction action_class = ConfigureWinDCAction
contibutes = ('dc_name', 'dc_count', 'adm_password', 'recovery_password')
def contribute(self, data, context):
if data:
context['dc_name'] = data.get('dc_name', '')
context['dc_count'] = data.get('dc_count', 1)
context['adm_password'] = data.get('adm_password', '')
context['recovery_password'] = data.get('recovery_password', '')
context['type'] = 'active_directory_service'
return context
class ConfigureWinIISAction(workflows.Action): class ConfigureWinIISAction(workflows.Action):
@ -138,6 +149,15 @@ class ConfigureWinIISAction(workflows.Action):
class ConfigureWinIIS(workflows.Step): class ConfigureWinIIS(workflows.Step):
action_class = ConfigureWinIISAction action_class = ConfigureWinIISAction
contibutes = ('iis_name', 'iis_count', 'iis_domain')
def contribute(self, data, context):
if data:
context['iis_name'] = data.get('iis_name', '')
context['iis_count'] = data.get('iis_count', 1)
context['iis_domain'] = data.get('iis_domain', '')
return context
class CreateWinService(workflows.Workflow): class CreateWinService(workflows.Workflow):
slug = "create" slug = "create"
@ -149,15 +169,21 @@ class CreateWinService(workflows.Workflow):
default_steps = (SelectProjectUser, default_steps = (SelectProjectUser,
ConfigureWinDC, ConfigureWinDC,
ConfigureWinIIS) ConfigureWinIIS)
def format_status_message(self, message): def format_status_message(self, message):
name = self.context.get('name', 'noname') name = self.context.get('dc_name', 'noname')
return message % name return message % name
def handle(self, request, context): def handle(self, request, context):
try: try:
datacenter = context.get('domain_controller_name', '') ############## FIX ME:
service = api.windc.services_create(request, context) link = request.__dict__['META']['HTTP_REFERER']
datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1]
##############
service = api.windc.services_create(request,
datacenter_id,
context)
return True return True
except: except:
exceptions.handle(request) exceptions.handle(request)

View File

@ -38,6 +38,7 @@ from windc.common import cfg
from windc.common import config from windc.common import config
from windc.common import wsgi from windc.common import wsgi
from windc.db import session from windc.db import session
from windc.core import builder_set
gettext.install('balancer', unicode=1) gettext.install('balancer', unicode=1)
@ -50,10 +51,11 @@ if __name__ == '__main__':
conf.register_cli_opt(dbsync_opt) conf.register_cli_opt(dbsync_opt)
conf() conf()
config.setup_logging(conf)
if conf.dbsync: if conf.dbsync:
config.setup_logging(conf)
session.sync(conf) session.sync(conf)
else: else:
builder_set.builders.load(conf)
app = config.load_paste_app(conf) app = config.load_paste_app(conf)
server = wsgi.Server() server = wsgi.Server()
server.start(app, conf, default_port=8181) server.start(app, conf, default_port=8181)

View File

@ -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
}

View File

@ -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" : {
}
}

View File

@ -51,3 +51,7 @@ admin_password = 000
[filter:auth-context] [filter:auth-context]
paste.filter_factory = windc.common.wsgi:filter_factory paste.filter_factory = windc.common.wsgi:filter_factory
windc.filter_factory = keystone.middleware.balancer_auth_token:KeystoneContextMiddleware windc.filter_factory = keystone.middleware.balancer_auth_token:KeystoneContextMiddleware
[rabbitmq]
host = 10.0.0.1
vhost = keero

View File

@ -1,5 +1,8 @@
#!/bin/bash #!/bin/bash
source openrc.sh
#export OS_USERNAME=admin
#source ../../devstack/openrc
#nova keypair-add keero-linux-keys > heat_key.priv
heat "$@" heat "$@"

View File

@ -20,3 +20,4 @@ PyChef
Paste Paste
passlib passlib
puka

View File

@ -49,6 +49,7 @@ class Services_Controller(object):
# We need to create Service object and return its id # We need to create Service object and return its id
params['tenant_id'] = tenant_id params['tenant_id'] = tenant_id
params['datacenter_id'] = datacenter_id params['datacenter_id'] = datacenter_id
params['type'] = 'active_directory_service'
service_id = core_api.create_service(self.conf, params) service_id = core_api.create_service(self.conf, params)
return {'service': {'id': service_id}} return {'service': {'id': service_id}}

View File

@ -18,4 +18,4 @@
import builder_set import builder_set
builder_set.builders = builder_set.BuilderSet() builder_set.builders = builder_set.BuilderSet()
builder_set.builders.load() #builder_set.builders.load()

View File

@ -20,7 +20,7 @@ class Builder:
type = "abstract" type = "abstract"
version = 0 version = 0
def __init__(self): def __init__(self, conf):
pass pass
def __str__(self): def __str__(self):

View File

@ -26,7 +26,7 @@ import traceback
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
global builders global builders
def load_from_file(filepath): def load_from_file(filepath, conf):
class_inst = None class_inst = None
mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1]) 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): if hasattr(py_mod, mod_name):
callable = getattr(__import__(mod_name),mod_name) callable = getattr(__import__(mod_name),mod_name)
class_inst = callable() class_inst = callable(conf)
return class_inst return class_inst
@ -50,14 +50,14 @@ class BuilderSet:
sys.path.append(self.path) sys.path.append(self.path)
self.set = {} self.set = {}
def load(self): def load(self, conf):
files = glob.glob(self.path+'/*.py') files = glob.glob(self.path+'/*.py')
for file in files: for file in files:
LOG.debug("Trying to load builder from file: %s", file) LOG.debug("Trying to load builder from file: %s", file)
try: try:
builder = load_from_file(file) builder = load_from_file(file, conf)
LOG.info("Buider '%s' loaded.", builder.name) LOG.info("Buider '%s' loaded.", builder.name)
self.set[builder.type] = builder self.set[builder.type] = builder
except: except:

View File

@ -18,6 +18,9 @@
import logging import logging
import uuid import uuid
import os
from sphinx.ext.autosummary import generate
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
from windc.core.builder import Builder from windc.core.builder import Builder
@ -25,90 +28,183 @@ from windc.core import change_events as events
from windc.db import api as db_api from windc.db import api as db_api
from windc.core.templates import Template from windc.core.templates import Template
from windc.core import commands as command_api from windc.core import commands as command_api
import json
from windc.common import cfg
from random import choice
chars = 'abcdefghklmnopqrstvwxyz2345689'
class ActiveDirectory(Builder): class ActiveDirectory(Builder):
def __init__(self): def __init__(self, conf):
self.name = "Active Directory Builder" self.name = "Active Directory Builder"
self.type = "active_directory_service" self.type = "active_directory_service"
self.version = 1 self.version = 1
self.conf = conf
def build(self, context, event, data): conf.register_group(cfg.OptGroup(name="rabbitmq"))
dc = db_api.unpack_extra(data) conf.register_opts([
if event.scope == events.SCOPE_SERVICE_CHANGE: cfg.StrOpt('host', default='10.0.0.1'),
LOG.info ("Got service change event. Analysing..") cfg.StrOpt('vhost', default='keero'),
if self.do_analysis(context, event, dc): ], group="rabbitmq")
self.plan_changes(context, event, dc)
self.submit_commands(context, event, dc)
else:
LOG.debug("Not in my scope. Skip event.")
pass
def do_analysis(self, context, event, data): def build(self, context, event, data, executor):
LOG.debug("Doing analysis for data: %s", data) dc = db_api.unpack_extra(data)
zones = data['zones'] if event.scope == events.SCOPE_SERVICE_CHANGE:
if data['type'] == self.type and len(zones) == 1: LOG.info ("Got service change event. Analysing..")
LOG.debug("It is a service which I should build.") if self.do_analysis(context, event, dc):
datacenter_id = data['datacenter_id'] self.plan_changes(context, event, dc)
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
def plan_changes(self, context, event, data): self.submit_commands(context, event, dc, executor)
# Here we can plan multiple command execution. else:
# It might be Heat call command, then chef call command and other LOG.debug("Not in my scope. Skip event.")
# pass
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 prepare_template(self, context, event, data): def generate(self, length):
LOG.debug("Prepare CloudFormation Template...") return ''.join(choice(chars) for _ in range(length))
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() def do_analysis(self, context, event, data):
instance_name= 'AD-DC001' LOG.debug("Doing analysis for data: %s", data)
template.add_security_group(instance, 'ADSecurityGroup') print data
template.add_resource(instance_name, instance)
template.add_output_value(instance_name+'-IP',{"Fn::GetAtt" : [instance_name,'PublicIp']}, context['zones'] = ['a1']
'Public IP for the domain controller.') if data['type'] == self.type:
context['template']=template LOG.debug("It is a service which I should build.")
pass 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
def deploy_template_command(self, context, event, data): def plan_changes(self, context, event, data):
LOG.debug("Creating CloudFormation Template deployment command...") # Here we can plan multiple command execution.
fname = "templates/"+str(uuid.uuid4()) # It might be Heat call command, then chef call command and other
f=open(fname, "w") #
f.write(context['template'].to_json()) LOG.debug("Plan changes...")
f.close() self.prepare_template(context, event, data)
context['template_name']=fname # self.chef_configuration(context, event, data)
command = command_api.Command(command_api.TEMPLATE_DEPLOYMENT_COMMAND, context) # context['commands'].append(self.deploy_template_command(context, event, data))
return command # context['commands'].append(self.chef_configuration_command(context, event, data))
pass pass
def chef_configuration(self, context, event, data): def prepare_template(self, context, event, data):
LOG.debug("Creating Chef configuration...") LOG.debug("Prepare CloudFormation Template...")
context['Role'] = 'pdc' # template = Template()
pass # 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_command(self, context, event, data): print "-------------------"
LOG.debug("Creating Chef configuration command...") print data
command = command_api.Command(command_api.CHEF_COMMAND, context) print "-------------------"
return command print context
print "********"
try:
print self.conf.rabbitmq.vhost
except Exception, ex:
print ex
print "********"
def submit_commands(self, context, event, data): with open('data/Windows.template', 'r') as f:
LOG.debug("Submit commands for execution...") read_data = f.read()
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

View File

@ -23,12 +23,12 @@ from windc.core.builder import Builder
from windc.core import change_events as events from windc.core import change_events as events
class DataCenter(Builder): class DataCenter(Builder):
def __init__(self): def __init__(self, conf):
self.name = "Data Center Builder" self.name = "Data Center Builder"
self.type = "datacenter" self.type = "datacenter"
self.version = 1 self.version = 1
def build(self, context, event, data): def build(self, context, event, data, executor):
if event.scope == events.SCOPE_DATACENTER_CHANGE: if event.scope == events.SCOPE_DATACENTER_CHANGE:
LOG.info ("Got Data Center change event. Analysing...") LOG.info ("Got Data Center change event. Analysing...")
else: else:

View File

@ -33,24 +33,21 @@ ACTION_MODIFY = "Modify"
ACTION_DELETE = "Delete" ACTION_DELETE = "Delete"
class Event: class Event:
scope = None scope = None
action = None action = None
previous_state = None previous_state = None
def __init__(self, scope, action): def __init__(self, scope, action):
self.scope = scope self.scope = scope
self.action = action self.action = action
def change_event(conf, event, data): def change_event(conf, event, data):
LOG.info("Change event of type: %s ", event) LOG.info("Change event of type: %s ", event)
context = builder.create_context() context = builder.create_context()
context['conf'] = conf context['conf'] = conf
for builder_type in builder_set.builders.set: executor = command_executor.Executor(conf)
builder_instance = builder_set.builders.set[builder_type] for builder_type in builder_set.builders.set:
builder_instance.build(context, event, data) builder_instance = builder_set.builders.set[builder_type]
builder_instance.build(context, event, data, executor)
executor = command_executor.Executor()
executor.execute(context['commands'])
pass

View File

@ -16,26 +16,19 @@
# under the License. # under the License.
TEMPLATE_DEPLOYMENT_COMMAND = "Template" TEMPLATE_DEPLOYMENT_COMMAND = "Template"
EXECUTION_PLAN_DEPLOYMENT_COMMAND = "EPlan"
CHEF_COMMAND = "Chef" CHEF_COMMAND = "Chef"
CHEF_OP_CREATE_ENV = "Env" CHEF_OP_CREATE_ENV = "Env"
CHEF_OP_CREATE_ROLE = "Role" CHEF_OP_CREATE_ROLE = "Role"
CHEF_OP_ASSIGN_ROLE = "AssignRole" CHEF_OP_ASSIGN_ROLE = "AssignRole"
CHEF_OP_CREATE_NODE = "CRNode" CHEF_OP_CREATE_NODE = "CRNode"
class Command: class Command(object):
type = "Empty" type = "Empty"
context = None context = None
def __init__(self):
self.type = "Empty"
self.context = None
self.data = None
def __init__(self, type, context): def __init__(self, type="Empty", context=None, data=None):
self.type = type
self.context = context
def __init__(self, type, context, data):
self.type = type self.type = type
self.context = context self.context = context
self.data = data self.data = data

View File

@ -20,18 +20,21 @@
from windc.core import commands as commands_api from windc.core import commands as commands_api
from windc.drivers import openstack_heat from windc.drivers import openstack_heat
from windc.drivers import windows_agent
class Executor: class Executor:
map = {commands_api.TEMPLATE_DEPLOYMENT_COMMAND : openstack_heat.Heat} map = {commands_api.TEMPLATE_DEPLOYMENT_COMMAND : openstack_heat.Heat}
def __init__(self): def __init__(self, conf):
pass self._conf = conf
def execute(self, commands): def execute(self, command):
for command in commands: if command.type == commands_api.TEMPLATE_DEPLOYMENT_COMMAND:
if command.type == commands_api.TEMPLATE_DEPLOYMENT_COMMAND: executor = openstack_heat.Heat()
executor = openstack_heat.Heat() return executor.execute(command)
executor.execute(command) elif command.type == commands_api.EXECUTION_PLAN_DEPLOYMENT_COMMAND:
executor = windows_agent.Agent(self._conf)
return executor.execute(command)

View File

@ -32,7 +32,12 @@ class Heat:
def execute(self, command): def execute(self, command):
# client = Client('1',OS_IMAGE_ENDPOINT, OS_TENANT_ID) # client = Client('1',OS_IMAGE_ENDPOINT, OS_TENANT_ID)
LOG.debug('Calling heat script to execute template') LOG.debug('Calling heat script to execute template')
call(["./heat_run","stack-create","-f "+command.context['template_name'], arguments = ";".join(['%s=%s' % (key, value) for (key, value) in command.context['template_arguments'].items()])
command.context['stack_name']]) call([
"./heat_run","stack-create",
"-f" + command.context['template_name'],
"-P" + arguments,
command.context['stack_name']
])
pass pass

View File

@ -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()