Removed all projects except Glazier Deployment

This commit is contained in:
Serg Melikyan 2013-04-09 15:29:23 +04:00
parent c3083f5f6a
commit 0f5debdcb1
410 changed files with 0 additions and 30043 deletions

View File

@ -1,17 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{501BE151-4B8C-4355-88DC-3AEF1921B2D7}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ConsoleApplication1</RootNamespace>
<AssemblyName>ExecutionPlanGenerator</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -1,141 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Command
{
public string Name { get; set; }
public Dictionary<string, object> Arguments { get; set; }
}
class ExecutionPlan
{
public List<string> Scripts { get; set; }
public List<Command> Commands { get; set; }
public int RebootOnCompletion { get; set; }
}
class Program
{
static void Main(string[] args)
{
if (args.Length < 1 || args.Length > 2)
{
Console.WriteLine("Usage: ExecutionPlanGenerator inputfile [outputfile]");
return;
}
var outFile = args.Length == 2 ? args[1] : null;
var plan = new ExecutionPlan {
Scripts = new List<string>(),
Commands = new List<Command>()
};
var lines = File.ReadAllLines(args[0]);
foreach (var statement in lines
.Select(t => t.Split(new[] { ' ', '\t' }, 2))
.Where(t => t.Length == 2)
.Select(t => new Tuple<string, string>(t[0].Trim().ToLower(), t[1].Trim())))
{
switch (statement.Item1)
{
case "include":
Include(statement.Item2, plan, args[0]);
break;
case "call":
Call(statement.Item2, plan);
break;
case "reboot":
plan.RebootOnCompletion = int.Parse(statement.Item2);
break;
case "out":
if (args.Length < 2)
{
var path = statement.Item2;
if (!Path.IsPathRooted(path))
{
path = Path.Combine(Path.GetDirectoryName(args[0]), path);
}
outFile = path;
}
break;
}
}
var data = JsonConvert.SerializeObject(plan, Formatting.Indented);
if (outFile == null)
{
Console.WriteLine(data);
}
else
{
File.WriteAllText(outFile, data);
}
}
private static void Call(string line, ExecutionPlan plan)
{
var parts = line.Split(new[] { ' ', '\t'}, 2);
var command = new Command() {
Name = parts[0].Trim(),
Arguments = new Dictionary<string, object>()
};
if (parts.Length == 2)
{
foreach (var x in parts[1]
.Split(',')
.Select(t => t.Split('='))
.Where(t => t.Length == 2)
.Select(t => new KeyValuePair<string, string>(t[0].Trim(), t[1].Trim())))
{
object value = null;
long num;
bool boolean;
if (x.Value.StartsWith("\""))
{
value = x.Value.Substring(1, x.Value.Length - 2);
}
else if (long.TryParse(x.Value, out num))
{
value = num;
}
else if (bool.TryParse(x.Value, out boolean))
{
value = boolean;
}
else
{
continue;
}
command.Arguments.Add(x.Key, value);
}
}
plan.Commands.Add(command);
}
private static void Include(string file, ExecutionPlan plan, string dslPath)
{
var path = file;
if (!Path.IsPathRooted(file))
{
path = Path.Combine(Path.GetDirectoryName(dslPath), path);
}
var text = File.ReadAllText(path, Encoding.UTF8);
plan.Scripts.Add(Convert.ToBase64String(Encoding.UTF8.GetBytes(text)));
}
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9aab688a-ce5f-402e-8891-2d7b4ae85ea3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
</packages>

Binary file not shown.

View File

@ -1,26 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsAgent", "WindowsAgent\WindowsAgent.csproj", "{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExecutionPlanGenerator", "ExecutionPlanGenerator\ExecutionPlanGenerator.csproj", "{501BE151-4B8C-4355-88DC-3AEF1921B2D7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}.Release|Any CPU.Build.0 = Release|Any CPU
{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{501BE151-4B8C-4355-88DC-3AEF1921B2D7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<configSections>
<section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="file" xsi:type="File" fileName="${basedir}/log.txt"
layout="${date} ${level}: &lt;${logger:shortName=true}&gt; ${message} ${exception:format=tostring}"/>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="file" />
</rules>
</nlog>
<appSettings>
<add key="rabbitmq.host" value="localhost"/>
<add key="rabbitmq.user" value="keero"/>
<add key="rabbitmq.password" value="keero"/>
<add key="rabbitmq.vhost" value="keero"/>
<add key="rabbitmq.resultExchange" value=""/>
<add key="rabbitmq.resultRoutingKey" value="-execution-results"/>
<add key="rabbitmq.durableMessages" value="true"/>
</appSettings>
</configuration>

View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mirantis.Keero.WindowsAgent
{
class ExecutionPlan
{
public class Command
{
public string Name { get; set; }
public Dictionary<string, object> Arguments { get; set; }
}
public string[] Scripts { get; set; }
public LinkedList<Command> Commands { get; set; }
public int RebootOnCompletion { get; set; }
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mirantis.Keero.WindowsAgent
{
class MqMessage
{
private readonly Action ackFunc;
public MqMessage(Action ackFunc)
{
this.ackFunc = ackFunc;
}
public MqMessage()
{
}
public string Body { get; set; }
public string Id { get; set; }
public void Ack()
{
ackFunc();
}
}
}

View File

@ -1,176 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using NLog;
using Newtonsoft.Json;
namespace Mirantis.Keero.WindowsAgent
{
class PlanExecutor
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
class ExecutionResult
{
public bool IsException { get; set; }
public object Result { get; set; }
}
private readonly string path;
public PlanExecutor(string path)
{
this.path = path;
}
public bool RebootNeeded { get; set; }
public void Execute()
{
RebootNeeded = false;
var resultPath = this.path + ".result";
Runspace runSpace = null;
try
{
var plan = JsonConvert.DeserializeObject<ExecutionPlan>(File.ReadAllText(this.path));
List<ExecutionResult> currentResults = null;
try
{
currentResults = JsonConvert.DeserializeObject<List<ExecutionResult>>(File.ReadAllText(resultPath));
}
catch
{
currentResults = new List<ExecutionResult>();
}
runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
var runSpaceInvoker = new RunspaceInvoke(runSpace);
runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
if (plan.Scripts != null)
{
foreach (var script in plan.Scripts)
{
runSpaceInvoker.Invoke(Encoding.UTF8.GetString(Convert.FromBase64String(script)));
}
}
while (plan.Commands != null && plan.Commands.Any())
{
var command = plan.Commands.First();
var pipeline = runSpace.CreatePipeline();
var psCommand = new Command(command.Name);
if (command.Arguments != null)
{
foreach (var kvp in command.Arguments)
{
psCommand.Parameters.Add(kvp.Key, kvp.Value);
}
}
Log.Info("Executing {0} {1}", command.Name, string.Join(" ",
(command.Arguments ?? new Dictionary<string, object>()).Select(
t => string.Format("{0}={1}", t.Key, t.Value == null ? "null" : t.Value.ToString()))));
pipeline.Commands.Add(psCommand);
try
{
var result = pipeline.Invoke();
if (result != null)
{
currentResults.Add(new ExecutionResult {
IsException = false,
Result = result.Select(SerializePsObject).Where(obj => obj != null).ToList()
});
}
}
catch (Exception exception)
{
currentResults.Add(new ExecutionResult {
IsException = true,
Result = new[] {
exception.GetType().FullName, exception.Message
}
});
break;
}
finally
{
plan.Commands.RemoveFirst();
File.WriteAllText(path, JsonConvert.SerializeObject(plan));
File.WriteAllText(resultPath, JsonConvert.SerializeObject(currentResults));
}
}
runSpace.Close();
var executionResult = JsonConvert.SerializeObject(new ExecutionResult {
IsException = false,
Result = currentResults
}, Formatting.Indented);
if (plan.RebootOnCompletion > 0)
{
if (plan.RebootOnCompletion == 1)
{
RebootNeeded = !currentResults.Any(t => t.IsException);
}
else
{
RebootNeeded = true;
}
}
File.WriteAllText(resultPath, executionResult);
}
catch (Exception ex)
{
File.WriteAllText(resultPath, JsonConvert.SerializeObject(new ExecutionResult {
IsException = true,
Result = ex.Message
}, Formatting.Indented));
}
finally
{
if (runSpace != null)
{
try
{
runSpace.Close();
}
catch
{}
}
}
}
private static object SerializePsObject(PSObject obj)
{
if (obj.BaseObject is PSCustomObject)
{
var result = new Dictionary<string, object>();
foreach (var property in obj.Properties.Where(p => p.IsGettable))
{
try
{
result[property.Name] = property.Value.ToString();
}
catch
{
}
}
return result;
}
else
{
return obj.BaseObject;
}
}
}
}

View File

@ -1,168 +0,0 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Net;
using System.Text;
using System.Threading;
using NLog;
namespace Mirantis.Keero.WindowsAgent
{
[DisplayName("Keero Agent")]
sealed public class Program : WindowsService
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private volatile bool stop;
private Thread thread;
private RabbitMqClient rabbitMqClient;
private int delayFactor = 1;
private string plansDir;
static void Main(string[] args)
{
Start(new Program(), args);
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
Log.Info("Version 0.3");
this.rabbitMqClient = new RabbitMqClient();
var basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
this.plansDir = Path.Combine(basePath, "plans");
if (!Directory.Exists(plansDir))
{
Directory.CreateDirectory(plansDir);
}
this.thread = new Thread(Loop);
this.thread.Start();
}
void Loop()
{
const string unknownName = "unknown";
while (!stop)
{
try
{
foreach (var file in Directory.GetFiles(this.plansDir, "*.json.result")
.Where(file => !File.Exists(Path.Combine(this.plansDir, Path.GetFileNameWithoutExtension(file)))))
{
var id = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file)) ?? unknownName;
if (id.Equals(unknownName, StringComparison.InvariantCultureIgnoreCase))
{
id = "";
}
var result = File.ReadAllText(file);
Log.Info("Sending results for {0}", id ?? unknownName);
rabbitMqClient.SendResult(new MqMessage { Body = result, Id = id });
File.Delete(file);
}
var path = Directory.EnumerateFiles(this.plansDir, "*.json").FirstOrDefault();
if (path == null)
{
var message = rabbitMqClient.GetMessage();
var id = message.Id;
if(string.IsNullOrEmpty(id))
{
id = unknownName;
}
path = Path.Combine(this.plansDir, string.Format("{0}.json", id));
File.WriteAllText(path, message.Body);
Log.Info("Received new execution plan {0}", id);
message.Ack();
}
else
{
var id = Path.GetFileNameWithoutExtension(path);
Log.Info("Executing exising plan {0}", id);
}
var executor = new PlanExecutor(path);
executor.Execute();
File.Delete(path);
delayFactor = 1;
if (stop) break;
if (executor.RebootNeeded)
{
Reboot();
}
}
catch (Exception exception)
{
WaitOnException(exception);
}
}
}
private void Reboot()
{
Log.Info("Going for reboot!!");
LogManager.Flush();
/*try
{
System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0");
}
catch (Exception ex)
{
Log.ErrorException("Cannot execute shutdown.exe", ex);
}*/
try
{
PowerShell.Create().AddCommand("Restart-Computer").AddParameter("Force").Invoke();
}
catch (Exception exception)
{
Log.FatalException("Reboot exception", exception);
}
finally
{
Log.Info("Waiting for reboot");
for (var i = 0; i < 10 * 60 * 5 && !stop; i++)
{
Thread.Sleep(100);
}
Log.Info("Done waiting for reboot");
}
}
private void WaitOnException(Exception exception)
{
if (stop) return;
Log.WarnException("Exception in main loop", exception);
var i = 0;
while (!stop && i < 10 * (delayFactor * delayFactor))
{
Thread.Sleep(100);
i++;
}
delayFactor = Math.Min(delayFactor + 1, 6);
}
protected override void OnStop()
{
stop = true;
this.rabbitMqClient.Dispose();
base.OnStop();
}
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsAgent")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsAgent")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9591bf2c-f38b-47e0-a39d-ea9849356371")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,128 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using NLog;
using RabbitMQ.Client;
namespace Mirantis.Keero.WindowsAgent
{
class RabbitMqClient : IDisposable
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static readonly ConnectionFactory connectionFactory;
private IConnection currentConnecton;
static RabbitMqClient()
{
connectionFactory = new ConnectionFactory {
HostName = ConfigurationManager.AppSettings["rabbitmq.host"] ?? "localhost",
UserName = ConfigurationManager.AppSettings["rabbitmq.user"] ?? "guest",
Password = ConfigurationManager.AppSettings["rabbitmq.password"] ??"guest",
Protocol = Protocols.FromEnvironment(),
VirtualHost = ConfigurationManager.AppSettings["rabbitmq.vhost"] ?? "/",
RequestedHeartbeat = 10
};
}
public RabbitMqClient()
{
}
public MqMessage GetMessage()
{
var queueName = ConfigurationManager.AppSettings["rabbitmq.inputQueue"] ?? Dns.GetHostName().ToLower();
try
{
IConnection connection = null;
lock (this)
{
connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
}
var session = connection.CreateModel();
session.BasicQos(0, 1, false);
//session.QueueDeclare(queueName, true, false, false, null);
var consumer = new QueueingBasicConsumer(session);
var consumeTag = session.BasicConsume(queueName, false, consumer);
var e = (RabbitMQ.Client.Events.BasicDeliverEventArgs) consumer.Queue.Dequeue();
Action ackFunc = delegate {
session.BasicAck(e.DeliveryTag, false);
session.BasicCancel(consumeTag);
session.Close();
};
return new MqMessage(ackFunc) {
Body = Encoding.UTF8.GetString(e.Body),
Id = e.BasicProperties.MessageId
};
}
catch (Exception exception)
{
Dispose();
throw;
}
}
public void SendResult(MqMessage message)
{
var exchangeName = ConfigurationManager.AppSettings["rabbitmq.resultExchange"] ?? "";
var resultRoutingKey = ConfigurationManager.AppSettings["rabbitmq.resultRoutingKey"] ?? "-execution-results";
bool durable = bool.Parse(ConfigurationManager.AppSettings["rabbitmq.durableMessages"] ?? "true");
try
{
IConnection connection = null;
lock (this)
{
connection = this.currentConnecton = this.currentConnecton ?? connectionFactory.CreateConnection();
}
var session = connection.CreateModel();
/*if (!string.IsNullOrEmpty(resultQueue))
{
//session.QueueDeclare(resultQueue, true, false, false, null);
if (!string.IsNullOrEmpty(exchangeName))
{
session.ExchangeBind(exchangeName, resultQueue, resultQueue);
}
}*/
var basicProperties = session.CreateBasicProperties();
basicProperties.SetPersistent(durable);
basicProperties.MessageId = message.Id;
basicProperties.ContentType = "application/json";
session.BasicPublish(exchangeName, resultRoutingKey, basicProperties, Encoding.UTF8.GetBytes(message.Body));
session.Close();
}
catch (Exception)
{
Dispose();
throw;
}
}
public void Dispose()
{
lock (this)
{
try
{
if (this.currentConnecton != null)
{
this.currentConnecton.Close();
}
}
catch
{
}
finally
{
this.currentConnecton = null;
}
}
}
}
}

View File

@ -1,37 +0,0 @@
{
"Scripts":
[
"ZnVuY3Rpb24gdDMgeyAxMjsgcmV0dXJuICJ0ZXN0IiB9",
"ZnVuY3Rpb24gTmV3LVBlcnNvbigpDQp7DQogIHBhcmFtICgkRmlyc3ROYW1lLCAkTGFzdE5hbWUsICRQaG9uZSkNCg0KICAkcGVyc29uID0gbmV3LW9iamVjdCBQU09iamVjdA0KDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBGaXJzdCAtVmFsdWUgJEZpcnN0TmFtZQ0KICAkcGVyc29uIHwgYWRkLW1lbWJlciAtdHlwZSBOb3RlUHJvcGVydHkgLU5hbWUgTGFzdCAtVmFsdWUgJExhc3ROYW1lDQogICRwZXJzb24gfCBhZGQtbWVtYmVyIC10eXBlIE5vdGVQcm9wZXJ0eSAtTmFtZSBQaG9uZSAtVmFsdWUgJFBob25lDQoNCiAgcmV0dXJuICRwZXJzb24NCn0=",
"ZnVuY3Rpb24gVGVzdFRocm93KCkNCnsNCglUaHJvdyBbc3lzdGVtLkluZGV4T3V0T2ZSYW5nZUV4Y2VwdGlvbl0gDQp9"
],
"Commands" :
[
{
"Name": "New-Person",
"Arguments" :
{
"FirstName": "MyFirstName",
"LastName": "MyLastName",
"Phone": "123-456"
}
},
{
"Name": "t3",
"Arguments" :
{
}
},
{
"Name": "Get-Date",
},
{
"Name": "TestThrow",
}
],
"RebootOnCompletion": 0
}

View File

@ -1,111 +0,0 @@
using System;
using System.Configuration.Install;
using System.Reflection;
using System.ServiceProcess;
using NLog;
namespace Mirantis.Keero.WindowsAgent
{
public class ServiceManager
{
private readonly string serviceName;
public ServiceManager(string serviceName)
{
this.serviceName = serviceName;
}
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public bool Restart(string[] args, TimeSpan timeout)
{
var service = new ServiceController(serviceName);
try
{
var millisec1 = TimeSpan.FromMilliseconds(Environment.TickCount);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
Log.Info("Service is stopped");
// count the rest of the timeout
var millisec2 = TimeSpan.FromMilliseconds(Environment.TickCount);
timeout = timeout - (millisec2 - millisec1);
service.Start(args);
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
Log.Info("Service has started");
return true;
}
catch (Exception ex)
{
Log.ErrorException("Cannot restart service " + serviceName, ex);
return false;
}
}
public bool Stop(TimeSpan timeout)
{
var service = new ServiceController(serviceName);
try
{
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
return true;
}
catch (Exception ex)
{
Log.ErrorException("Cannot stop service " + serviceName, ex);
return false;
}
}
public bool Start(string[] args, TimeSpan timeout)
{
var service = new ServiceController(serviceName);
try
{
service.Start(args);
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return true;
}
catch (Exception ex)
{
Log.ErrorException("Cannot start service " + serviceName, ex);
return false;
}
}
public bool Install()
{
try
{
ManagedInstallerClass.InstallHelper(
new string[] { Assembly.GetEntryAssembly().Location });
}
catch(Exception ex)
{
Log.ErrorException("Cannot install service " + serviceName, ex);
return false;
}
return true;
}
public bool Uninstall()
{
try
{
ManagedInstallerClass.InstallHelper(
new string[] { "/u", Assembly.GetEntryAssembly().Location });
}
catch (Exception ex)
{
Log.ErrorException("Cannot uninstall service " + serviceName, ex);
return false;
}
return true;
}
}
}

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F7E2A8D5-6D24-4651-A4BC-1024D59F4903}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Mirantis.Keero.WindowsAgent</RootNamespace>
<AssemblyName>WindowsAgent</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog">
<HintPath>..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="RabbitMQ.Client">
<HintPath>..\packages\RabbitMQ.Client.3.0.2\lib\net30\RabbitMQ.Client.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core" />
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll</HintPath>
</Reference>
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ExecutionPlan.cs" />
<Compile Include="MqMessage.cs" />
<Compile Include="PlanExecutor.cs" />
<Compile Include="Program.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RabbitMqClient.cs" />
<Compile Include="ServiceManager.cs" />
<Compile Include="WindowsService.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="WindowsServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="SampleExecutionPlan.json" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>$(SolutionDir)Tools\nuget install $(ProjectDir)packages.config -o $(SolutionDir)Packages</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -1,95 +0,0 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
using NLog;
namespace Mirantis.Keero.WindowsAgent
{
public abstract class WindowsService : ServiceBase
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public bool RunningAsService { get; private set; }
protected static void Start(WindowsService service, string[] arguments)
{
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
if (arguments.Contains("/install", StringComparer.OrdinalIgnoreCase))
{
new ServiceManager(service.ServiceName).Install();
}
else if (arguments.Contains("/uninstall", StringComparer.OrdinalIgnoreCase))
{
new ServiceManager(service.ServiceName).Uninstall();
}
else if (arguments.Contains("/start", StringComparer.OrdinalIgnoreCase))
{
new ServiceManager(service.ServiceName).Start(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
}
else if (arguments.Contains("/stop", StringComparer.OrdinalIgnoreCase))
{
new ServiceManager(service.ServiceName).Stop(TimeSpan.FromMinutes(1));
}
else if (arguments.Contains("/restart", StringComparer.OrdinalIgnoreCase))
{
new ServiceManager(service.ServiceName).Restart(Environment.GetCommandLineArgs(), TimeSpan.FromMinutes(1));
}
else if (!arguments.Contains("/console", StringComparer.OrdinalIgnoreCase))
{
service.RunningAsService = true;
Run(service);
}
else
{
try
{
service.RunningAsService = false;
Console.Title = service.ServiceName;
service.OnStart(Environment.GetCommandLineArgs());
service.WaitForExitSignal();
}
finally
{
service.OnStop();
service.Dispose();
}
}
}
protected WindowsService()
{
var displayNameAttribute =
this.GetType().GetCustomAttributes(typeof (DisplayNameAttribute), false).Cast<DisplayNameAttribute>().
FirstOrDefault();
if(displayNameAttribute != null)
{
ServiceName = displayNameAttribute.DisplayName;
}
}
protected virtual void WaitForExitSignal()
{
Console.WriteLine("Press ESC to exit");
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
}
}
protected override void OnStart(string[] args)
{
Log.Info("Service {0} started", ServiceName);
base.OnStart(args);
}
protected override void OnStop()
{
Log.Info("Service {0} exited", ServiceName);
base.OnStop();
}
}
}

View File

@ -1,39 +0,0 @@
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
namespace Mirantis.Keero.WindowsAgent
{
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
public WindowsServiceInstaller()
{
var processInstaller = new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem };
foreach (var type in Assembly.GetEntryAssembly().GetExportedTypes().Where(t => t.IsSubclassOf(typeof(ServiceBase))))
{
var nameAttribute = type.GetCustomAttributes(typeof (DisplayNameAttribute), false)
.Cast<DisplayNameAttribute>().FirstOrDefault();
if(nameAttribute == null) continue;
var serviceInstaller = new ServiceInstaller {
StartType = ServiceStartMode.Automatic,
ServiceName = nameAttribute.DisplayName,
DisplayName = nameAttribute.DisplayName
};
var descriptionAttribute = type.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>().FirstOrDefault();
if(descriptionAttribute != null)
{
serviceInstaller.Description = descriptionAttribute.Description;
}
Installers.Add(serviceInstaller);
}
Installers.Add(processInstaller);
}
}
}

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
<package id="NLog" version="2.0.0.2000" targetFramework="net45" />
<package id="RabbitMQ.Client" version="3.0.2" targetFramework="net45" />
</packages>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\WindowsAgent\packages.config" />
</repositories>

23
api/.gitignore vendored
View File

@ -1,23 +0,0 @@
#IntelJ Idea
.idea/
#virtualenv
.venv/
#Build results
build/
dist/
*.egg-info/
#Python
*.pyc
#Translation build
*.mo
*.pot
#SQLite Database files
*.sqlite
#Autogenerated Documentation
doc/source/api

View File

@ -1,7 +0,0 @@
Glazier API README
=====================
Glazier API is a project that provides access to engine via API.
SEE ALSO
--------
* `Glazier <http://glazier.mirantis.com>`__

View File

@ -1 +0,0 @@
[python: **.py]

View File

@ -1,54 +0,0 @@
#!/usr/bin/env python
#
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
import gettext
import os
import sys
# If ../glazierapi/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
from glazierapi.common.service import TaskResultHandlerService
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
os.pardir,
os.pardir))
if os.path.exists(os.path.join(possible_topdir, 'portas', '__init__.py')):
sys.path.insert(0, possible_topdir)
from glazierapi.common import config
from glazierapi.openstack.common import log
from glazierapi.openstack.common import wsgi
from glazierapi.openstack.common import service
gettext.install('glazierapi', './glazierapi/locale', unicode=1)
if __name__ == '__main__':
try:
config.parse_args()
log.setup('glazierapi')
launcher = service.ServiceLauncher()
api_service = wsgi.Service(config.load_paste_app(),
port=config.CONF.bind_port,
host=config.CONF.bind_host)
launcher.launch_service(api_service)
launcher.launch_service(TaskResultHandlerService())
launcher.wait()
except RuntimeError, e:
sys.stderr.write("ERROR: %s\n" % e)
sys.exit(1)

View File

@ -1,2 +0,0 @@
[theme]
inherit = default

View File

@ -1,241 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2010 OpenStack Foundation.
#
# 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.
#
# Portas documentation build configuration file, created by
# sphinx-quickstart on Tue February 28 13:50:15 2013.
#
# This file is execfile()'d with the current directory set to its containing
# dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path = [os.path.abspath('../../glazierapi'),
os.path.abspath('../..'),
os.path.abspath('../../bin')] + sys.path
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.pngmath',
'sphinx.ext.ifconfig',
'sphinx.ext.graphviz']
# Add any paths that contain templates here, relative to this directory.
templates_path = []
if os.getenv('HUDSON_PUBLISH_DOCS'):
templates_path = ['_ga', '_templates']
else:
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Glazier APIs'
copyright = u'2013, Mirantis, Inc'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
from glazierapi.version import version_info as portas_version
# The full version, including alpha/beta/rc tags.
release = portas_version.version_string_with_vcs()
# The short X.Y version.
version = portas_version.canonical_version_string()
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['api']
# The reST default role (for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
show_authors = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['glazierapi.']
# -- Options for man page output --------------------------------------------
# Grouping the document tree for man pages.
# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual'
man_pages = [
('man/glazierapi', 'glazier-api', u'Glazier API Server',
[u'Mirantis, Inc'], 1)
]
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme_path = ["."]
html_theme = '_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = ['_theme']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1"
html_last_updated_fmt = os.popen(git_cmd).read()
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
html_use_modindex = False
# If false, no index is generated.
html_use_index = False
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'glazierapidoc'
# -- Options for LaTeX output ------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author,
# documentclass [howto/manual]).
latex_documents = [
('index', 'Glazier.tex', u'Glazier Documentation',
u'Mirantis, Inc', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('http://docs.python.org/', None)}

View File

@ -1,114 +0,0 @@
..
Copyright (c) 2013 Mirantis, Inc.
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.
==============================================
Welcome to Glazier API Service!
==============================================
Glazier API is a project that provides access to engine via API.
This document describes Glazier API for contributors of the project,
and assumes that you are already familiar with Glazier API from an
`end-user perspective`_.
.. _`end-user perspective`: http://glazier.mirantis.com/
This documentation is generated by the Sphinx toolkit and lives in the source
tree.
Installation Guide
==================
Install
-------
1. Check out sources to some directory (<home>/glazier)::
user@work:~/$ git clone ssh://<user>@gerrit.mirantis.com:29418/keero/keero.git
2. Install Glazier API::
user@work:~/$ cd glazier/api && sudo python setup.py install
Configure
---------
1. Open first configuration file for editing::
user@work:~/$ cd glazier/api/etc && nano glazier-api.conf
2. Configure according to you environment (please note rabbitmq section)::
[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/glazier-api.log
#A valid SQLAlchemy connection string for the metadata database
sql_connection = sqlite:///glazier.sqlite
[reports]
results_exchange = task-results
results_queue = task-results
reports_exchange = task-reports
reports_queue = task-reports
[rabbitmq]
host = localhost
port = 5672
virtual_host = keero
login = keero
password = keero
3. Open second configuration file for editing::
smelikyan@work:~/cd glazier/api/etc && nano glazier-api.conf
4. Configure according to you environment (please note filter:authtoken section)::
[pipeline:glazier-api]
pipeline = authtoken context apiv1app
[app:apiv1app]
paste.app_factory = glazierapi.api.v1.router:API.factory
[filter:context]
paste.filter_factory = glazierapi.api.middleware.context:ContextMiddleware.factory
[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
auth_host = localhost
auth_port = 35357
auth_protocol = http
admin_tenant_name = admin
admin_user = admin
admin_password = password
signing_dir = /tmp/keystone-signing-glazierapi
Run
----
Run Glazier API and supply valid configuration file::
user@work:~/$ glazier-api --config-file=./glazier/api/etc/glazier-api.conf
Man Pages
=========
.. toctree::
:maxdepth: 1
man/glazierapi

View File

@ -1,69 +0,0 @@
..
Copyright (c) 2013 Mirantis, Inc.
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.
==========
glazier-api
==========
-----------------------------
Glazier API Server
-----------------------------
:Author: smelikyan@mirantis.com
:Date: 2013-04-04
:Copyright: Mirantis, Inc.
:Version: 2013.1-dev
:Manual section: 1
:Manual group: cloud computing
SYNOPSIS
========
glazier-api [options]
DESCRIPTION
===========
glazier-api is a server daemon that serves the Glazier API
OPTIONS
=======
**General options**
**-v, --verbose**
Print more verbose output
**--config-file**
Config file used for running service
**--bind-host=HOST**
Address of host running ``glazier-api``. Defaults to `0.0.0.0`.
**--bind-port=PORT**
Port that ``glazier-api`` listens on. Defaults to `8082`.
FILES
=====
* /etc/glazier/glazier-api.conf
* /etc/glazier/glazier-api-paste.conf
SEE ALSO
========
* `Glazier <http://glazier.mirantis.com>`__

View File

@ -1,18 +0,0 @@
[pipeline:glazier-api]
pipeline = authtoken context apiv1app
[app:apiv1app]
paste.app_factory = glazierapi.api.v1.router:API.factory
[filter:context]
paste.filter_factory = glazierapi.api.middleware.context:ContextMiddleware.factory
[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
auth_host = localhost
auth_port = 35357
auth_protocol = http
admin_tenant_name = admin
admin_user = admin
admin_password = password
signing_dir = /tmp/keystone-signing-portas

View File

@ -1,32 +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/portas-api.log
#A valid SQLAlchemy connection string for the metadata database
sql_connection = sqlite:///glazier.sqlite
[reports]
results_exchange = task-results
results_queue = task-results
reports_exchange = task-reports
reports_queue = task-reports
[rabbitmq]
host = localhost
port = 5672
virtual_host = keero
login = keero
password = keero

View File

@ -1,13 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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.

View File

@ -1,14 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg

View File

@ -1,14 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg

View File

@ -1,86 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
import json
from oslo.config import cfg
import webob.exc
from glazierapi.openstack.common import wsgi
import glazierapi.context
import glazierapi.openstack.common.log as logging
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class BaseContextMiddleware(wsgi.Middleware):
def process_response(self, resp):
try:
request_id = resp.request.context.request_id
except AttributeError:
LOG.warn(_('Unable to retrieve request id from context'))
else:
resp.headers['x-openstack-request-id'] = 'req-%s' % request_id
return resp
class ContextMiddleware(BaseContextMiddleware):
def process_request(self, req):
"""Convert authentication information into a request context
Generate a glazierapi.context.RequestContext object from the available
authentication headers and store on the 'context' attribute
of the req object.
:param req: wsgi request object that will be given the context object
:raises webob.exc.HTTPUnauthorized: when value of the X-Identity-Status
header is not 'Confirmed' and
anonymous access is disallowed
"""
if req.headers.get('X-Identity-Status') == 'Confirmed':
roles_header = req.headers.get('X-Roles', '')
roles = [r.strip().lower() for r in roles_header.split(',')]
#NOTE(bcwaldon): This header is deprecated in favor of X-Auth-Token
deprecated_token = req.headers.get('X-Storage-Token')
service_catalog = None
if req.headers.get('X-Service-Catalog') is not None:
try:
catalog_header = req.headers.get('X-Service-Catalog')
service_catalog = json.loads(catalog_header)
except ValueError:
raise webob.exc.HTTPInternalServerError(
_('Invalid service catalog json.'))
kwargs = {
'user': req.headers.get('X-User-Id'),
'tenant': req.headers.get('X-Tenant-Id'),
'roles': roles,
'auth_token': req.headers.get('X-Auth-Token',
deprecated_token),
'service_catalog': service_catalog,
'session': req.headers.get('X-Configuration-Session')
}
req.context = glazierapi.context.RequestContext(**kwargs)
else:
raise webob.exc.HTTPUnauthorized()
@classmethod
def factory(cls, global_conf, **local_conf):
def filter(app):
return cls(app)
return filter

View File

@ -1,110 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from glazierapi.db.models import Session, Environment, Status
from glazierapi.db.session import get_session
def get_draft(environment_id=None, session_id=None):
unit = get_session()
#TODO: When session is deployed should be returned env.description
if session_id:
session = unit.query(Session).get(session_id)
return session.description
else:
environment = unit.query(Environment).get(environment_id)
return environment.description
def save_draft(session_id, draft):
unit = get_session()
session = unit.query(Session).get(session_id)
session.description = draft
session.save(unit)
def get_env_status(environment_id, session_id):
status = 'draft'
unit = get_session()
if not session_id:
variants = ['open', 'deploying']
session = unit.query(Session).filter(
Session.environment_id == environment_id and
Session.state.in_(variants)
).first()
if session:
session_id = session.id
else:
return status
session_state = unit.query(Session).get(session_id).state
reports_count = unit.query(Status).filter_by(environment_id=environment_id,
session_id=session_id).count()
if session_state == 'deployed':
status = 'finished'
if session_state == 'deploying' and reports_count > 1:
status = 'pending'
draft = get_draft(environment_id, session_id)
if not 'services' in draft:
return 'pending'
def get_statuses(type):
if type in draft['services']:
services = draft['services'][type]
return [get_service_status(environment_id,
session_id,
service) for service in services]
else:
return []
is_inprogress = filter(lambda item: item == 'inprogress',
get_statuses('activeDirectories') +
get_statuses('webServers'))
if session_state == 'deploying' and is_inprogress > 1:
status = 'inprogress'
return status
def get_service_status(environment_id, session_id, service):
status = 'draft'
unit = get_session()
session_state = unit.query(Session).get(session_id).state
entities = [u['id'] for u in service['units']]
reports_count = unit.query(Status).filter(
Status.environment_id == environment_id
and Status.session_id == session_id
and Status.entity_id.in_(entities)
).count()
if session_state == 'deployed':
status = 'finished'
if session_state == 'deploying' and reports_count == 0:
status = 'pending'
if session_state == 'deploying' and reports_count > 0:
status = 'inprogress'
return status

View File

@ -1,85 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from glazierapi import utils
from glazierapi.api.v1 import save_draft, get_draft, get_service_status
from glazierapi.common import uuidutils
from glazierapi.openstack.common import wsgi, timeutils
from glazierapi.openstack.common import log as logging
log = logging.getLogger(__name__)
class Controller(object):
def index(self, request, environment_id):
log.debug(_('ActiveDirectory:Index <EnvId: {0}>'.
format(environment_id)))
draft = prepare_draft(get_draft(environment_id,
request.context.session))
for dc in draft['services']['activeDirectories']:
dc['status'] = get_service_status(environment_id,
request.context.session,
dc)
return {'activeDirectories': draft['services']['activeDirectories']}
@utils.verify_session
def create(self, request, environment_id, body):
log.debug(_('ActiveDirectory:Create <EnvId: {0}, Body: {1}>'.
format(environment_id, body)))
draft = get_draft(session_id=request.context.session)
active_directory = body.copy()
active_directory['id'] = uuidutils.generate_uuid()
active_directory['created'] = str(timeutils.utcnow())
active_directory['updated'] = str(timeutils.utcnow())
unit_count = 0
for unit in active_directory['units']:
unit_count += 1
unit['id'] = uuidutils.generate_uuid()
unit['name'] = 'dc{0}'.format(unit_count)
draft = prepare_draft(draft)
draft['services']['activeDirectories'].append(active_directory)
save_draft(request.context.session, draft)
return active_directory
def delete(self, request, environment_id, active_directory_id):
log.debug(_('ActiveDirectory:Delete <EnvId: {0}, Id: {1}>'.
format(environment_id, active_directory_id)))
draft = get_draft(request.context.session)
items = [service for service in draft['services']['activeDirectories']
if service['id'] != active_directory_id]
draft['services']['activeDirectories'] = items
save_draft(request.context.session, draft)
def prepare_draft(draft):
if not 'services' in draft:
draft['services'] = {}
if not 'activeDirectories' in draft['services']:
draft['services']['activeDirectories'] = []
return draft
def create_resource():
return wsgi.Resource(Controller())

View File

@ -1,132 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from amqplib.client_0_8 import Message
import anyjson
import eventlet
from webob import exc
from glazierapi.common import config
from glazierapi.api.v1 import get_env_status
from glazierapi.db.session import get_session
from glazierapi.db.models import Environment
from glazierapi.openstack.common import wsgi
from glazierapi.openstack.common import log as logging
amqp = eventlet.patcher.import_patched('amqplib.client_0_8')
rabbitmq = config.CONF.rabbitmq
log = logging.getLogger(__name__)
class Controller(object):
def index(self, request):
log.debug(_('Environments:List'))
#Only environments from same tenant as users should be shown
filters = {'tenant_id': request.context.tenant}
session = get_session()
environments = session.query(Environment).filter_by(**filters)
environments = [env.to_dict() for env in environments]
for env in environments:
env['status'] = get_env_status(env['id'], request.context.session)
return {"environments": environments}
def create(self, request, body):
log.debug(_('Environments:Create <Body {0}>'.format(body)))
#tagging environment by tenant_id for later checks
params = body.copy()
params['tenant_id'] = request.context.tenant
environment = Environment()
environment.update(params)
session = get_session()
with session.begin():
session.add(environment)
#saving environment as Json to itself
environment.update({"description": environment.to_dict()})
environment.save(session)
return environment.to_dict()
def show(self, request, environment_id):
log.debug(_('Environments:Show <Id: {0}>'.format(environment_id)))
session = get_session()
environment = session.query(Environment).get(environment_id)
if environment.tenant_id != request.context.tenant:
log.info('User is not authorized to access this tenant resources.')
raise exc.HTTPUnauthorized
env = environment.to_dict()
env['status'] = get_env_status(environment_id, request.context.session)
return env
def update(self, request, environment_id, body):
log.debug(_('Environments:Update <Id: {0}, Body: {1}>'.
format(environment_id, body)))
session = get_session()
environment = session.query(Environment).get(environment_id)
if environment.tenant_id != request.context.tenant:
log.info('User is not authorized to access this tenant resources.')
raise exc.HTTPUnauthorized
environment.update(body)
environment.save(session)
return environment.to_dict()
def delete(self, request, environment_id):
log.debug(_('Environments:Delete <Id: {0}>'.format(environment_id)))
session = get_session()
environment = session.query(Environment).get(environment_id)
with session.begin():
session.delete(environment)
#preparing data for removal from conductor
env = environment.description
env['services'] = []
env['deleted'] = True
#Set X-Auth-Token for conductor
env['token'] = request.context.auth_token
connection = amqp.Connection('{0}:{1}'.
format(rabbitmq.host, rabbitmq.port),
virtual_host=rabbitmq.virtual_host,
userid=rabbitmq.login,
password=rabbitmq.password,
ssl=rabbitmq.use_ssl, insist=True)
channel = connection.channel()
channel.exchange_declare('tasks', 'direct', durable=True,
auto_delete=False)
channel.basic_publish(Message(body=anyjson.serialize(env)), 'tasks',
'tasks')
return None
def create_resource():
return wsgi.Resource(Controller())

View File

@ -1,106 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
import routes
from glazierapi.openstack.common import wsgi
from glazierapi.api.v1 import (environments, sessions,
active_directories, webservers)
class API(wsgi.Router):
@classmethod
def factory(cls, global_conf, **local_conf):
return cls(routes.Mapper())
def __init__(self, mapper):
environments_resource = environments.create_resource()
mapper.connect('/environments',
controller=environments_resource,
action='index',
conditions={'method': ['GET']})
mapper.connect('/environments',
controller=environments_resource,
action='create',
conditions={'method': ['POST']})
mapper.connect('/environments/{environment_id}',
controller=environments_resource,
action='update',
conditions={'method': ['PUT']})
mapper.connect('/environments/{environment_id}',
controller=environments_resource,
action='show',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}',
controller=environments_resource,
action='delete',
conditions={'method': ['DELETE']})
sessions_resource = sessions.create_resource()
mapper.connect('/environments/{environment_id}/sessions',
controller=sessions_resource,
action='index',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}/configure',
controller=sessions_resource,
action='configure',
conditions={'method': ['POST']})
mapper.connect('/environments/{environment_id}/sessions/{session_id}',
controller=sessions_resource,
action='show',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}/sessions/{session_id}',
controller=sessions_resource,
action='delete',
conditions={'method': ['DELETE']})
mapper.connect('/environments/{environment_id}/sessions/'
'{session_id}/reports',
controller=sessions_resource,
action='reports',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}/sessions/'
'{session_id}/deploy',
controller=sessions_resource,
action='deploy',
conditions={'method': ['POST']})
activeDirectories_resource = active_directories.create_resource()
mapper.connect('/environments/{environment_id}/activeDirectories',
controller=activeDirectories_resource,
action='index',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}/activeDirectories',
controller=activeDirectories_resource,
action='create',
conditions={'method': ['POST']})
mapper.connect('/environments/{environment_id}/activeDirectories/'
'{active_directory_id}',
controller=activeDirectories_resource,
action='delete',
conditions={'method': ['DELETE']})
webServers_resource = webservers.create_resource()
mapper.connect('/environments/{environment_id}/webServers',
controller=webServers_resource,
action='index',
conditions={'method': ['GET']})
mapper.connect('/environments/{environment_id}/webServers',
controller=webServers_resource,
action='create',
conditions={'method': ['POST']})
mapper.connect('/environments/{environment_id}/webServers/'
'{web_server_id}',
controller=webServers_resource,
action='delete',
conditions={'method': ['DELETE']})
super(API, self).__init__(mapper)

View File

@ -1,168 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from amqplib.client_0_8 import Message
import anyjson
import eventlet
from webob import exc
from glazierapi.common import config
from glazierapi.db.models import Session, Status, Environment
from glazierapi.db.session import get_session
from glazierapi.openstack.common import wsgi
from glazierapi.openstack.common import log as logging
amqp = eventlet.patcher.import_patched('amqplib.client_0_8')
rabbitmq = config.CONF.rabbitmq
log = logging.getLogger(__name__)
class Controller(object):
def index(self, request, environment_id):
log.debug(_('Session:List <EnvId: {0}>'.format(environment_id)))
filters = {'environment_id': environment_id,
'user_id': request.context.user}
unit = get_session()
configuration_sessions = unit.query(Session).filter_by(**filters)
sessions = [session.to_dict() for session in configuration_sessions if
session.environment.tenant_id == request.context.tenant]
return {"sessions": sessions}
def configure(self, request, environment_id):
log.debug(_('Session:Configure <EnvId: {0}>'.format(environment_id)))
params = {'environment_id': environment_id,
'user_id': request.context.user, 'state': 'open'}
session = Session()
session.update(params)
unit = get_session()
if unit.query(Session).filter(
Session.environment_id == environment_id and
Session.state.in_(['open', 'deploying'])
).first():
log.info('There is already open session for this environment')
raise exc.HTTPConflict
#create draft for apply later changes
environment = unit.query(Environment).get(environment_id)
session.description = environment.description
with unit.begin():
unit.add(session)
return session.to_dict()
def show(self, request, environment_id, session_id):
log.debug(_('Session:Show <EnvId: {0}, '
'SessionId: {1}>'.format(environment_id, session_id)))
unit = get_session()
session = unit.query(Session).get(session_id)
if session.environment.tenant_id != request.context.tenant:
log.info('User is not authorized to access this tenant resources.')
raise exc.HTTPUnauthorized
return session.to_dict()
def delete(self, request, environment_id, session_id):
log.debug(_('Session:Delete <EnvId: {0}, '
'SessionId: {1}>'.format(environment_id, session_id)))
unit = get_session()
session = unit.query(Session).get(session_id)
comment = 'Session object in \'deploying\' state could not be deleted'
if session.state == 'deploying':
log.info(comment)
raise exc.HTTPForbidden(comment=comment)
with unit.begin():
unit.delete(session)
return None
def reports(self, request, environment_id, session_id):
log.debug(_('Session:Reports <EnvId: {0}, '
'SessionId: {1}>'.format(environment_id, session_id)))
unit = get_session()
statuses = unit.query(Status).filter_by(session_id=session_id).all()
result = statuses
if 'service_id' in request.GET:
service_id = request.GET['service_id']
environment = unit.query(Session).get(session_id).description
services = []
if 'services' in environment and 'activeDirectories' in\
environment['services']:
services += environment['services']['activeDirectories']
if 'services' in environment and 'webServers' in\
environment['services']:
services += environment['services']['webServers']
service = [service for service in services
if service['id'] == service_id][0]
if service:
entities = [u['id'] for u in service['units']]
entities.append(service_id)
result = []
for status in statuses:
if status.entity_id in entities:
result.append(status)
return {'reports': [status.to_dict() for status in result]}
def deploy(self, request, environment_id, session_id):
log.debug(_('Session:Deploy <EnvId: {0}, '
'SessionId: {1}>'.format(environment_id, session_id)))
unit = get_session()
session = unit.query(Session).get(session_id)
msg = _('Could not deploy session. Session is already '
'deployed or in deployment state')
if session.state != 'open':
log.warn(msg)
session.state = 'deploying'
session.save(unit)
#Set X-Auth-Token for conductor
env = session.description
env['token'] = request.context.auth_token
connection = amqp.Connection('{0}:{1}'.
format(rabbitmq.host, rabbitmq.port),
virtual_host=rabbitmq.virtual_host,
userid=rabbitmq.login,
password=rabbitmq.password,
ssl=rabbitmq.use_ssl, insist=True)
channel = connection.channel()
channel.exchange_declare('tasks', 'direct', durable=True,
auto_delete=False)
channel.basic_publish(Message(body=anyjson.serialize(env)), 'tasks',
'tasks')
def create_resource():
return wsgi.Resource(Controller())

View File

@ -1,85 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from glazierapi import utils
from glazierapi.api.v1 import save_draft, get_draft, get_service_status
from glazierapi.common import uuidutils
from glazierapi.openstack.common import wsgi, timeutils
from glazierapi.openstack.common import log as logging
log = logging.getLogger(__name__)
class Controller(object):
def index(self, request, environment_id):
log.debug(_('WebServer:List <EnvId: {0}>'.format(environment_id)))
draft = prepare_draft(get_draft(environment_id,
request.context.session))
for dc in draft['services']['webServers']:
dc['status'] = get_service_status(environment_id,
request.context.session, dc)
return {'webServers': draft['services']['webServers']}
@utils.verify_session
def create(self, request, environment_id, body):
log.debug(_('WebServer:Create <EnvId: {0}, Body: {1}>'.
format(environment_id, body)))
draft = get_draft(session_id=request.context.session)
webServer = body.copy()
webServer['id'] = uuidutils.generate_uuid()
webServer['created'] = str(timeutils.utcnow())
webServer['updated'] = str(timeutils.utcnow())
unit_count = 0
for unit in webServer['units']:
unit_count += 1
unit['id'] = uuidutils.generate_uuid()
unit['name'] = webServer['name'] + '_instance_' + str(unit_count)
draft = prepare_draft(draft)
draft['services']['webServers'].append(webServer)
save_draft(request.context.session, draft)
return webServer
@utils.verify_session
def delete(self, request, environment_id, web_server_id):
log.debug(_('WebServer:Delete <EnvId: {0}, Id: {1}>'.
format(environment_id, web_server_id)))
draft = get_draft(session_id=request.context.session)
elements = [service for service in draft['services']['webServers'] if
service['id'] != web_server_id]
draft['services']['webServers'] = elements
save_draft(request.context.session, draft)
def prepare_draft(draft):
if not 'services' in draft:
draft['services'] = {}
if not 'webServers' in draft['services']:
draft['services']['webServers'] = []
return draft
def create_resource():
return wsgi.Resource(Controller())

View File

@ -1,14 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg

View File

@ -1,205 +0,0 @@
#!/usr/bin/env python
# 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.
"""
Routines for configuring Glance
"""
import logging
import logging.config
import logging.handlers
import os
import sys
from oslo.config import cfg
from paste import deploy
from glazierapi.version import version_info as version
paste_deploy_opts = [
cfg.StrOpt('flavor'),
cfg.StrOpt('config_file'),
]
bind_opts = [
cfg.StrOpt('bind-host', default='0.0.0.0'),
cfg.IntOpt('bind-port', default='8082'),
]
reports_opts = [
cfg.StrOpt('results_exchange', default='task-results'),
cfg.StrOpt('results_queue', default='task-results'),
cfg.StrOpt('reports_exchange', default='task-reports'),
cfg.StrOpt('reports_queue', default='task-reports')
]
rabbit_opts = [
cfg.StrOpt('host', default='localhost'),
cfg.IntOpt('port', default=5672),
cfg.BoolOpt('use_ssl', default=False),
cfg.StrOpt('login', default='guest'),
cfg.StrOpt('password', default='guest'),
cfg.StrOpt('virtual_host', default='/'),
]
CONF = cfg.CONF
CONF.register_opts(paste_deploy_opts, group='paste_deploy')
CONF.register_cli_opts(bind_opts)
# CONF.register_opts(bind_opts)
CONF.register_opts(reports_opts, group='reports')
CONF.register_opts(rabbit_opts, group='rabbitmq')
CONF.import_opt('verbose', 'glazierapi.openstack.common.log')
CONF.import_opt('debug', 'glazierapi.openstack.common.log')
CONF.import_opt('log_dir', 'glazierapi.openstack.common.log')
CONF.import_opt('log_file', 'glazierapi.openstack.common.log')
CONF.import_opt('log_config', 'glazierapi.openstack.common.log')
CONF.import_opt('log_format', 'glazierapi.openstack.common.log')
CONF.import_opt('log_date_format', 'glazierapi.openstack.common.log')
CONF.import_opt('use_syslog', 'glazierapi.openstack.common.log')
CONF.import_opt('syslog_log_facility', 'glazierapi.openstack.common.log')
def parse_args(args=None, usage=None, default_config_files=None):
CONF(args=args,
project='glazierapi',
version=version.cached_version_string(),
usage=usage,
default_config_files=default_config_files)
def setup_logging():
"""
Sets up the logging options for a log with supplied name
"""
if CONF.log_config:
# Use a logging configuration file for all settings...
if os.path.exists(CONF.log_config):
logging.config.fileConfig(CONF.log_config)
return
else:
raise RuntimeError("Unable to locate specified logging "
"config file: %s" % CONF.log_config)
root_logger = logging.root
if CONF.debug:
root_logger.setLevel(logging.DEBUG)
elif CONF.verbose:
root_logger.setLevel(logging.INFO)
else:
root_logger.setLevel(logging.WARNING)
formatter = logging.Formatter(CONF.log_format, CONF.log_date_format)
if CONF.use_syslog:
try:
facility = getattr(logging.handlers.SysLogHandler,
CONF.syslog_log_facility)
except AttributeError:
raise ValueError(_("Invalid syslog facility"))
handler = logging.handlers.SysLogHandler(address='/dev/log',
facility=facility)
elif CONF.log_file:
logfile = CONF.log_file
if CONF.log_dir:
logfile = os.path.join(CONF.log_dir, logfile)
handler = logging.handlers.WatchedFileHandler(logfile)
else:
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
root_logger.addHandler(handler)
def _get_deployment_flavor():
"""
Retrieve the paste_deploy.flavor config item, formatted appropriately
for appending to the application name.
"""
flavor = CONF.paste_deploy.flavor
return '' if not flavor else ('-' + flavor)
def _get_paste_config_path():
paste_suffix = '-paste.ini'
conf_suffix = '.conf'
if CONF.config_file:
# Assume paste config is in a paste.ini file corresponding
# to the last config file
path = CONF.config_file[-1].replace(conf_suffix, paste_suffix)
else:
path = CONF.prog + '-paste.ini'
return CONF.find_file(os.path.basename(path))
def _get_deployment_config_file():
"""
Retrieve the deployment_config_file config item, formatted as an
absolute pathname.
"""
path = CONF.paste_deploy.config_file
if not path:
path = _get_paste_config_path()
if not path:
msg = "Unable to locate paste config file for %s." % CONF.prog
raise RuntimeError(msg)
return os.path.abspath(path)
def load_paste_app(app_name=None):
"""
Builds and returns a WSGI app from a paste config file.
We assume the last config file specified in the supplied ConfigOpts
object is the paste config file.
:param app_name: name of the application to load
:raises RuntimeError when config file cannot be located or application
cannot be loaded from config file
"""
if app_name is None:
app_name = CONF.prog
# append the deployment flavor to the application name,
# in order to identify the appropriate paste pipeline
app_name += _get_deployment_flavor()
conf_file = _get_deployment_config_file()
try:
logger = logging.getLogger(__name__)
logger.debug(_("Loading %(app_name)s from %(conf_file)s"),
{'conf_file': conf_file, 'app_name': app_name})
app = deploy.loadapp("config:%s" % conf_file, name=app_name)
# Log the options used when starting if we're in debug mode...
if CONF.debug:
CONF.log_opt_values(logger, logging.DEBUG)
return app
except (LookupError, ImportError), e:
msg = _("Unable to load %(app_name)s from "
"configuration file %(conf_file)s."
"\nGot: %(e)r") % locals()
logger.error(msg)
raise RuntimeError(msg)

View File

@ -1,116 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
import anyjson
from eventlet import patcher
from glazierapi.db.models import Status, Session, Environment
from glazierapi.db.session import get_session
amqp = patcher.import_patched('amqplib.client_0_8')
from glazierapi.openstack.common import service
from glazierapi.openstack.common import log as logging
from glazierapi.common import config
conf = config.CONF.reports
rabbitmq = config.CONF.rabbitmq
log = logging.getLogger(__name__)
channel = None
class TaskResultHandlerService(service.Service):
def __init__(self, threads=1000):
super(TaskResultHandlerService, self).__init__(threads)
def start(self):
super(TaskResultHandlerService, self).start()
self.tg.add_thread(self._handle_results)
def stop(self):
super(TaskResultHandlerService, self).stop()
def _handle_results(self):
connection = amqp.Connection('{0}:{1}'.
format(rabbitmq.host, rabbitmq.port),
virtual_host=rabbitmq.virtual_host,
userid=rabbitmq.login,
password=rabbitmq.password,
ssl=rabbitmq.use_ssl, insist=True)
ch = connection.channel()
def bind(exchange, queue):
if not exchange:
ch.exchange_declare(exchange, 'direct', durable=True,
auto_delete=False)
ch.queue_declare(queue, durable=True, auto_delete=False)
if not exchange:
ch.queue_bind(queue, exchange, queue)
bind(conf.results_exchange, conf.results_queue)
bind(conf.reports_exchange, conf.reports_queue)
ch.basic_consume(conf.results_exchange, callback=handle_result)
ch.basic_consume(conf.reports_exchange, callback=handle_report,
no_ack=True)
while ch.callbacks:
ch.wait()
def handle_report(msg):
log.debug(_('Got report message from orchestration engine:\n{0}'.
format(msg.body)))
params = anyjson.deserialize(msg.body)
params['entity_id'] = params['id']
del params['id']
status = Status()
status.update(params)
session = get_session()
#connect with session
conf_session = session.query(Session).filter_by(
**{'environment_id': status.environment_id,
'state': 'deploying'}).first()
status.session_id = conf_session.id
with session.begin():
session.add(status)
def handle_result(msg):
log.debug(_('Got result message from '
'orchestration engine:\n{0}'.format(msg.body)))
environment_result = anyjson.deserialize(msg.body)
if 'deleted' in environment_result:
log.debug(_('Result for environment {0} is dropped. '
'Environment is deleted'.format(environment_result['id'])))
msg.channel.basic_ack(msg.delivery_tag)
return
session = get_session()
environment = session.query(Environment).get(environment_result['id'])
environment.description = environment_result
environment.save(session)
#close session
conf_session = session.query(Session).filter_by(
**{'environment_id': environment.id, 'state': 'deploying'}).first()
conf_session.state = 'deployed'
conf_session.save(session)
msg.channel.basic_ack(msg.delivery_tag)

View File

@ -1,19 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
import uuid
def generate_uuid():
return str(uuid.uuid4()).replace('-', '')

View File

@ -1,57 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 glazierapi.openstack.common import uuidutils
class RequestContext(object):
"""
Stores information about the security context under which the user
accesses the system, as well as additional request information.
"""
def __init__(self, auth_token=None, user=None, tenant=None,
roles=None, service_catalog=None, session=None):
self.auth_token = auth_token
self.user = user
self.tenant = tenant
self.roles = roles or []
self.request_id = uuidutils.generate_uuid()
self.service_catalog = service_catalog
self.session = session
def to_dict(self):
# NOTE(ameade): These keys are named to correspond with the default
# format string for logging the context in openstack common
return {
'request_id': self.request_id,
#NOTE(bcwaldon): openstack-common logging expects 'user'
'user': self.user,
'user_id': self.user,
#NOTE(bcwaldon): openstack-common logging expects 'tenant'
'tenant': self.tenant,
'tenant_id': self.tenant,
'project_id': self.tenant,
'roles': self.roles,
'auth_token': self.auth_token,
'session': self.session
}
@classmethod
def from_dict(cls, values):
return cls(**values)

View File

@ -1,26 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from oslo.config import cfg
sql_connection_opt = cfg.StrOpt('sql_connection',
default='sqlite:///glazierapi.sqlite',
secret=True,
metavar='CONNECTION',
help='A valid SQLAlchemy connection '
'string for the metadata database. '
'Default: %(default)s')
CONF = cfg.CONF
CONF.register_opt(sql_connection_opt)

View File

@ -1,4 +0,0 @@
This is a database migration repository.
More information at
http://code.google.com/p/sqlalchemy-migrate/

View File

@ -1 +0,0 @@
# template repository default module

View File

@ -1,20 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from migrate.versioning.shell import main
# This should probably be a console script entry point.
if __name__ == '__main__':
main(debug='False', repository='.')

View File

@ -1,20 +0,0 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
repository_id=Glazier Migrations
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
# If this is changed once a database is under version control, you'll need to
# change the table name in each database too.
version_table=migrate_version
# When committing a change script, Migrate will attempt to generate the
# sql for all supported databases; normally, if one of them fails - probably
# because you don't have that database installed - it is ignored and the
# commit continues, perhaps ending successfully.
# Databases in this list MUST compile successfully during a commit, or the
# entire commit will fail. List the databases your application will actually
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['glazier','sqlite']
required_dbs=[]

View File

@ -1,48 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
from sqlalchemy.types import String, Text, DateTime
meta = MetaData()
Table('environment', meta,
Column('id', String(32), primary_key=True),
Column('name', String(255), nullable=False),
Column('created', DateTime(), nullable=False),
Column('updated', DateTime(), nullable=False),
Column('tenant_id', String(32), nullable=False),
Column('description', Text(), nullable=False),
)
Table('service', meta,
Column('id', String(32), primary_key=True),
Column('name', String(255), nullable=False),
Column('type', String(40), nullable=False),
Column('environment_id', String(32), ForeignKey('environment.id')),
Column('created', DateTime, nullable=False),
Column('updated', DateTime, nullable=False),
Column('description', Text(), nullable=False),
)
def upgrade(migrate_engine):
meta.bind = migrate_engine
meta.create_all()
def downgrade(migrate_engine):
meta.bind = migrate_engine
meta.drop_all()

View File

@ -1,39 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
from sqlalchemy.types import String, Text, DateTime
meta = MetaData()
session = Table('session', meta,
Column('id', String(32), primary_key=True),
Column('environment_id', String(32),
ForeignKey('environment.id')),
Column('created', DateTime, nullable=False),
Column('updated', DateTime, nullable=False),
Column('user_id', String(32), nullable=False),
Column('state', Text(), nullable=False),
)
def upgrade(migrate_engine):
meta.bind = migrate_engine
meta.reflect()
session.create()
def downgrade(migrate_engine):
meta.bind = migrate_engine
session.drop()

View File

@ -1,40 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
from sqlalchemy.types import String, Text, DateTime
meta = MetaData()
status = Table('status', meta,
Column('id', String(32), primary_key=True),
Column('created', DateTime, nullable=False),
Column('updated', DateTime, nullable=False),
Column('entity', String(10), nullable=False),
Column('environment_id', String(32),
ForeignKey('environment.id')),
Column('session_id', String(32), ForeignKey('session.id')),
Column('text', Text(), nullable=False),
)
def upgrade(migrate_engine):
meta.bind = migrate_engine
meta.reflect()
status.create()
def downgrade(migrate_engine):
meta.bind = migrate_engine
status.drop()

View File

@ -1,31 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from sqlalchemy.schema import MetaData, Table, Column
from sqlalchemy.types import Text
meta = MetaData()
def upgrade(migrate_engine):
meta.bind = migrate_engine
session = Table('session', meta, autoload=True)
description = Column('description', Text(), nullable=True, default='{}')
description.create(session)
def downgrade(migrate_engine):
meta.bind = migrate_engine
session = Table('session', meta, autoload=True)
session.c.description.drop()

View File

@ -1,42 +0,0 @@
# Copyright (c) 2013 Mirantis, Inc.
#
# 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 oslo.config import cfg
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
from sqlalchemy.types import String, Text, DateTime
meta = MetaData()
service = Table('service', meta,
Column('id', String(32), primary_key=True),
Column('name', String(255), nullable=False),
Column('type', String(40), nullable=False),
Column('environment_id', String(32),
ForeignKey('environment.id')),
Column('created', DateTime, nullable=False),
Column('updated', DateTime, nullable=False),
Column('description', Text(), nullable=False),
)
def upgrade(migrate_engine):
meta.bind = migrate_engine
meta.reflect()
service.drop()
def downgrade(migrate_engine):
meta.bind = migrate_engine
meta.reflect()
service.create()

Some files were not shown because too many files have changed in this diff Show More