5. Developers Giude

These resources are for software developers who want to extend the Atomia Automation Server system and/or create their own plugins, extensions and modules for Atomia.

5.1. API and SDK Reference

Here you can find links to the Atomia Automation Server APIs and SDK.

5.1.1. Atomia Automation Server APIs

Atomia Automation Server system provides four APIs: Core API, Config API, Native API and the Authorization API.

5.1.1.1. Atomia Automation Server Core API

Atomia Automation Server Core API represents main API which exposes a set of methods for managing accounts, their packages and services. A list of all methods can be found in the Atomia Automation Server Core API reference .

5.1.1.2. Atomia Automation Server Native API

Atomia Automation Server Native API is a set of methods for bulk operations over accounts, packages and services. Native API is used for operations over large set of Provisioning objects not connected to just one account, as Provisioning Core API does. A list of all methods is found in the Atomia Automation Server Native API reference .

5.1.1.3. Atomia Automation Server Config API

Atomia Automation Server Config API exposes a set of methods for managing Provisioning descriptions  and Resource descriptions . A list of all methods is found in the Atomia Automation Server Config API reference .

5.1.1.4. Atomia Automation Server Authorization API

Atomia Automation Server Authorization API exploses a set of methods for listing and setting permissions per user or per user groups. A list of all methods is found in the Atomia Automation Server Authorization API reference .

5.1.3. Full Atomia Automation Server Reference

Atomia Automation Server API reference and Atomia Automation Server SDK can be found on the following page: Atomia Automation Server Reference

5.2. Code Examples

5.2.1. Atomia Automation Server Modules - Code Examples

5.2.1.1. ModuleBase methods examples
5.2.1.1.1. Provide service example
               public void ProvideService(ModuleService service, ResourceDescription resource)
               {
               this.PrepareCommandList(service, null, resource, null, ModuleCommandType.Add);
               foreach (ModuleCommand command in this.commands)
               {
               command.Prepare();
               }
               try
               {
               foreach (ModuleCommand command in this.commands)
               {
               command.Execute();
               }
               }
               catch
               {
               // if something goes wrong during the execution of the commands,
               // rollback all performed actions and throw the exception up to the UCPCore
               RollbackTransaction();
               throw;
               }
               }
               private void PrepareCommandList(ModuleService service, ModuleService newServiceSettings, ResourceDescription resource, string commandType)
               {
               if (commandType != ModuleCommandType.Remove)
               {
               this.commands.Add(this.GetModuleCommand(resource, commandType, service, newServiceSettings));
               }
               if (service.Children != null)
               {
               for (int i = 0; i < service.Children.Length; i++)
               {
               ModuleService childService = service.Children[i];
               ModuleService newChildSettings = null;
               if (newServiceSettings != null && newServiceSettings.Children != null && newServiceSettings.Children.Length > i)
               {
               newChildSettings = newServiceSettings.Children[i];
               }
               this.PrepareCommandList(childService, newChildSettings, resource, commandType);
               }
               }
               if (commandType == ModuleCommandType.Remove)
               {
               this.commands.Add(this.GetModuleCommand(resource, targetResource, commandType, service, newServiceSettings));
               }
               }
               private ModuleCommand GetModuleCommand(ResourceDescription resource, string commandType, params ModuleService[] childService)
               {
               ModuleCommand command = null;
               switch (commandType)
               {
               case ModuleCommandType.Add:
               switch (childService[0].Name)
               {
               case ModuleServiceName.LiteSpeedWebSite:
               command = new AddLiteSpeedWebSiteCommand(childService[0], resource);
               break;
               case ModuleServiceName.LiteSpeedListener:
               command = new AddLiteSpeedListenerCommand(childService[0], resource);
               break;
               ....
               }
               break;
               case ModuleCommandType.Remove:
               switch (childService[0].Name)
               {
               case ModuleServiceName.LiteSpeedWebSite:
               command = new RemoveLiteSpeedWebSiteCommand(childService[0], resource);
               break;
               case ModuleServiceName.LiteSpeedListener:
               command = new RemoveLiteSpeedListenerCommand(childService[0], resource);
               break;
               ....
               }
               break;
               case ModuleCommandType.Modify:
               switch (childService[0].Name)
               {
               case ModuleServiceName.LiteSpeedWebSite:
               command = new ModifyWebSiteCommand(childService[0], resource, childService[1]);
               break;
               case ModuleServiceName.LiteSpeedListener:
               command = new ModifyLiteSpeedListenerCommand(childService[0], resource, childService[1]);
               break;
               ....
               }
               break;
               }
               return command;
               }
5.2.1.1.2. Begin transaction example
               public void BeginTransaction()
               {
               if (this.commands.Count > 0)
               {
               throw ExceptionHelper.GetModuleException("ID400002", null, null);
               }
               }
5.2.1.1.3. Commit transaction example
               public void CommitTransaction()
               {
               foreach (ModuleCommand command in this.commands)
               {
               command.CleanUp();
               }
               this.commands.Clear();
               }
               h3. Rollback transaction example
               {newcode:csharp}public void RollbackTransaction()
               {
               int size = this.commands.Count;
               for (int i = size - 1; i >= 0; i--)
               {
               if (this.commands[i].Status == ModuleCommandStatus.Executed)
               {
               this.commands[i].Undo();
               }
               this.commands[i].CleanUp();
               }
               this.commands.Clear();
               }
5.2.1.2. Module commands examples
5.2.1.2.1. Add command example
               internal class AddLiteSpeedWebSiteCommand : ModuleCommand
               {
               /// <summary>
               /// Initializes a new instance of the <see cref="AddLiteSpeedWebSiteCommand"/> class.
               /// </summary>
               /// <param name="service">The service.</param>
               /// <param name="resource">Server resource.</param>
               public AddLiteSpeedWebSiteCommand(ModuleService service, ResourceDescription resource) : base(service, resource)
               {
               }
               /// <summary>
               /// Prepares everything to be able to call undo and validate data.
               /// </summary>
               public override void Prepare()
               {
               LSValidation.ValidateWebSiteProperties(this.service);
               }
               /// <summary>
               /// Executes this command.
               /// </summary>
               public override void Execute()
               {
               this.status = LiteSpeedHelperMethods.AddWebSite(this.service, this.resource);
               }
               /// <summary>
               /// Undoes this command.
               /// </summary>
               public override void Undo()
               {
               LiteSpeedHelperMethods.RemoveLiteSpeedWebSite(this.service, this.resource);
               }
               /// <summary>
               /// Cleans up.
               /// </summary>
               public override void CleanUp()
               {
               }
               }
5.2.1.2.2. Remove command example
               internal class RemoveLiteSpeedWebSiteCommand : ModuleCommand
               {
               /// <summary>
               /// Initializes a new instance of the <see cref="RemoveLiteSpeedWebSiteCommand"/> class.
               /// </summary>
               /// <param name="service">The service.</param>
               /// <param name="resource">Server resource.</param>
               public AddLiteSpeedWebSiteCommand(ModuleService service, ResourceDescription resource) : base(service, resource)
               {
               }
               /// <summary>
               /// Prepares everything to be able to call undo and validate data.
               /// </summary>
               public override void Prepare()
               {
               }
               /// <summary>
               /// Executes this command.
               /// </summary>
               public override void Execute()
               {
               this.status = LiteSpeedHelperMethods.RemoveWebSite(this.service, this.resource);
               }
               /// <summary>
               /// Undoes this command.
               /// </summary>
               public override void Undo()
               {
               LiteSpeedHelperMethods.AddLiteSpeedWebSite(this.service, this.resource);
               }
               /// <summary>
               /// Cleans up.
               /// </summary>
               public override void CleanUp()
               {
               }
               }
5.2.1.3. Complete module example

This example represents a simple implementation of a provisioning module which "provisions" file and folder services. This example is also downloadable as a full Microsoft Visual Studio 2008 project here:  Atomia.Examples.Modules.FolderMapper .

             /// <summary>
             /// Folder mapper agent.
             /// </summary>
             public class FolderMapperAgent : ModuleBase
             {
             /// <summary>
             /// Action executed.
             /// </summary>
             private Action action;
             /// <summary>
             /// Root folder for creating folder-service structure.
             /// </summary>
             private string rootFolder;
             /// <summary>
             /// List of files and folders that was created/deleted.
             /// </summary>
             private List<FileContent> actions;
             /// <summary>
             /// Initializes a new instance of the FolderMapperAgent class.
             /// </summary>
             public FolderMapperAgent()
             {
             this.actions = new List<FileContent>();
             string configFilePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(FolderMapperAgent)).Location) + "\\FolderMapper.txt";
             try
             {
             // Create an instance of StreamWriter to write text to a file.
             using (StreamReader sr = new StreamReader(configFilePath))
             {
             this.rootFolder = sr.ReadLine();
             }
             }
             catch
             {
             this.rootFolder = "c:\\";
             }
             }
             /// <summary>
             /// Module actions type.
             /// </summary>
             private enum Action
             {
             /// <summary>
             /// Create service action.
             /// </summary>
             Create,
             /// <summary>
             /// Delete service action.
             /// </summary>
             Delete,
             /// <summary>
             /// Modify service action.
             /// </summary>
             Modify
             }
             /// <summary>
             /// Service type. Document or folder.
             /// </summary>
             private enum FileFolder
             {
             /// <summary>
             /// File type.
             /// </summary>
             File,
             /// <summary>
             /// Folder type.
             /// </summary>
             Folder
             }
             #region ModuleBase Members
             /// <summary>
             /// Begins transaction. After this method is executed and before <see cref="CommitTransaction"/> or <see cref="RollbackTransaction"/> method, only one method must be called.
             /// </summary>
             public void BeginTransaction()
             {
             this.actions.Clear();
             }
             /// <summary>
             /// Commits transaction. Successfully finishes transaction.
             /// </summary>
             public void CommitTransaction()
             {
             this.actions.Clear();
             }
             /// <summary>
             /// Rollbacks transaction. Cancel transaction and rolls back in case of an error.
             /// </summary>
             public void RollbackTransaction()
             {
             switch (this.action)
             {
             case Action.Create:
             {
             // delete all created file/folers
             int size = this.actions.Count;
             for (int i = size - 1; i >= 0; i--)
             {
             FileContent fc = this.actions[i];
             if (fc.fileFolder == FileFolder.File)
             {
             System.IO.File.Delete(fc.fileName);
             }
             else if (fc.fileFolder == FileFolder.Folder)
             {
             System.IO.Directory.Delete(fc.fileName, true);
             }
             }
             }
             break;
             case Action.Delete:
             {
             int size = this.actions.Count;
             for (int i = 0; i < size; i++)
             {
             FileContent fc = this.actions[i];
             if (fc.fileFolder == FileFolder.File)
             {
             using (StreamWriter sw = new StreamWriter(fc.fileName, false))
             {
             sw.WriteLine(fc.content);
             }
             }
             else if (fc.fileFolder == FileFolder.Folder)
             {
             System.IO.Directory.CreateDirectory(fc.fileName);
             }
             }
             }
             break;
             case Action.Modify:
             {
             foreach (FileContent fc in this.actions)
             {
             if (fc.fileFolder == FileFolder.File)
             {
             using (StreamWriter sw = new StreamWriter(fc.fileName, false))
             {
             sw.WriteLine(fc.content);
             }
             }
             }
             }
             break;
             default:
             break;
             }
             this.actions.Clear();
             }
             /// <summary>
             /// Provides specific service.
             /// </summary>
             /// <param name="service">Module service to provide.</param>
             /// <param name="resource">Resource associated with this service.</param>
             public void ProvideService(ModuleService service, ResourceDescription resource)
             {
             this.action = Action.Create;
             // create resource folder if it does not exist.
             string currentFolder;
             Stack<string> pathStack;
             this.GetFolderPath4Service(service.Parent, resource, out currentFolder, out pathStack);
             // we should have all folders till new one
             if (!System.IO.Directory.Exists(currentFolder))
             {
             throw new ModuleException("Cannot find folder with name " + currentFolder);
             }
             // we have all necessery folders. we should create new one
             currentFolder += this.GetFolderName(service) + "\\";
             // if it is exist it is an error
             if (System.IO.Directory.Exists(currentFolder))
             {
             // throw new Atomia.Provisioning.Base.Exceptions.ModuleException("Service already exist. Service path: " + currentFolder);
             }
             else
             {
             System.IO.Directory.CreateDirectory(currentFolder);
             }
             FileContent fc = new FileContent();
             fc.fileFolder = FileFolder.Folder;
             fc.fileName = currentFolder;
             this.actions.Add(fc);
             // write folder properties
             // prepear string
             string propertyFileText = CreatePropertiesFileText(service);
             // write to file
             using (StreamWriter sw = new StreamWriter(currentFolder + "properties.txt", false))
             {
             sw.WriteLine(propertyFileText);
             }
             fc = new FileContent();
             fc.fileFolder = FileFolder.File;
             fc.fileName = currentFolder + "properties.txt";
             this.actions.Add(fc);
             }
             /// <summary>
             /// Creates the properties file text.
             /// </summary>
             /// <param name="service">The service.</param>
             /// <returns>Property file text.</returns>
             private static string CreatePropertiesFileText(ModuleService service)
             {
             string propertyFileText = string.Empty;
             foreach (ModuleServiceProperty property in service.GetAllProperties())
             {
             propertyFileText += property.Name + "=" + property.Value + "\r\n";
             }
             return propertyFileText;
             }
             /// <summary>
             /// Gets the folder path4 service.
             /// </summary>
             /// <param name="service">The service.</param>
             /// <param name="resource">The resource.</param>
             /// <param name="currentFolder">The current folder.</param>
             /// <param name="pathStack">The path stack.</param>
             private void GetFolderPath4Service(ModuleService service, ResourceDescription resource, out string currentFolder, out Stack<string> pathStack)
             {
             pathStack = new Stack<string>();
             string resourceFolder = this.GetFolderName(resource);
             pathStack.Push(resourceFolder);
             currentFolder = this.rootFolder + resourceFolder + "\\";
             ModuleService currentService = service;
             string reversePath = string.Empty;
             while (currentService != null)
             {
             pathStack.Push(this.GetFolderName(currentService));
             reversePath = this.GetFolderName(currentService) + "\\" + reversePath;
             currentService = currentService.Parent;
             }
             currentFolder += reversePath;
             }
             /// <summary>
             /// Removes specific service from the resource.
             /// </summary>
             /// <param name="service">Module service to remove.</param>
             /// <param name="resource">Resource associated with this service</param>
             public void RemoveService(ModuleService service, ResourceDescription resource)
             {
             this.action = Action.Delete;
             string currentFolder;
             Stack<string> pathStack;
             this.GetFolderPath4Service(service, resource, out currentFolder, out pathStack);
             // we should have all folders
             if (!System.IO.Directory.Exists(currentFolder))
             {
             throw new ModuleException("Cannot find folder with name " + currentFolder);
             }
             // current folder should not have subfolders
             if (System.IO.Directory.GetDirectories(currentFolder).Length > 0)
             {
             throw new ModuleException("Child services exist. Currnet folder for delete: " + currentFolder);
             }
             System.IO.Directory.Delete(currentFolder, true);
             FileContent fc = new FileContent();
             fc.fileFolder = FileFolder.Folder;
             fc.fileName = currentFolder;
             this.actions.Add(fc);
             string propertyFileText = CreatePropertiesFileText(service);
             fc = new FileContent();
             fc.fileFolder = FileFolder.File;
             fc.fileName = currentFolder + "properties.txt";
             fc.content = propertyFileText;
             this.actions.Add(fc);
             }
             /// <summary>
             /// Modifies given module service.
             /// </summary>
             /// <param name="service">Module service containing old service properties and settings.</param>
             /// <param name="resource">Resource associated with this service.</param>
             /// <param name="newServiceSettings">New service settings.</param>
             public void ModifyService(ModuleService service, ResourceDescription resource, ModuleService newServiceSettings)
             {
             this.action = Action.Modify;
             string currentFolder;
             Stack<string> pathStack;
             this.GetFolderPath4Service(service, resource, out currentFolder, out pathStack);
             // we should have all folders
             if (!System.IO.Directory.Exists(currentFolder))
             {
             throw new ModuleException("Cannot find folder with name " + currentFolder);
             }
             string propertyFileText = string.Empty;
             foreach (ModuleServiceProperty property in service.GetAllProperties())
             {
             propertyFileText += property.Name + "=" + property.Value + "\r\n";
             }
             using (StreamReader sr = new StreamReader(currentFolder + "properties.txt"))
             {
             FileContent fc = new FileContent();
             fc.fileFolder = FileFolder.File;
             fc.fileName = currentFolder + "properties.txt";
             fc.content = sr.ReadToEnd();
             this.actions.Add(fc);
             }
             // write to file
             using (StreamWriter sw = new StreamWriter(currentFolder + "properties.txt", false))
             {
             sw.WriteLine(propertyFileText);
             }
             }
             /// <summary>
             /// Moves service from one resource to another. Module should also remove all related child and parent simple service resources.
             /// If this operation failed, module must rollback service status as before.
             /// </summary>
             /// <param name="service">Service that should change resource location.</param>
             /// <param name="currentResource">Resource where service is currently located.</param>
             /// <param name="targetResource">Resource where service will be moved.</param>
             public void MoveToResource(ModuleService service, ResourceDescription currentResource, ResourceDescription targetResource)
             {
             // TODO add code for moving resources
             }
             /// <summary>
             /// Lists the services no children.
             /// </summary>
             /// <param name="serviceName">Name of the service.</param>
             /// <param name="targetResource">The target resource.</param>
             /// <returns></returns>
             public List<ModuleService> ListServicesNoChildren(string serviceName, ResourceDescription targetResource)
             {
             return null;
             }
             /// <summary>
             /// Lists the services.
             /// </summary>
             /// <param name="service">The service.</param>
             /// <param name="maxDepth">The max depth.</param>
             /// <param name="targetResource">The target resource.</param>
             /// <returns></returns>
             public ModuleService ListServices(ModuleService service, int maxDepth, ResourceDescription targetResource)
             {
             return service;
             }
             /// <summary>
             /// Calls the operation.
             /// </summary>
             /// <param name="service">The service.</param>
             /// <param name="operationName">Name of the operation.</param>
             /// <param name="operationArgument">The operation argument.</param>
             /// <param name="targetResource">The target resource.</param>
             /// <returns></returns>
             public string CallOperation(ModuleService service, string operationName, string operationArgument, ResourceDescription targetResource)
             {
             return string.Empty;
             }
             /// <summary>
             /// Gets the service description of services supported by this module. Root element of this XML is simpleServiceList node.
             /// </summary>
             /// <returns>Module service description.</returns>
             public string GetModuleServiceDescription()
             {
             return null;
             }
             #endregion
             #region IDisposable Members
             /// <summary>
             /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
             /// </summary>
             public void Dispose()
             {
             throw new NotImplementedException();
             }
             #endregion
             /// <summary>
             /// Gets the name of the folder.
             /// </summary>
             /// <param name="resource">The resource.</param>
             /// <returns></returns>
             private string GetFolderName(ResourceDescription resource)
             {
             return resource.Name;
             }
             /// <summary>
             /// Gets the name of the folder.
             /// </summary>
             /// <param name="service">The service.</param>
             /// <returns></returns>
             private string GetFolderName(ModuleService service)
             {
             string folderName = service.Name;
             folderName += " " + service.PhysicalID;
             return folderName;
             }
             /// <summary>
             /// File content structure.
             /// </summary>
             private struct FileContent
             {
             public string fileName;
             public string content;
             public FileFolder fileFolder;
             };
             }

5.2.2. Atomia Automation Server Resource Assignment Policy Agents - Code Examples

5.2.2.1. Atomia Provisioning Resource Assignment Policy Agents example

This is an example Resource Assignment Policy Agent. It implements the DefaultResource policy for resource assignment. This example is also available for download as a working Microsoft Visual Studio 2008 project here:  Atomia.Examples.RAPA.DefaultResource .

             /// <summary>
             /// Atomia DefaultResource resource assignment plug-in
             /// </summary>
             public class DefaultResourcePolicyPlugin : ResourceAssignmentPolicyAgentBase
             {
             /// <summary>
             /// Resource description manager. Needed to get list of available resources for specific service.
             /// </summary>
             private IResourceDescriptionManager resourceDescriptionManager;
             /// <summary>
             /// Service context resolver. Provides the context for the service.
             /// </summary>
             private IServiceContextResolver serviceContextResolver;
             #region IResourceAssignmentPolicyAgent Members
             /// <summary>
             /// Gets or sets a name of the resource assignment policy that realizes this agent.
             /// </summary>
             /// <value>The name of the policy.</value>
             public override string PolicyName
             {
             get { return "DefaultResource"; }
             protected set { }
             }
             /// <summary>
             /// Initializes resource assignment policy agent.
             /// </summary>
             public override void Init()
             {
             }
             /// <summary>
             /// Gets the resource.
             /// </summary>
             /// <param name="moduleName">Name of the module.</param>
             /// <param name="accountId">The account id of the service.</param>
             /// <param name="service">The service which needs to be provisioned.</param>
             /// <param name="resourceRequest">Null or <see cref="ResourceRequestDescription"/> object that can help this agent to make decision.</param>
             /// <param name="resourceHelperProvider">The resource helper provider.</param>
             /// <returns>
             /// Resource description of resource that will be used for hosting <paramref name="service"/>.
             /// </returns>
             public override ResourceDescription GetResource(
             string moduleName,
             string accountId,
             ProvisioningService service,
             ResourceRequestDescription resourceRequest,
             ResourceHelperProviderBase resourceHelperProvider)
             {
             this.serviceContextResolver = resourceHelperProvider.GetHelper<IServiceContextResolver>();
             // get the provisioning description
             string provDescription = service.ProvisioningDescription;
             if (String.IsNullOrEmpty(provDescription))
             {
             provDescription = this.serviceContextResolver.GetProvisioningDescriptionVersionName(service);
             }
             // create provisioning description - package string
             string provDescPackage = provDescription + "." + this.serviceContextResolver.GetPackageName(service);
             ResourceDescription resDescription = null;
             if (String.IsNullOrEmpty(moduleName))
             {
             throw new ArgumentNullException("moduleName", "Module name cannot be null.");
             }
             // get resources for the module and specified policy
             this.resourceDescriptionManager = resourceHelperProvider.GetResourceDescriptionManager(this.ResourceDescriptionManagerName);
             ResourceDescription[] resourcesDescriptions = this.resourceDescriptionManager.GetResources(accountId, moduleName, this.PolicyName);
             if (resourcesDescriptions.Length < 1)
             {
             return null;
             }
             int i = 0;
             bool finish = false;
             // find first resource which can be default for the service
             while ((i < resourcesDescriptions.Length) && (!finish))
             {
             List<ResourceDescriptionPropertyList> propertyList = resourcesDescriptions[i].PropertyList.FindAll(pl => pl.PropertyListName == "DefaultResource.Packages");
             if (propertyList.Count > 0)
             {
             if (propertyList[0].PropertyListItems.FindAll(pli => pli == provDescPackage).Count > 0)
             {
             resDescription = resourcesDescriptions[i];
             finish = true;
             }
             }
             i++;
             }
             // if none is chosen, choose default one
             if (resDescription == null)
             {
             foreach (ResourceDescription resourcesDescription in resourcesDescriptions)
             {
             string isDefault = resourcesDescription["DefaultResource.Default"];
             if (isDefault != null && isDefault.ToLowerInvariant() == "true")
             {
             return resourcesDescription;
             }
             }
             }
             // if none is chosen, choose first
             if (resDescription == null)
             {
             resDescription = resourcesDescriptions[0];
             }
             return resDescription;
             }
             #endregion
             }

5.3. Getting Started

5.3.1. Atomia Automation Server Action Hooks

5.3.1.1. Introduction

Atomia Automation Server allows developers to write action hooks. With action hooks, you can add your own code that will run when specific actions occur within the provisioning system. Using action hooks allows developers to extend the functionality of the Atomia Automation Server.

At the moment the following events are monitored:

  • OnBeforeAddService - Occurs before a service is being added to the Provisioning system.

  • OnBeforeChangePackage - Occurs before an account package is changed.

  • OnBeforeSwitchService - Occurs before a service is replaced with another one.

5.3.1.2. Classes used in action hooks development
5.3.1.3. Creating action hook

All action hooks must inherit the  ActionHookBase2 class.

             /// <summary>
             /// The base class that should be derived for implementing action hooks
             /// </summary>
             public abstract class ActionHookBase2
             {
             /// <summary>
             /// Gets or sets the tag. THIS IS FOR SYSTEM USE. DO NOT CHANGE THIS PROPERTY;
             /// </summary>
             public object Tag { get; set; }
             /// <summary>
             /// Gets or sets the action hook bridge. It is used to acquire plug-ins necessary interfaces.
             /// </summary>
             protected ActionHookBridgeBase ActionHookBridge { get; set; }
             /// <summary>
             /// Initializes the specified action hook bridge base.
             /// </summary>
             /// <param name="actionHookBridgeBase">The action hook bridge.</param>
             public virtual void Init(ActionHookBridgeBase actionHookBridgeBase)
             {
             this.ActionHookBridge = actionHookBridgeBase;
             }
             /// <summary>
             /// Called before adding service. Services are prepared for adding but not added to database or on resource, yet.
             /// </summary>
             /// <param name="service">The service that has to be added. It is instance of <c>UcpServiceLogical</c> class.</param>
             /// <param name="argument">The argument string from configuration.</param>
             /// <param name="overridesDefaultBehavior">If set to <c>true</c> plug-in will override default behavior of provisioning.</param>
             public virtual void OnBeforeAddService(Service service, string argument, out bool overridesDefaultBehavior)
             {
             overridesDefaultBehavior = false;
             }
             /// <summary>
             /// Called before changing a package.
             /// </summary>
             /// <param name="package">The existing package. It is instance of <c>Package</c> class.</param>
             /// <param name="newPackageName">Name of the new package.</param>
             /// <param name="argument">The argument string from configuration.</param>
             /// <param name="overridesDefaultBehavior">If set to <c>true</c> plug-in will override default behavior of changing package.</param>
             /// <returns>New package instance.</returns>
             public virtual Package OnBeforeChangePackage(Package package, string newPackageName, string argument, out bool overridesDefaultBehavior)
             {
             overridesDefaultBehavior = false;
             return null;
             }
             /// <summary>
             /// Called before switch service.
             /// </summary>
             /// <param name="service">The service to change.</param>
             /// <param name="newServiceName">New name of the service.</param>
             /// <param name="arguments">The arguments passed from API.</param>
             /// <param name="configurationArgument">The configuration argument from configuration file.</param>
             /// <param name="overridesDefaultBehavior">If set to <c>true</c> overrides default behavior.</param>
             /// <returns>New service instance.</returns>
             public virtual Service OnBeforeSwitchService(Service service, string newServiceName, Dictionary<string, string> arguments, string configurationArgument, out bool overridesDefaultBehavior)
             {
             overridesDefaultBehavior = false;
             return null;
             }
             /// <summary>
             /// Return instance event if it is under proxy
             /// </summary>
             /// <returns>Instance of <see cref="ActionHookBase2"/>.</returns>
             public virtual ActionHookBase2 This()
             {
             return this;
             }
             }
5.3.1.3.1. Installing Resource Assignment Policy Agent

In order to use the newly created Action Hook, the following steps must be followed:

  1. Build Action Hook project.

  2. Open any file explorer (Windows Explorer i.e.) and navigate to the Atomia Provisioning installation folder.

  3. Copy Action Hook and all other needed libraries to the following folder: Atomia Automation Server installation folder (usually : C:\Program Files (x86)\Atomia\AutomationServer)\Web\bin

5.3.2. Atomia Automation Server Modules

5.3.2.1. Introduction

The p rovisioning module is a plugin written using .NET framework. It does the actual provisioning of services on a specific resource such as a web server, database, DNS, etc.

Each module is specified to work with one type of resource. For example, IISModule is in charge of provisioning and managing services on the Microsoft IIS platform.

5.3.2.2. Classes used in module development
5.3.2.3. Creating a Provisioning Module
  1. Download Atomia Provisioning SDK, Atomia Provisioning Module SDK and Atomia Provisioning Module template project for Microsoft Visual Studio 2008 . Instructions on how to obtain SDKs can be found on How to obtain Atomia Automation Server SDKs .

  1. Create a new project in Visual Studio.

    1. Project type should be Class Library project.

  2. Add a reference to Atomia.Provisioning.Base and Atomia.Provisioning.Base.Module libraries.

  3. Classes that should represent a module must inherit the  ModuleBase class.

The simplest implementation of a module class would be:

             public class SimpleModule : ModuleBase
             {
             /// <summary>
             /// Begins transaction. After this method is executed and before <see cref="CommitTransaction"/> or <see cref="RollbackTransaction"/> method, only one method must be called.
             /// </summary>
             void BeginTransaction()
             {
             // start transaction
             }
             /// <summary>
             /// Commits transaction. Successfully finishes transaction.
             /// </summary>
             void CommitTransaction()
             {
             // do cleaning up and commit transaction
             }
             /// <summary>
             /// Rollbacks transaction. Cancel transaction and rolls back in case of an error.
             /// </summary>
             void RollbackTransaction()
             {
             // put code for reverting resource into previous state in case of provisioning failure
             }
             /// <summary>
             /// Provides specific service.
             /// </summary>
             /// <param name="service">Module service to provide.</param>
             /// <param name="resource">Resource associated with this service.</param>
             void ProvideService(ModuleService service, ResourceDescription resource)
             {
             // add some code for provisioning services on resource
             }
             /// <summary>
             /// Removes specific service from the resource.
             /// </summary>
             /// <param name="service">Module service to remove.</param>
             /// <param name="resource">Resource associated with this service</param>
             void RemoveService(ModuleService service, ResourceDescription resource)
             {
             // add some code for removing specific services from resources
             }
             /// <summary>
             /// Modifies given module service.
             /// </summary>
             /// <param name="service">Module service containing old service properties and settings.</param>
             /// <param name="resource">Resource associated with this service.</param>
             /// <param name="newServiceSettings">New service settings.</param>
             void ModifyService(ModuleService service, ResourceDescription resource, ModuleService newServiceSettings)
             {
             // add some code for modifying specific services on resource
             }
             /// <summary>
             /// Moves service from one resource to another. Module should also remove all related child and parent simple service resources.
             /// If this operation failed, module must rollback service status as before.
             /// </summary>
             /// <param name="service">Service that should change resource location.</param>
             /// <param name="currentResource">Resource where service is currently located.</param>
             /// <param name="targetResource">Resource where service will be moved.</param>
             void MoveToResource(ModuleService service, ResourceDescription currentResource, ResourceDescription targetResource)
             {
             // implement logic for moving service from one resource to another one
             }
             /// <summary>
             /// Lists all services with the name <paramref name="serviceName"/> on the specific resource without linking them with their child services.
             /// </summary>
             /// <param name="serviceName">Name of the root simple service. If required service is not root exception will be thrown.</param>
             /// <param name="resource">The resource description of resource where services are located.</param>
             /// <returns>List of services.</returns>
             List<ModuleService> ListServicesNoChildren(string serviceName, ResourceDescription resource)
             {
             // implement logic for returning all root services with given name
             }
             /// <summary>
             /// Creates service tree for specific service. This function should create tree structure of children for specific service.
             /// </summary>
             /// <param name="service">Specific service for which to build a service tree.</param>
             /// <param name="maxDepth">Maximum depth of services. If this value is -1 module should list all children services.</param>
             /// <param name="resource">The resource description of resource where is service located.</param>
             /// <returns>Service with connected children tree structure.</returns>
             ModuleService ListServices(ModuleService service, int maxDepth, ResourceDescription resource)
             {
             // implement logic for listing children subtree of a given service
             }
             /// <summary>
             /// Calls the specified operation on specific service.
             /// </summary>
             /// <param name="service">Specified service.</param>
             /// <param name="operationName">Name of the specified operation.</param>
             /// <param name="operationArgument">Operation argument.</param>
             /// <param name="resource">The resource description of resource where service is located.</param>
             /// <returns>Result of operation execution.</returns>
             string CallOperation(ModuleService service, string operationName, string operationArgument, ResourceDescription resource)
             {
             // implement logic for executing operations over specific service
             }
             /// <summary>
             /// Gets the service description of services supported by this module. Root element of this XML is simpleServiceList node.
             /// </summary>
             /// <returns>Module service description.</returns>
             string GetModuleServiceDescription()
             {
             // implement logic for returning string representation of the simple service description.
             }
             /// <summary>
             /// Lists the child services.
             /// </summary>
             /// <param name="parentService">The parent service. If parent service is null module will return root services.</param>
             /// <param name="resource">The resource description for which resource we are listing child services.</param>
             /// <param name="serviceName">Name of the service. If the service name is empty or null all child services will be listed.</param>
             /// <param name="pageNumber">The page number.</param>
             /// <param name="pageSize">Size of the page. If this value is <c>0</c> all items will be returned.</param>
             /// <param name="sortAsc">If this argument is set to <c>true</c> services will sorted in ascending order (by name).</param>
             /// <param name="totalServiceNumber">The total service number.</param>
             /// <returns>
             /// List of services that fulfill given criteria.
             /// </returns>
             public virtual List<ModuleService> ListChildServices(
             ModuleService parentService,
             ResourceDescription resource,
             string serviceName,
             int pageNumber,
             int pageSize,
             bool sortAsc,
             out int totalServiceNumber)
             {
             // implement getting child services for a specific parent service
             }
             /// <summary>
             /// Update expiring properties from resource for a list of services (guaranteed to be of the same type).
             /// </summary>
             /// <param name="services">The parent service. If parent service is null module will return root services.</param>
             /// <param name="resource">The resource description for which resource we are listing child services.</param>
             public virtual void SyncExpiringProperties(List<ModuleService> services, ResourceDescription resource)
             {
             // helper method which adds possibility to have some external system updating service properties
             }
             /// <summary>
             /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
             /// </summary>
             public virtual void Dispose()
             {
             // dispose object
             }
             }

It should be noted that the ModuleService instance which is being passed to some module methods, by the Atomia Automation Server Core, may contain children sub-tree structures. Module developers  should implement the processing of each child service being passed to the functions ProvideService , RemoveService , MoveToResource .

Also, make sure that you do proper transaction handling, taking into account the full service tree in the transaction functions: BeginTransaction , CommitTransaction , RollbackTransaction .

For more detailed and in-depth examples, please see Examples .

5.3.2.3.1. Installing Provisioning Modules

In order to use the newly created Provisioning Module, the following steps should be followed:

  1. Build Provisioning Module project.

  2. Open any file explorer (Windows Explorer i.e.) and navigate to the Atomia Provisioning installation folder.

  3. Copy the Provisioning module and all other needed libraries to the following folder: Atomia Provisioning installation folder \Bin\Modules

  4. The service description should be updated with services which are going to be provisioned by the new module.

5.3.2.4. Transaction model

The service provisioning process is usually a complex process that comprises of smaller provisioning tasks. These tasks may all use the same resource but also very often they are using different resources. For example, a hosting service includes setups for an IIS website, DNS records, Mail and FTP services.

If an error occured during the provisioning process, the final result of such provisioning would be unpredictable. The provisioning of both website, e-mail and FTP might have been successful, but due to an error in the DNS setup these services are unavailable. To prevent such situations, the Provisioning module uses transactions to ensure that all processes will be finished successfully or no one. In the case of an error, the processes that finished successfully will be rolled back back to undo the changes that were made to the resource.

To support transactions, ModuleBase offers three methods: BeginTransaction, CommitTransaction and RollbackTransaction. Details about these methods can be found in the Examples section.

5.3.2.5. Recommendations

Developers should avoid putting service management logic inside the CommitTransaction method. CommitTransaction should only do clean up, that is, it should remove temporary files, objects, etc. (if any), which are created during the execution of the Module command. Rollback must revert resource into the previous state, before Module command was executed. If this recommendations are followed, it will be insured that provisioning process will be done correctly.

It is our recommendation to split module provisioning actions into commands which can be executed separately. Use recommended Command pattern solution for this.

5.3.2.6. Examples

Various Atomia Provisioning Modules example code snippets can be found on the  Code Example page .

5.3.2.7. Command pattern
5.3.2.7.1. Explanation of Command Pattern

In object-oriented programming, the Command pattern is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time.

Command objects are useful for implementing:

Multi-level undo If all user actions in a program are implemented as command objects, the program can keep a stack of the most recently executed commands. When the user wants to undo a command, the program simply pops the most recent command object and executes its undo() method.

Transactional behavior Undo is perhaps even more essential when it is called rollback and happens automatically when an operation fails partway through. Installers need this and so do databases. Command objects can also be used to implement two-phase commit.

The following snippet demonstrates the Command pattern which stores requests as objects allowing clients to execute or playback the requests.

                 using System;
                 namespace Atomia.Command.Structural
                 {
                 /// <summary>
                 /// MainApp startup class for Structural
                 /// Command Design Pattern.
                 /// </summary>
                 class MainApp
                 {
                 /// <summary>
                 /// Entry point into console application.
                 /// </summary>
                 static void Main()
                 {
                 // Create receiver, command, and invoker
                 Receiver receiver = new Receiver();
                 Command command = new ConcreteCommand(receiver);
                 Invoker invoker = new Invoker();
                 // Set and execute command
                 invoker.SetCommand(command);
                 invoker.ExecuteCommand();
                 // Wait for user
                 Console.ReadKey();
                 }
                 }
                 /// <summary>
                 /// The 'Command' abstract class
                 /// </summary>
                 abstract class Command
                 {
                 protected Receiver receiver;
                 // Constructor
                 public Command(Receiver receiver)
                 {
                 this.receiver = receiver;
                 }
                 public abstract void Execute();
                 }
                 /// <summary>
                 /// The 'ConcreteCommand' class
                 /// </summary>
                 class ConcreteCommand : Command
                 {
                 // Constructor
                 public ConcreteCommand(Receiver receiver): base(receiver)
                 {
                 }
                 public override void Execute()
                 {
                 receiver.Action();
                 }
                 }
                 /// <summary>
                 /// The 'Receiver' class
                 /// </summary>
                 class Receiver
                 {
                 public void Action()
                 {
                 Console.WriteLine("Called Receiver.Action()");
                 }
                 }
                 /// <summary>
                 /// The 'Invoker' class
                 /// </summary>
                 class Invoker
                 {
                 private Command _command;
                 public void SetCommand(Command command)
                 {
                 this._command = command;
                 }
                 public void ExecuteCommand()
                 {
                 _command.Execute();
                 }
                 }
                 }

# The Invoker keeps an instance of the Command and invokes its Execute method.

  1. The Command's method Execute calls the Receiver to perform the Action.

  2. The Receiver performs the action that was ordered through the Command.

When used in a Provisioning Module this pattern looks like this:

1. ModuleCommand is a base class for various commands (add, remove, modify)

                 internal abstract class ModuleCommand
                 {
                 /// <summary>
                 /// Service to be managed.
                 /// </summary>
                 protected ModuleService service;
                 /// <summary>
                 /// Resource that hosts the service.
                 /// </summary>
                 protected ResourceDescription resource;
                 /// <summary>
                 /// Status of command - defines when the command can be rolled back
                 /// </summary>
                 protected ModuleCommandStatus status = ModuleCommandStatus.NotExecuted;
                 /// <summary>
                 /// Constructor
                 /// </summary>
                 public ModuleCommand(ModuleService service, ResourceDescription resource)
                 {
                 this.service = service;
                 this.resource = resource;
                 ]
                 /// <summary>
                 /// Prepares everything to be able to call undo and validate data.
                 /// </summary>
                 public abstract void Prepare();
                 /// <summary>
                 /// Executes this command.
                 /// </summary>
                 public abstract void Execute();
                 /// <summary>
                 /// Undoes this command.
                 /// </summary>
                 public abstract void Undo();
                 /// <summary>
                 /// Cleans up.
                 /// </summary>
                 public abstract void CleanUp();
                 }

* service - description of the service to be managed (added, modified, moved or removed)

  • resource - resource where the service is or will be hosted Commands derived from ModuleCommand use these properties to "remember" what was done and where it was done. Knowing that, command are able to undo their action(s).

2. Each of the Add (or Remove or Modify) commands is a concrete module command

                 internal class AddApplicationPoolCommand : ModuleCommand
                 {
                 public AddApplicationPoolCommand(ModuleService service, ResourceDescription resource) : base(service, resource)
                 {
                 }
                 public override void Prepare()
                 {
                 // data validation
                 IISValidation.ValidateApplicationPool(this.service);
                 }
                 public override void Execute()
                 {
                 // code that adds the application pool
                 // into applicationHost.config file
                 // and sets the status of the command
                 this.status = IISHelper.AddApplicationPool(this.service, this.resource);
                 }
                 public override void Undo()
                 {
                 // code that removes the application pool
                 // from applicationHost.config file
                 IISHelper.RemoveApplicationPool(this.service, this.resource);
                 }
                 public override void CleanUp()
                 {
                 // code to clean up resources
                 }
                 }

3. Invoker is IISModule - keeps ModuleCommands and invokes its methods

                 class IISModule : IModule
                 {
                 ....
                 private List<ModuleCommand> commands = new List<ModuleCommand>();
                 public void BeginTransaction()
                 {
                 if (this.commands.Count > 0)
                 {
                 throw ExceptionHelper.GetModuleException("ID400002", null, null);
                 }
                 }
                 public void CommitTransaction()
                 {
                 foreach (ModuleCommand command in this.commands)
                 {
                 command.CleanUp();
                 }
                 this.commands.Clear();
                 }
                 public void RollbackTransaction()
                 {
                 int size = this.commands.Count;
                 // Actions must be undone in reverse order
                 for (int i = size - 1; i >= 0; i--)
                 {
                 if (this.commands[i].Status == ModuleCommandStatus.Executed)
                 {
                 this.commands[i].Undo();
                 }
                 this.commands[i].CleanUp();
                 }
                 this.commands.Clear();
                 }
                 public void ProvideService(ModuleService service, ResourceDescription resource)
                 {
                 string comment = string.Empty;
                 this.resource = resource;
                 if (resource == null)
                 {
                 throw new InvalidPropertyException("ResourceDescription must not be null.", string.Empty);
                 }
                 if (!TypeValidator.ValidateProperty(resource["IPAddress"], ref comment))
                 {
                 throw new InvalidPropertyException(comment, "IPAddress");
                 }
                 using (ServerManager serverManager = ServerManager.OpenRemote(this.resource["IPAddress"].ToString()))
                 {
                 this.PrepareCommandList(service, null, this.resource, null, ModuleCommandType.Add, serverManager, null);
                 foreach (ModuleCommand command in this.commands)
                 {
                 command.Prepare();
                 }
                 try
                 {
                 foreach (ModuleCommand command in this.commands)
                 {
                 command.Execute();
                 }
                 }
                 catch
                 {
                 // in case of error, remove commands to suppress rollback
                 this.commands.Clear();
                 throw;
                 }
                 serverManager.CommitChanges();
                 }
                 }
                 ....
                 }

4. Receiver is a IISHelper class that performs the actual provisioning.

For more details on this topic, please see:

[Important]Note

Using of command pattern is optional but we at Atomia find it appropriate for this purpose.

5.3.3. Atomia Automation Server Resource Assignment Policy Agents

5.3.3.1. Introduction

The Atomia Automation Server system provisions services on different type of resources. Resources are not limited to just one instance. For example, there can be more then one machine with IIS installed, or there can be multiple MS SQL servers. Atomia Automation Server has a component that decides which resource should be used when service is being provisioned. This component is called Resource Assignment Policy Agent .

Each Resource Assignment Policy Agent implements one strategy for deciding which resource is going to be used for service provisioning. In the Atomia Automation Server system, a resource assignment policy is set per module which means that all service types provisioned by one module have same resource assignment policy. Policies are set in the resource description file . During the provisioning process, Atomia Automation Server Core reads the policy for a specific module and invokes the Resource Assignment Policy Agent which implements that policy. The agent decides which resource should be used for provisioning and returns its Resource Description .

Atomia Automation Server currently comes with the following pack of available Resource Assignment Policy Agents:

Resource assignment policy key

Description

Library name

DefaultResource

There is one default resource for each module.

Atomia.Provisioning.ResourceAssignmentPolicy.DefaultResource.dll

DefaultResourceStickyPerAccount

Similar as DefaultResource , but services in one account, provisioned by the same module, are always on the same resource.

Atomia.Provisioning.ResourceAssignmentPolicy.DefaultResourceStickyPerAccount.dll

ExactResource

Automation Server tells the agent which resource should be used.

Atomia.Provisioning.ResourceAssignmentPolicy.ExactResource.dll

MatchingMappedResource

It needs to parameters to find right resource: MappedResourcePath - path to the resource; and MappedResourceName - resource name.

Atomia.Provisioning.ResourceAssignmentPolicy.MatchingMappedResource.dll

MatchingResourceProperty

Agent searches for a resource with the specified property.

Atomia.Provisioning.ResourceAssignmentPolicy.MatchingResourceProperty.dll

MatchingServiceName

Agent searches for a resource which can handle a service with given name.

Atomia.Provisioning.ResourceAssignmentPolicy.MatchingServiceName.dll

MatchingServiceNameLimitPerResource

Agent searches for resource but has limitation in number of accounts per resource.

Atomia.Provisioning.ResourceAssignmentPolicy.MatchingServiceNameLimitPerResource.dll

ProvDescSpecified

This agent searches for a parent service with the property ResourceId. It then matches that id to a resource with the property id.

Atomia.Provisioning.ResourceAssignmentPolicy.ProvDescSpecified.dll

ResellerSpecific

Specify a whitelist of reseller account ids that are allowed to use a resource.

Atomia.Provisioning.ResourceAssignmentPolicy.ResellerSpecific.dll

RoundRobin

Agent uses the Round Robin algorithm to determine a target resource.

Atomia.Provisioning.ResourceAssignmentPolicy.RoundRobin.dll

RoundRobinStickyPerAccount

Similar as RoundRobin, but services in one account, provisioned by the same module, are always on the same resource.

Atomia.Provisioning.ResourceAssignmentPolicy.RoundRobinStickyPerAccount.dll

RoundRobinStickyPerAccountWithMaximum

Similar to RoundRobinStickyPerAccount but has limitation in number of services per resource.

Atomia.Provisioning.ResourceAssignmentPolicy.RoundRobinStickyPerAccountWithMaximum.dll

RoundRobinStickyPerComplexService

Similar to RoundRobin but all services within same complex service are on the same resource.

Atomia.Provisioning.ResourceAssignmentPolicy.RoundRobinStickyPerComplexService.dll

SpecificResource

Agent searches for a specific resource. If search is unsuccessful, it returns the first one from the list.

Atomia.Provisioning.ResourceAssignmentPolicy.SpecificResource.dll

5.3.3.2. Classes and interfaces used in resource policy agent development
5.3.3.3. Creating resource policy agent

The simplest implementation of ResourceAssignmentPolicyAgentBase would look like this:

             /// <summary>
             /// Resource assignment agent example.
             /// </summary>
             public class ResourceAgentExample : ResourceAssignmentPolicyAgentBase
             {
             /// <summary>
             /// Gets a name of the resource assignment policy that realizes this agent.
             /// </summary>
             string PolicyName
             {
             get
             {
             // return name of the resource assignment policy
             }
             }
             /// <summary>
             /// Gets or sets resource description manager that this instance of the agent is agent for..
             /// </summary>
             /// <value>The name of the resource description manager.</value>
             public string ResourceDescriptionManagerName { get; set; }
             /// <summary>
             /// Initializes resource assignment policy agent.
             /// </summary>
             void Init()
             {
             // initialize resource assignment policy agent
             }
             /// <summary>
             /// Gets the resource.
             /// </summary>
             /// <param name="moduleName">Name of the module.</param>
             /// <param name="accountId">The account id of the service.</param>
             /// <param name="service">The service which needs to be provisioned.</param>
             /// <param name="resourceRequest">Null or <see cref="ResourceRequestDescription"/> object that can help this agent to make decision.</param>
             /// <param name="resourceHelperProvider">The resource helper provider.</param>
             /// <returns>
             /// Resource description of resource that will be used for hosting <paramref name="service"/>.
             /// </returns>
             public abstract ResourceDescription GetResource(
             string moduleName,
             string accountId,
             ProvisioningService service,
             ResourceRequestDescription resourceRequest,
             ResourceHelperProviderBase resourceHelperProvider)
             {
             // implement logic for determining which resource should be used.
             }
             }
5.3.3.3.1. Installing Resource Assignment Policy Agent

In order to use a newly created Resource Assignment Policy agent, the following steps must be followed:

  1. Build Resource Assignment Policy Agent project.

  2. Open any file explorer (Windows Explorer i.e.) and navigate to the Atomia Provisioning installation folder.

  3. Copy Resource Assignment Policy Agent and all other needed libraries to the following folder: Atomia Automation Server installation folder (usually : C:\Program Files (x86)\Atomia\AutomationServer)\Common\ResourceAgents

  4. Edit the  Resource description file to use new agent, as needed.

5.3.3.4. Examples

For more examples on how to create resource assignment policy agents, please see the  Code examples page .

5.3.3.5. ExactResource assignment policy
5.3.3.5.1. Usage

Policy agent which implements expects resource name to be externally specified. If Automation Server users want to use this policy, resource name must be specified. On the using Atomia Provisioning Core API page is an example how to add service. In case of using ExactResource policy, adding service would look like this:

               ...
               // create dictionary with additional resource request details
               Dictionary<string, string> requestExtensions = new Dictionary<string, string>();
               // add one pair with key - resourceName, which has name of the resource (from the Resource Description) as value
               requestExtensions.Add("resourceName", "ApacheServer001");
               // create resource request object
               ResourceRequestDescription requestDetails = new ResourceRequestDescription(null)
               {
               PolicyName = "ExactResource",
               RequestExtensions = requestExtensions
               };
               // Add service on resource
               var addedService = coreApi.AddService(newlyCreatedService, null, "300500", requestDetails);
               ...

If no resource is found with given name, an exception is thrown.

5.3.3.6. MatchingMappedResource assignment policy

5.3.3.6.1. Usage

In order for this resource assignment policy agent to work properly, it is necessary to configure Resource Description file properly. For each resource which will be using MatchingMappedResource policy additional properties must be added:

  • MappedResourcePath - path to the service which holds resource information agent should be using

  • MappedResourceName - resource name which will be checked against one used for service that is found on the MappedResourcePath . If it is the same service, it will be used, otherwise exception is thrown.

Resource description example:

               ...
               <moduleList>
               <module name="Atomia.Provisioning.Modules.ExampleModule" resourceAsignmentPolicy="MatchingMappedResource"/>
               </moduleList>
               <resourceList>
               <resource name="IISServer1">
               <property name="MappedResourcePath">../ServiceWithResourceInfor</property>
               <property name="MappedResourceName">Server1</property>
               </resource>
               </resourceList>
               ...
5.3.3.7. MatchingResourceProperty assignment policy
5.3.3.7.1. Usage

MatchingResourceProperty uses three values to find proper resource. These values are defined externally, through ResourceRequestDescription (see example). Information needed to successfully find resource:

  • serviceName - name of the service that might hold needed resource information.

  • resourcePropertyName - resource that should be used must contain this property.

  • {matchingPropertyName}} left for future use. At the moment should be string.Empty .

               ...
               // create dictionary with additional resource request details
               Dictionary<string, string> requestExtensions = new Dictionary<string, string>();
               // add one pair with key - resourceName, which has name of the resource (from the Resource Description) as value
               requestExtensions.Add("serviceName", "IISWebSite");
               requestExtensions.Add("resourcePropertyName", "DomainName");
               requestExtensions.Add("matchingPropertyName", string.Empty);
               // create resource request object
               ResourceRequestDescription requestDetails = new ResourceRequestDescription(null)
               {
               PolicyName = "MatchingResourceProperty",
               RequestExtensions = requestExtensions
               };
               // Add service on resource
               var addedService = coreApi.AddService(newlyCreatedService, null, "300500", requestDetails);
               ...
5.3.3.8. MatchingServiceName assignment policy
5.3.3.8.1. Usage

MatchingServiceName assignment policy uses service name to determine which resource is suitable for service being added. For each resource which will be using MatchingServiceName policy additional property must be added:

  • ServiceName - Exact service name or regular expression to match more then one service name.

Resource description example:

               ...
               <moduleList>
               <module name="Atomia.Provisioning.Modules.ExampleModule" resourceAsignmentPolicy="MatchingServiceName"/>
               </moduleList>
               <resourceList>
               <resource name="IISServer1">
               <property name="ServiceName">WindowsWebsite</property>
               </resource>
               </resourceList>
               ...
5.3.3.9. MatchingServiceNameLimitPerResource assignment policy
5.3.3.9.1. Usage

MatchingServiceNameLimitPerResource assignment policy is similar to MatchingServiceName assignment policy except that it allows limit of how many different accounts can have services on one resource. First it checks if account already has services on particular resource. If account has services on particular resource, it will be used again. If not, agent uses round robin queuing to check if next resource in list has not exceeded limit and allows service with given name to be provisioned on it. If resource which meets requirements is not found, exception is thrown.

For each resource which will be using MatchingServiceNameLimitPerResource policy additional properties must be added:

  • ServiceName - Exact service name or regular expression to match more then one service name.

  • MaxAccounts - Maximum number of accounts which can have services on specific resource.

Resource description example:

               ...
               <moduleList>
               <module name="Atomia.Provisioning.Modules.ExampleModule" resourceAsignmentPolicy="MatchingServiceNameLimitPerResource"/>
               </moduleList>
               <resourceList>
               <resource name="IISServer1">
               <property name="ServiceName">WindowsWebsite</property>
               <property name="MaxAccounts">200</property>
               </resource>
               </resourceList>
               ...
5.3.3.10. ResellerSpecific resource assignment policy
5.3.3.10.1. Usage

The ResellerSpecific resource assignment policy uses a reseller account id whitelist and subreseller property to specify what resellers are allowed to use a specific resource.

For each resource that should be using the ResellerSpecific policy an additional property list and property can be added:

  • ResellerSpecific.AllowedResellerIds - A property list where each item is an account id for a reseller that is allowed to use the resource. A resource without the list will be usable by all resellers.

  • ResellerSpecific.AllowSubresellers - A property that determines whether subresellers of a reselller on the whitelist are allowed to use the resource. none (default if property is not available) does not allow any subresellers. all allows any subreseller of resellers on the whitelist to use the resource. direct only allows subresellers that are direct children of the reseller on the whitelist.

Resource description example:

                ...
                <moduleList>
                <module name="Atomia.Provisioning.Modules.ExampleModule" resourceAsignmentPolicy="ResellerSpecific"/>
                </moduleList>
                <resourceList>
                <resource name="AtomiaDomainRegistration1">
                <property name="ResellerSpecific.AllowSubresellers">direct</property>
                <propertyList name="ResellerSpecific.AllowedResellerIds">
                <propertyListItem>100001</propertyList>
                </propertyList>
                </resource>
                </resourceList>
                ...
              
5.3.3.11. RoundRobinStickyPerAccountWithMaximum assignment policy
5.3.3.11.1. Usage

RoundRobinStickyPerAccountWithMaximum assignment policy works almost the same as MatchingServiceNameLimitPerResource assignment policy . The only difference is that limit is in services, not accounts, per resource.

For each resource which will be using RoundRobinStickyPerAccountWithMaximum policy additional property must be added:

  • MaxItems - Maximum number of accounts which can have services on specific resource.

Resource description example:

               ...
               <moduleList>
               <module name="Atomia.Provisioning.Modules.ExampleModule" resourceAsignmentPolicy="MatchingServiceNameLimitPerResource"/>
               </moduleList>
               <resourceList>
               <resource name="IISServer1">
               <property name="MaxItems">5000</property>
               </resource>
               </resourceList>
               ...

5.3.4. How to obtain Atomia Automation Server SDKs

5.3.4.1. Atomia Automation Server SDK

Please contact Atomia AB for information on how to obtain Atomia products. Contact information is available at www.atomia.com

5.3.4.2. Atomia Automation Server Module SDK

Please contact Atomia AB for information on how to obtain Atomia products. Contact information is available at www.atomia.com