/// return 0 if program completes successfully, -1 otherwise. public static int Main(string[] args) { if (args.Length < 1) { Console.WriteLine("This is for internal use only"); return(-1); } #if DEBUG // To add a sleep time while debugging add a "Sleep" key (in milliseconds) to the following registry location: HKLM\\Software\\Microsoft\\Service Fabric try { using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(FabricConstants.FabricRegistryKeyPath, true)) { var sleepRegVal = registryKey.GetValue("Sleep"); if (sleepRegVal != null) { int sleepinms = int.Parse(sleepRegVal.ToString()); ImageBuilderExe.TraceSource.WriteNoise(ImageBuilderExe.TraceType, "ImageBuilderExe: Sleep time requested: {0}", sleepinms.ToString()); Thread.Sleep(sleepinms); } } } catch (Exception e) { ImageBuilderExe.TraceSource.WriteNoise(ImageBuilderExe.TraceType, "ImageBuilderExe: Exception code:{0}, msg:{1} when attempting to read registry value \"Sleep\" in {2}.", e.HResult, e.Message, FabricConstants.FabricRegistryKeyPath); } #endif // Parameters // /schemaPath:<The xsd schema file of Windows Fabric ServiceModel> - optional. Default: <Current Working Directory>\ServiceFabricServiceModel.xsd // /workingDir:<The root of working directory of the node> - optional. Default: <Current Working Directory> // /storeRoot:<The root path of ImageStore> - optional // /output: <The root folder|file where output will be placed> - required // /input: <The root folder|file where input will be read from> - required for Delete // /progress: <The file where operation progress will be read from> - optional. Used by BuildApplicationType and DownloadAndBuildApplicationType. // /operation:<BuildApplicationTypeInfo | BuildApplicationType | BuildApplication | BuildComposeDeployment | ValidateComposeDeployment | UpgradeApplication | GetFabricVersion | ProvisionFabric | UpgradeFabric | Delete | TestErrorDetails | DownloadAndBuildApplicationType> - required // /timeout:<ticks> - optional /* ImageBuilder arguments for DownloadAndBuildApplicationType */ // /downloadPath: <path to .sfpkg file from a store that supports GET method> - required // /appTypeName:<Application Type Name> - required. Expected application type name in the downloaded package. // /appTypeVersion:<Application Type Version> - required. Expected application type version in the downloaded package. // /progress: <The file where operation progress will be read from> - optional. // /output: <The root folder|file where output will be placed> - required // /timeout:<ticks> - optional /* ImageBuilder arguments for BuildComposeDeployment */ // /cf:<Compose File path> - required // /of:<Overrides File path> - optional // /appTypeName:<Application Type Name> - required // /appTypeVersion:<Application Type Version> - required // /output: <The root folder|file where output application package will be placed> - required // /ocf:<Output Merged compose file path> - required // /repoUserName:<Repository User Name> - optional // /repoPwd:<Repository Password> - optional // /pwdEncrypted:<Is Repository Password encrypted> - optional // /cleanup:<Cleanup the compose files> - optional // /timeout:<ticks> - optional /* ImageBuilder arguments for ValidateComposeDeployment */ // /cf:<Compose File path> - required // /of:<Overrides File path> - optional // /appTypeName:<Application Type Name> - optional // /appTypeVersion:<Application Type Version> - optional // /cleanup:<Cleanup the compose files> - optional // /timeout:<ticks> - optional /* ImageBuilder arguments for Application */ // /appTypeName:<Application Type Name> - required for BuildApplication and UpgradeApplication operation // /appTypeVersion:<Application Type Version> - required for BuildApplication and UpgradeApplication operation // /appId:<Application ID> - required for BuildApplication and UpgradeApplication operation // /nameUri:<Name URI> - required for BuildApplication operation // /appParam:<semi-colon separated key-value pair>. Multiple such parameters can be passed. Key cannot have ';'. // /buildPath: <The root folder of build layout> - required for ApplicationTypeInfo and BuildApplicationType operation // /currentAppInstanceVersion: <The current app instance of the Application that needs to be upgraded> - required for UpgradeApplication operation /* ImageBuilder arguments for Fabric Upgrade */ // /codePath: <The path to MSP for FabricUpgrade> // /configPath: <The path to ClusterManifest for FabricUpgrade> // /currentFabricVersion: <The current FabricVersion> // /targetFabricVersion: <The target FabricVersion> // /im: <Path to InfrastructureManifest.xml file> // Dictionary <string, string> commandArgs = null; Exception exception = null; string errorDetailsFile = null; try { commandArgs = ParseParameters(args); // Ensure that required parameters are present EnsureRequiredCommandLineParameters(commandArgs); Dictionary <string, string> applicationParameters = ParseAppParameters(commandArgs); errorDetailsFile = commandArgs.ContainsKey(StringConstants.ErrorDetails) ? commandArgs[StringConstants.ErrorDetails] : null; string workingDirectory = commandArgs.ContainsKey(StringConstants.WorkingDir) ? commandArgs[StringConstants.WorkingDir] : Directory.GetCurrentDirectory(); string imageStoreConnectionString; if (commandArgs.ContainsKey(StringConstants.StoreRoot)) { imageStoreConnectionString = commandArgs[StringConstants.StoreRoot]; } else { ImageBuilderExe.TraceSource.WriteInfo(ImageBuilderExe.TraceType, "Loading ImageStoreConnectionString from config."); bool isEncrypted; NativeConfigStore configStore = NativeConfigStore.FabricGetConfigStore(); var configValue = configStore.ReadString("Management", "ImageStoreConnectionString", out isEncrypted); if (isEncrypted) { var secureString = NativeConfigStore.DecryptText(configValue); var secureCharArray = FabricValidatorUtility.SecureStringToCharArray(secureString); imageStoreConnectionString = new string(secureCharArray); } else { imageStoreConnectionString = configValue; } if (string.IsNullOrEmpty(imageStoreConnectionString)) { throw new ArgumentException(StringResources.Error_MissingImageStoreConnectionStringInManifest); } } StringBuilder stringToTrace = new StringBuilder(); foreach (var commandArg in commandArgs) { // Skipping tracing StoreRoot since it could be a secret value if (!ImageBuilderUtility.Equals(commandArg.Key, StringConstants.StoreRoot)) { stringToTrace.AppendFormat("{0}:{1}", commandArg.Key, commandArg.Value); stringToTrace.AppendLine(); } } ImageBuilderExe.TraceSource.WriteInfo( ImageBuilderExe.TraceType, "ImageBuilderExe called with - {0}", stringToTrace.ToString()); string currentExecutingDirectory = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); string schemaPath = commandArgs.ContainsKey(StringConstants.SchemaPath) ? commandArgs[StringConstants.SchemaPath] : Path.Combine( currentExecutingDirectory, StringConstants.DefaultSchemaPath); TimeSpan timeout = commandArgs.ContainsKey(StringConstants.Timeout) ? TimeSpan.FromTicks(long.Parse(commandArgs[StringConstants.Timeout])) : TimeSpan.MaxValue; Timer timer = null; if (timeout != TimeSpan.MaxValue) { ImageBuilderExe.TraceSource.WriteInfo( ImageBuilderExe.TraceType, "ImageBuilderExe enabled timeout monitor: {0}", timeout); timer = new Timer(OnTimeout, errorDetailsFile, timeout, TimeSpan.FromMilliseconds(-1)); } IImageStore imageStore = ImageStoreFactoryProxy.CreateImageStore( imageStoreConnectionString, null, workingDirectory, true /*isInternal*/); ImageBuilder imageBuilder = new ImageBuilder(imageStore, schemaPath, workingDirectory); string operationValue = commandArgs[StringConstants.Operation]; bool sfVolumeDiskServiceEnabled = commandArgs.ContainsKey(StringConstants.SFVolumeDiskServiceEnabled) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.SFVolumeDiskServiceEnabled]) : false; imageBuilder.IsSFVolumeDiskServiceEnabled = sfVolumeDiskServiceEnabled; if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationDownloadAndBuildApplicationType)) { string progressFile = commandArgs.ContainsKey(StringConstants.Progress) ? commandArgs[StringConstants.Progress] : null; bool shouldSkipChecksumValidation = commandArgs.ContainsKey(StringConstants.DisableChecksumValidation) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.DisableChecksumValidation]) : false; imageBuilder.DownloadAndBuildApplicationType( commandArgs[StringConstants.DownloadPath], commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.AppTypeVersion], commandArgs[StringConstants.Output], timeout, progressFile, shouldSkipChecksumValidation); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildApplicationTypeInfo)) { imageBuilder.GetApplicationTypeInfo(commandArgs[StringConstants.BuildPath], timeout, commandArgs[StringConstants.Output]); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildApplicationType)) { string outputFile = commandArgs.ContainsKey(StringConstants.Output) ? commandArgs[StringConstants.Output] : null; string progressFile = commandArgs.ContainsKey(StringConstants.Progress) ? commandArgs[StringConstants.Progress] : null; bool shouldSkipChecksumValidation = commandArgs.ContainsKey(StringConstants.DisableChecksumValidation) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.DisableChecksumValidation]) : false; bool shouldSkipServerSideCopy = commandArgs.ContainsKey(StringConstants.DisableServerSideCopy) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.DisableServerSideCopy]) : false; imageBuilder.BuildApplicationType(commandArgs[StringConstants.BuildPath], timeout, outputFile, progressFile, shouldSkipChecksumValidation, shouldSkipServerSideCopy); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildSingleInstanceApplication)) { bool generateDnsNames = commandArgs.ContainsKey(StringConstants.GenerateDnsNames) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.GenerateDnsNames]) : false; bool useOpenNetworkConfig = commandArgs.ContainsKey(StringConstants.UseOpenNetworkConfig) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.UseOpenNetworkConfig]) : false; Application application = null; using (StreamReader file = File.OpenText(commandArgs[StringConstants.SingleInstanceApplicationDescription])) { JsonSerializer serializer = new JsonSerializer(); serializer.Converters.Add(new DiagnosticsSinkJsonConverter()); serializer.Converters.Add(new VolumeMountJsonConverter()); application = (Application)serializer.Deserialize(file, typeof(Application)); } GenerationConfig config = null; if (commandArgs.ContainsKey(StringConstants.GenerationConfig)) { using (StreamReader file = File.OpenText(commandArgs[StringConstants.GenerationConfig])) { JsonSerializer serializer = new JsonSerializer(); config = (GenerationConfig)serializer.Deserialize(file, typeof(GenerationConfig)); } } imageBuilder.BuildSingleInstanceApplication( application, commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.AppTypeVersion], commandArgs[StringConstants.AppId], new Uri(commandArgs[StringConstants.AppName]), generateDnsNames, timeout, commandArgs[StringConstants.BuildPath], commandArgs[StringConstants.Output], useOpenNetworkConfig, config); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildSingleInstanceApplicationForUpgrade)) { bool generateDnsNames = commandArgs.ContainsKey(StringConstants.GenerateDnsNames) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.GenerateDnsNames]) : false; bool useOpenNetworkConfig = commandArgs.ContainsKey(StringConstants.UseOpenNetworkConfig) ? ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.UseOpenNetworkConfig]) : false; Application application = null; using (StreamReader file = File.OpenText(commandArgs[StringConstants.SingleInstanceApplicationDescription])) { JsonSerializer serializer = new JsonSerializer(); serializer.Converters.Add(new VolumeMountJsonConverter()); application = (Application)serializer.Deserialize(file, typeof(Application)); } GenerationConfig config = null; if (commandArgs.ContainsKey(StringConstants.GenerationConfig)) { using (StreamReader file = File.OpenText(commandArgs[StringConstants.GenerationConfig])) { JsonSerializer serializer = new JsonSerializer(); config = (GenerationConfig)serializer.Deserialize(file, typeof(GenerationConfig)); } } imageBuilder.BuildSingleInstanceApplicationForUpgrade( application, commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.CurrentAppTypeVersion], commandArgs[StringConstants.TargetAppTypeVersion], commandArgs[StringConstants.AppId], int.Parse(commandArgs[StringConstants.CurrentAppInstanceVersion], CultureInfo.InvariantCulture), new Uri(commandArgs[StringConstants.AppName]), generateDnsNames, timeout, commandArgs[StringConstants.BuildPath], commandArgs[StringConstants.Output], useOpenNetworkConfig, config); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildApplication)) { imageBuilder.BuildApplication( commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.AppTypeVersion], commandArgs[StringConstants.AppId], new Uri(commandArgs[StringConstants.NameUri]), applicationParameters, timeout, commandArgs[StringConstants.Output]); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationUpgradeApplication)) { imageBuilder.UpgradeApplication( commandArgs[StringConstants.AppId], commandArgs[StringConstants.AppTypeName], int.Parse(commandArgs[StringConstants.CurrentAppInstanceVersion], CultureInfo.InvariantCulture), commandArgs[StringConstants.AppTypeVersion], applicationParameters, timeout, commandArgs[StringConstants.Output]); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationDelete)) { imageBuilder.Delete(commandArgs[StringConstants.Input], timeout); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationCleanupApplicationPackage)) { imageBuilder.DeleteApplicationPackage(commandArgs[StringConstants.BuildPath], timeout); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationGetFabricVersion)) { imageBuilder.GetFabricVersionInfo( commandArgs[StringConstants.CodePath], commandArgs[StringConstants.ConfigPath], timeout, commandArgs[StringConstants.Output]); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationProvisionFabric)) { string configurationCsvFilePath = Path.Combine(currentExecutingDirectory, StringConstants.ConfigurationsFileName); imageBuilder.ProvisionFabric( commandArgs[StringConstants.CodePath], commandArgs[StringConstants.ConfigPath], configurationCsvFilePath, commandArgs[StringConstants.InfrastructureManifestFile], timeout); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationGetClusterManifest)) { imageBuilder.GetClusterManifestContents( commandArgs[StringConstants.ConfigVersion], commandArgs[StringConstants.Output], timeout); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationUpgradeFabric)) { string configurationCsvFilePath = Path.Combine(currentExecutingDirectory, StringConstants.ConfigurationsFileName); imageBuilder.UpgradeFabric( commandArgs[StringConstants.CurrentFabricVersion], commandArgs[StringConstants.TargetFabricVersion], configurationCsvFilePath, timeout, commandArgs[StringConstants.Output]); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationGetManifests)) { imageBuilder.GetManifests(commandArgs[StringConstants.Input], timeout); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationValidateComposeDeployment)) { bool cleanupComposeFiles = commandArgs.ContainsKey(StringConstants.CleanupComposeFiles) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.CleanupComposeFiles]); HashSet <string> ignoredKeys; imageBuilder.ValidateComposeDeployment( commandArgs[StringConstants.ComposeFilePath], commandArgs.ContainsKey(StringConstants.OverrideFilePath) ? commandArgs[StringConstants.OverrideFilePath] : null, commandArgs.ContainsKey(StringConstants.AppName) ? commandArgs[StringConstants.AppName] : null, commandArgs.ContainsKey(StringConstants.AppTypeName) ? commandArgs[StringConstants.AppTypeName] : null, commandArgs.ContainsKey(StringConstants.AppTypeVersion) ? commandArgs[StringConstants.AppTypeVersion] : null, timeout, out ignoredKeys, cleanupComposeFiles); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildComposeDeployment)) { bool cleanupComposeFiles = commandArgs.ContainsKey(StringConstants.CleanupComposeFiles) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.CleanupComposeFiles]); bool shouldSkipChecksumValidation = commandArgs.ContainsKey(StringConstants.DisableChecksumValidation) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.DisableChecksumValidation]); bool isPasswordEncrypted = commandArgs.ContainsKey(StringConstants.IsRepositoryPasswordEncrypted) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.IsRepositoryPasswordEncrypted]); bool generateDnsNames = commandArgs.ContainsKey(StringConstants.GenerateDnsNames) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.GenerateDnsNames]); imageBuilder.BuildComposeDeploymentPackage( commandArgs[StringConstants.ComposeFilePath], commandArgs.ContainsKey(StringConstants.OverrideFilePath) ? commandArgs[StringConstants.OverrideFilePath] : null, timeout, commandArgs.ContainsKey(StringConstants.AppName) ? commandArgs[StringConstants.AppName] : null, commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.AppTypeVersion], commandArgs.ContainsKey(StringConstants.RepositoryUserName) ? commandArgs[StringConstants.RepositoryUserName] : null, commandArgs.ContainsKey(StringConstants.RepositoryPassword) ? commandArgs[StringConstants.RepositoryPassword] : null, isPasswordEncrypted, generateDnsNames, commandArgs[StringConstants.OutputComposeFilePath], commandArgs[StringConstants.Output], cleanupComposeFiles, shouldSkipChecksumValidation); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.OperationBuildComposeApplicationForUpgrade)) { bool cleanupComposeFiles = commandArgs.ContainsKey(StringConstants.CleanupComposeFiles) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.CleanupComposeFiles]); bool shouldSkipChecksumValidation = commandArgs.ContainsKey(StringConstants.DisableChecksumValidation) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.DisableChecksumValidation]); bool isPasswordEncrypted = commandArgs.ContainsKey(StringConstants.IsRepositoryPasswordEncrypted) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.IsRepositoryPasswordEncrypted]); bool generateDnsNames = commandArgs.ContainsKey(StringConstants.GenerateDnsNames) && ImageBuilderUtility.ConvertString <bool>(commandArgs[StringConstants.GenerateDnsNames]); imageBuilder.BuildComposeDeploymentPackageForUpgrade( commandArgs[StringConstants.ComposeFilePath], commandArgs.ContainsKey(StringConstants.OverrideFilePath) ? commandArgs[StringConstants.OverrideFilePath] : null, timeout, commandArgs.ContainsKey(StringConstants.AppName) ? commandArgs[StringConstants.AppName] : null, commandArgs[StringConstants.AppTypeName], commandArgs[StringConstants.CurrentAppTypeVersion], commandArgs[StringConstants.TargetAppTypeVersion], commandArgs.ContainsKey(StringConstants.RepositoryUserName) ? commandArgs[StringConstants.RepositoryUserName] : null, commandArgs.ContainsKey(StringConstants.RepositoryPassword) ? commandArgs[StringConstants.RepositoryPassword] : null, isPasswordEncrypted, generateDnsNames, commandArgs[StringConstants.OutputComposeFilePath], commandArgs[StringConstants.Output], cleanupComposeFiles, shouldSkipChecksumValidation); } else if (ImageBuilderUtility.Equals(operationValue, StringConstants.TestErrorDetails)) { throw new Exception(StringConstants.TestErrorDetails); } else { throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, StringResources.Error_ImageBuilderExeCommandLineInvalidOperation, StringConstants.Operation, operationValue)); } } catch (AggregateException ae) { exception = ae.InnerException; StringBuilder exceptionStringBuilder = new StringBuilder("Aggregate exception has "); exceptionStringBuilder.Append(ae.InnerExceptions.Count); exceptionStringBuilder.Append(" exceptions. "); ae.InnerExceptions.ForEach(innerException => exceptionStringBuilder.AppendLine(innerException.Message)); ImageBuilderExe.TraceSource.WriteWarning( ImageBuilderExe.TraceType, "AggregateException: {0}", exceptionStringBuilder.ToString()); } catch (Exception e) { exception = e; } if (exception != null) { OnFailure(exception, errorDetailsFile); return(unchecked ((int)NativeTypes.FABRIC_ERROR_CODE.FABRIC_E_IMAGEBUILDER_UNEXPECTED_ERROR)); } else { ImageBuilderExe.TraceSource.WriteInfo( ImageBuilderExe.TraceType, "ImageBuilderExe operation completed successfully."); return(0); } }