133 lines
5.2 KiB
C#

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.SelfHost;
using System.Web.Http;
using log4net;
using HypervResource;
namespace CloudStack.Plugin.AgentShell
{
public partial class AgentService : ServiceBase
{
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
HttpSelfHostServer server;
private static ILog logger = LogManager.GetLogger(typeof(AgentService));
public AgentService()
{
logger.Info("Starting CloudStack agent");
InitializeComponent();
UriBuilder baseUri = new UriBuilder("https", AgentSettings.Default.private_ip_address, AgentSettings.Default.port);
var config = new HttpSelfHostConfiguration(baseUri.Uri);
// Allow ActionName to be applied to methods in ApiController, which allows it to serve multiple POST URLs
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{action}",
new { action = RouteParameter.Optional }
);
// Load controller assemblies that we want to config to route to.
ConfigServerResource();
AssertControllerAssemblyAvailable(config, typeof(HypervResourceController), "Cannot load Controller of type" + typeof(HypervResourceController));
server = new HttpSelfHostServer(config);
}
public static void ConfigServerResource()
{
// For simplicity, ServerResource config and settings file are tightly coupled.
// An alternative is to pass a dictionary to the server resource and let it find
// required settings. In contrast, the approach below is strongly typed and makes
// use of VisualStudio settings designer. The designer allows us to avoid
// accessing config using their key strings.
HypervResourceControllerConfig rsrcCnf = new HypervResourceControllerConfig();
rsrcCnf.PrivateIpAddress = AgentSettings.Default.private_ip_address;
rsrcCnf.GatewayIpAddress = AgentSettings.Default.gateway_ip_address;
rsrcCnf.RootDeviceReservedSpaceBytes = AgentSettings.Default.RootDeviceReservedSpaceBytes;
rsrcCnf.RootDeviceName = AgentSettings.Default.RootDeviceName;
rsrcCnf.ParentPartitionMinMemoryMb = AgentSettings.Default.dom0MinMemory;
rsrcCnf.LocalSecondaryStoragePath = AgentSettings.Default.local_secondary_storage_path;
rsrcCnf.systemVmIso = null;
// Side effect: loads the assembly containing HypervResourceController, which
// allows HttpSelfHostServer to route requests to the controller.
HypervResourceController.Configure(rsrcCnf);
}
// TODO: update to examine not the assembly resolver, but the list of available controllers themselves!
private static bool AssertControllerAssemblyAvailable(HttpSelfHostConfiguration config, Type controllerType, string errorMessage)
{
var assemblies = config.Services.GetAssembliesResolver().GetAssemblies();
foreach (var assembly in assemblies)
{
string name = assembly.GetName().Name;
if (controllerType.Assembly.GetName().Name.Equals(name))
{
logger.DebugFormat("Controller {0} is available", controllerType.Name);
return true;
}
}
logger.Error(errorMessage);
throw new AgentShellException(errorMessage);
}
protected override void OnStart(string[] args)
{
server.OpenAsync().Wait();
}
protected override void OnStop()
{
server.CloseAsync().Wait();
}
internal void RunConsole(string[] args)
{
OnStart(args);
AllocConsole();
Console.WriteLine("Service running ... press <ENTER> to stop");
Console.ReadLine();
FreeConsole();
OnStop();
}
}
}