// 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.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 to stop"); Console.ReadLine(); FreeConsole(); OnStop(); } } }