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:
parent
f32b95e7dc
commit
61801a0ca8
5
windc/heat_run
Executable file
5
windc/heat_run
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
source openrc.sh
|
||||
heat "$@"
|
||||
|
@ -4,5 +4,5 @@
|
||||
"domain": "ACME.cloud",
|
||||
"AdminUser": "Admin",
|
||||
"AdminPassword": "StrongPassword",
|
||||
"DomainControllerNames": ["APP-AD001","APP-AD002"]
|
||||
"DomainControllerNames": ["AD-DC001"]
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
19
windc/windc/adapters/openstack.py
Normal file
19
windc/windc/adapters/openstack.py
Normal 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
|
||||
|
@ -29,5 +29,9 @@ class Builder:
|
||||
def build(self, context, event, data):
|
||||
pass
|
||||
|
||||
def create_context():
|
||||
context = {}
|
||||
context['commands']=[]
|
||||
return context
|
||||
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
||||
|
||||
|
33
windc/windc/core/commands.py
Normal file
33
windc/windc/core/commands.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.
|
||||
|
||||
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
|
||||
|
||||
|
107
windc/windc/core/templates.py
Normal file
107
windc/windc/core/templates.py
Normal 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
|
||||
|
||||
|
||||
|
||||
|
37
windc/windc/drivers/command_executor.py
Normal file
37
windc/windc/drivers/command_executor.py
Normal 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)
|
||||
|
||||
|
38
windc/windc/drivers/openstack_heat.py
Normal file
38
windc/windc/drivers/openstack_heat.py
Normal 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user