1. Added support of CloudFormation templates. Made a simple interface to build template. Stan can work here to redesign template.py

2. Added calls of drivers. Now heat is called from cmd instead of client. Should be rewritten.
3. ActiveDirectory makes a static template. Need to rewrite this with working with actual parameters.
This commit is contained in:
Georgy Okrokvertskhov 2013-02-15 06:04:29 -08:00
parent f32b95e7dc
commit 61801a0ca8
11 changed files with 314 additions and 5 deletions

5
windc/heat_run Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
source openrc.sh
heat "$@"

View File

@ -4,5 +4,5 @@
"domain": "ACME.cloud",
"AdminUser": "Admin",
"AdminPassword": "StrongPassword",
"DomainControllerNames": ["APP-AD001","APP-AD002"]
"DomainControllerNames": ["AD-DC001"]
}

View File

@ -15,7 +15,7 @@ sqlalchemy-migrate>=0.7.2
httplib2
kombu
iso8601>=0.1.4
PyChef
# For paste.util.template used in keystone.common.template
Paste

View File

@ -0,0 +1,19 @@
# 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 heatclient import Client

View File

@ -29,5 +29,9 @@ class Builder:
def build(self, context, event, data):
pass
def create_context():
context = {}
context['commands']=[]
return context

View File

@ -17,11 +17,14 @@
import logging
import uuid
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
from windc.core.templates import Template
from windc.core import commands as command_api
class ActiveDirectory(Builder):
def __init__(self):
@ -35,6 +38,8 @@ class ActiveDirectory(Builder):
LOG.info ("Got service change event. Analysing..")
if self.do_analysis(context, event, dc):
self.plan_changes(context, event, dc)
self.submit_commands(context, event, dc)
else:
LOG.debug("Not in my scope. Skip event.")
pass
@ -44,10 +49,66 @@ class ActiveDirectory(Builder):
zones = data['zones']
if data['type'] == self.type and len(zones) == 1:
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
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 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.')
context['template']=template
pass
def deploy_template_command(self, context, event, data):
LOG.debug("Creating CloudFormation Template deployment command...")
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 chef_configuration(self, context, event, data):
LOG.debug("Creating Chef configuration...")
context['Role'] = 'pdc'
pass
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):
LOG.debug("Submit commands for execution...")
pass

View File

@ -20,6 +20,8 @@ import logging
LOG = logging.getLogger(__name__)
from windc.core import builder_set
from windc.core import builder
from windc.drivers import command_executor
#Declare events types
SCOPE_SERVICE_CHANGE = "Service"
@ -40,11 +42,14 @@ class Event:
def change_event(conf, event, data):
LOG.info("Change event of type: %s ", event)
context = {}
context = builder.create_context()
context['conf'] = conf
for builder_type in builder_set.builders.set:
builder = builder_set.builders.set[builder_type]
builder.build(context, event, data)
builder_instance = builder_set.builders.set[builder_type]
builder_instance.build(context, event, data)
executor = command_executor.Executor()
executor.execute(context['commands'])
pass

View 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.
TEMPLATE_DEPLOYMENT_COMMAND = "Template"
CHEF_COMMAND = "Chef"
class Command:
type = "Empty"
context = None
def __init__(self):
self.type = "Empty"
self.context = None
def __init__(self, type, context):
self.type = type
self.context = context

View File

@ -0,0 +1,107 @@
# 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
from windc.common.wsgi import JSONResponseSerializer
LOG = logging.getLogger(__name__)
class Template:
def __init__(self):
self.content = {'AWSTemplateFormatVersion':'2010-09-09', 'Description':'',
'Parameters':{}}
self.content['Mappings'] = {
"AWSInstanceType2Arch" : {
"t1.micro" : { "Arch" : "32" },
"m1.small" : { "Arch" : "32" },
"m1.large" : { "Arch" : "64" },
"m1.xlarge" : { "Arch" : "64" },
"m2.xlarge" : { "Arch" : "64" },
"m2.2xlarge" : { "Arch" : "64" },
"m2.4xlarge" : { "Arch" : "64" },
"c1.medium" : { "Arch" : "32" },
"c1.xlarge" : { "Arch" : "64" },
"cc1.4xlarge" : { "Arch" : "64" }
},
"DistroArch2AMI": {
"F16" : { "32" : "F16-i386-cfntools", "64" : "F16-x86_64-cfntools" },
"F17" : { "32" : "F17-i386-cfntools", "64" : "F17-x86_64-cfntools" },
"U10" : { "32" : "U10-i386-cfntools", "64" : "U10-x86_64-cfntools" },
"RHEL-6.1": { "32" : "rhel61-i386-cfntools", "64" : "rhel61-x86_64-cfntools" },
"RHEL-6.2": { "32" : "rhel62-i386-cfntools", "64" : "rhel62-x86_64-cfntools" },
"RHEL-6.3": { "32" : "rhel63-i386-cfntools", "64" : "rhel63-x86_64-cfntools" }
}
}
self.content['Resources'] = {}
self.content['Outputs'] = {}
def to_json(self):
serializer = JSONResponseSerializer()
json = serializer.to_json(self.content)
return json
def empty_template(self):
pass
def add_description(self, description):
self.content['Description'] = description
def add_parameter(self, name, parameter):
self.content['Parameters'].update({name : parameter})
def add_resource(self, name, resource):
self.content['Resources'].update({name : resource})
def create_parameter(self, defult, type, decription):
parameter = {'Default':default, 'Type':type, 'Description':description}
return parameter
def create_security_group(self, description):
sec_grp = {'Type':'AWS::EC2::SecurityGroup'}
sec_grp['Properties'] = {}
sec_grp['Properties']['GroupDescription'] = description
sec_grp['Properties']['SecurityGroupIngress'] = []
return sec_grp
def add_rule_to_securitygroup(self, grp, rule):
grp['Properties']['SecurityGroupIngress'].append(rule)
def create_securitygroup_rule(self, proto, f_port, t_port, cidr):
rule = {'IpProtocol':proto, 'FromPort':f_port, 'ToPort':t_port,'CidrIp': cidr}
return rule
def create_instance(self):
instance = {'Type':'AWS::EC2::Instance','Metadata':{},'Properties':{}}
instance['Properties']['ImageId'] = 'U10-x86_64-cfntools'
instance['Properties']['SecurityGroups']=[]
instance['Properties']['KeyName'] = 'keero-linux-keys'
instance['Properties']['InstanceType'] = 'm1.small'
return instance
def add_security_group(self, instance, grp_name):
instance['Properties']['SecurityGroups'].append({'Ref': grp_name})
def add_output_value(self, name, value, description):
self.content['Outputs'].update({name:{'Value':value, 'Description':description}})
def get_content(self):
return self.content

View File

@ -0,0 +1,37 @@
# 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.
from windc.core import commands as commands_api
from windc.drivers import openstack_heat
class Executor:
map = {commands_api.TEMPLATE_DEPLOYMENT_COMMAND : openstack_heat.Heat}
def __init__(self):
pass
def execute(self, commands):
for command in commands:
if command.type == commands_api.TEMPLATE_DEPLOYMENT_COMMAND:
executor = openstack_heat.Heat()
executor.execute(command)

View File

@ -0,0 +1,38 @@
# 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.
#from heatclient import Client
from subprocess import call
import logging
LOG = logging.getLogger(__name__)
class Heat:
def __init__(self):
pass
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']])
pass