/// <summary> /// Restarts the service. /// </summary> /// <param name="serviceCreator">Callback that creates and returns the new service instance.</param> /// <param name="runningTimeout"> /// Optionally specifies the maximum time the fixture should wait for the service to transition /// to the <see cref="KubeServiceStatus.Running"/> state. This defaults to <b>30 seconds</b>. /// </param> /// <exception cref="TimeoutException"> /// Thrown if the service didn't transition to the running (or terminated) state /// within <paramref name="runningTimeout"/>. /// </exception> /// <remarks> /// <para> /// This method first calls the <paramref name="serviceCreator"/> callback and expects /// it to return a new service instance that has been initialized by setting its environment /// variables and configuration files as required. The callback should not start thge service. /// </para> /// </remarks> public void Restart(Func <TService> serviceCreator = null, TimeSpan runningTimeout = default) { Covenant.Requires <ArgumentNullException>(serviceCreator != null, nameof(serviceCreator)); if (runningTimeout == default) { runningTimeout = defaultRunningTimeout; } StopService(); ClearCaches(); Service = serviceCreator(); Covenant.Assert(Service != null); serviceTask = Service.RunAsync(); // Wait for the service to signal that it's running or has terminated. try { NeonHelper.WaitFor(() => Service.Status == KubeServiceStatus.Running || Service.Status == KubeServiceStatus.Terminated, runningTimeout); } catch (TimeoutException) { // Throw a nicer exception that explains what's happened in more detail. throw new TimeoutException($"Service [{Service.Name}]'s [{typeof(TService).Name}.OnRunAsync()] method did not call [{nameof(KubeService.SetRunning)}()] within [{runningTimeout}] indicating that the service is ready. Ensure that [{nameof(KubeService.SetRunning)}()] is being called or increase the timeout."); } IsRunning = Service.Status == KubeServiceStatus.Running; }
/// <summary> /// Returns a single-use client. /// </summary> /// <returns>The client.</returns> /// <exception cref="ObjectDisposedException">Thrown when the instance is disposed.</exception> private HttpClient GetSingleUseClient() { Covenant.Assert(disableConnectionReuse); var client = GetClient(); HttpClient singleUseClient; if (handler == null) { singleUseClient = new HttpClient(); } else { singleUseClient = new HttpClient(handler, disposeHandler: false); } // Copy the settings from client to the new single use client. singleUseClient.BaseAddress = client.BaseAddress; singleUseClient.Timeout = client.Timeout; foreach (var item in client.DefaultRequestHeaders) { singleUseClient.DefaultRequestHeaders.Add(item.Key, item.Value); } return(singleUseClient); }
/// <summary> /// <para> /// Converts the <see cref="TlsCertificate"/> into a <see cref="X509Certificate2"/>. /// </para> /// <note> /// The certificate return <b>will not</b> include the <see cref="TlsCertificate"/>'s private /// key if there is one. /// </note> /// </summary> /// <returns>The new <see cref="X509Certificate2"/>.</returns> public X509Certificate2 ToX509Certificate2() { Covenant.Assert(!string.IsNullOrEmpty(CertPem)); // We're going to extract the base-64 encoded certificate lines into a single // long line of text, decode that into raw bytes and then use that to construct // the X509Certificate2. var sb = new StringBuilder(); using (var reader = new StringReader(CertPem)) { foreach (var l in reader.Lines()) { var line = l.Trim(); if (line.Length == 0 || line.StartsWith("-----BEGIN ") || line.StartsWith("-----END ")) { continue; } sb.Append(line); } } var bytes = Convert.FromBase64String(sb.ToString()); var x509Cert = new X509Certificate2(bytes, (string)null, X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); x509Cert.FriendlyName = this.FriendlyName; return(x509Cert); }
/// <summary> /// Selects target node backends based on the <see cref="Group"/> and <see cref="GroupLimit"/> properties /// and the host groups passed. This works only for backends that target a group. /// </summary> /// <param name="hostGroups"> /// Dictionary mapping host group names to the list of host node /// definitions within the named group. /// </param> /// <returns>The selected hive host node definitions.</returns> /// <exception cref="InvalidOperationException">Thrown if the backend does not target a group.</exception> public List <NodeDefinition> SelectGroupNodes(Dictionary <string, List <NodeDefinition> > hostGroups) { Covenant.Requires <ArgumentNullException>(hostGroups != null); Covenant.Assert(hostGroups.Count(g => g.Key.Equals(HiveHostGroups.All, StringComparison.InvariantCultureIgnoreCase)) > 0, "Expecting the [all] group to be present."); if (string.IsNullOrEmpty(Group)) { throw new InvalidOperationException($"[{nameof(TrafficBackend)}.{nameof(Group)}()] works only for rule backends that target a group."); } if (!hostGroups.TryGetValue(Group, out var groupNodes)) { // The group doesn't exist so return an empty list. return(new List <NodeDefinition>()); } if (GroupLimit == 0 || GroupLimit >= groupNodes.Count) { // If there is no group limit or the limit is greater than or equal // to the number of group nodes, so just return the group nodes. return(groupNodes); } else { // Randomly select [GroupLimit] nodes. return(groupNodes.SelectRandom(GroupLimit).ToList()); } }
/// <summary> /// Attempts to construct an instance of <paramref name="resultType"/> from a <see cref="Stream"/>. /// </summary> /// <param name="resultType">The result type.</param> /// <param name="stream">The source <see cref="Stream"/>.</param> /// <param name="encoding">Optionally specifies the encoding (defaults to UTF-8).</param> /// <returns> /// <c>true</c> if the object type implements <see cref="IRoundtripData"/> and the /// object was successfully deserialized. /// </returns> public static async Task <Tuple <bool, object> > TryCreateFromAsync(Type resultType, Stream stream, Encoding encoding) { await SyncContext.ClearAsync; Covenant.Requires <ArgumentNullException>(resultType != null, nameof(resultType)); Covenant.Requires <ArgumentNullException>(stream != null, nameof(stream)); if (encoding == null) { encoding = Encoding.UTF8; } MethodInfo createMethod; lock (classNameToStreamAsyncCreateMethod) { if (!classNameToStreamAsyncCreateMethod.TryGetValue(resultType.FullName, out createMethod)) { if (!resultType.Implements <IRoundtripData>()) { return(Tuple.Create <bool, object>(false, null)); } createMethod = resultType.GetMethod("CreateFromAsync", BindingFlags.Public | BindingFlags.Static, null, createFromStreamArgTypes, null); #if DEBUG Covenant.Assert(createMethod != null, $"Cannot locate generated [{resultType.FullName}.CreateFromAsync(Stream, Encoding)] method."); #endif classNameToStreamAsyncCreateMethod.Add(resultType.FullName, createMethod); } } return(Tuple.Create <bool, object>(true, await(Task <object>) createMethod.Invoke(null, new object[] { stream, encoding }))); }
/// <summary> /// Constructs an instance of <paramref name="resultType"/> from a <see cref="Stream"/>. /// </summary> /// <param name="resultType">The result type.</param> /// <param name="stream">The source <see cref="Stream"/>.</param> /// <param name="encoding">Optionally specifies the encoding (defaults to UTF-8).</param> /// <returns>The new instance as an <see cref="object"/>.</returns> public static async Task <object> CreateFromAsync(Type resultType, Stream stream, Encoding encoding = null) { Covenant.Requires(resultType != null); Covenant.Requires(stream != null); if (encoding == null) { encoding = Encoding.UTF8; } MethodInfo createMethod; lock (classNameToStreamCreateMethod) { if (!classNameToStreamCreateMethod.TryGetValue(resultType.FullName, out createMethod)) { if (!resultType.Implements <IRoundtripData>()) { throw new InvalidOperationException($"Type [{resultType.FullName}] does not implement [{nameof(IRoundtripData)}]."); } createMethod = resultType.GetMethod("CreateFromAsync", BindingFlags.Public | BindingFlags.Static, null, createFromStreamArgTypes, null); #if DEBUG Covenant.Assert(createMethod != null, $"Cannot locate generated [{resultType.FullName}.CreateFromAsync(Stream, Encoding)] method."); #endif classNameToStreamCreateMethod.Add(resultType.FullName, createMethod); } } return(await(Task <object>) createMethod.Invoke(null, new object[] { stream, encoding })); }
/// <summary> /// Constructor. /// </summary> /// <param name="defaultNamespace">The default namespace to be used for instanting types.</param> /// <param name="assemblyStream">The stream holding the assembly to be loaded.</param> public AssemblyContext(string defaultNamespace, Stream assemblyStream) : base(isCollectible: true) { Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(defaultNamespace)); Covenant.Requires <ArgumentNullException>(assemblyStream != null); Covenant.Assert(Current == null); AssemblyContext.Current = this; // We need the [Neon.Common] assembly. base.LoadFromAssemblyPath(typeof(IRoundtripData).Assembly.Location); // Load the assembly passed. this.DefaultNamespace = defaultNamespace; this.LoadedAssembly = LoadFromStream(assemblyStream); // Also load the [Neon.Common] assembly. This should be located // in the same directory as the running test assembly. var currentAssembly = Assembly.GetExecutingAssembly(); var currentAssemblyPath = currentAssembly.Location; this.NeonCommonAssembly = base.LoadFromAssemblyPath(Path.Combine(Path.GetDirectoryName(currentAssemblyPath), "Neon.Common.dll")); }
public Test_SimpleComposedFixture(ComposedFixture fixture) { this.fixture = fixture; fixture.Start( () => { fixture.AddFixture("zero", fixture0 = new Fixture0(), subFixture => { fixture0Initialized = true; }); fixture.AddFixture("one", fixture1 = new Fixture1(), subFixture => { fixture1Initialized = true; }); // Ensure that the subfixtures were initialized first // and that their actions were called. Covenant.Assert(fixture0Initialized); Covenant.Assert(fixture1Initialized); // Ensure that the subfixture indexers work. Covenant.Assert(fixture[0] == fixture0); Covenant.Assert(fixture[1] == fixture1); Covenant.Assert(fixture["zero"] == fixture0); Covenant.Assert(fixture["one"] == fixture1); }); }
//--------------------------------------------------------------------- // Implementation /// <summary> /// Static constructor. /// </summary> static PriorityClass() { var list = new List <PriorityDef>(); list.Add(SystemNodeCritical = new PriorityDef("system-node-critical ", 2000001000, isSystem: true)); list.Add(SystemClusterCritical = new PriorityDef("system-cluster-critical", 2000000000, isSystem: true)); list.Add(NeonMax = new PriorityDef("neon-max", 999999999, description: "Maximum priority reserved by neonKUBE")); list.Add(NeonOperator = new PriorityDef("neon-operator", 900008000, description: "Used for critical neonKUBE operator pods")); list.Add(NeonNetwork = new PriorityDef("neon-network", 900007000, description: "Used for critical neonKUBE networking pods")); list.Add(NeonStorage = new PriorityDef("neon-storage", 900006000, description: "Used for critical neonKUBE low-level storage pods")); list.Add(NeonData = new PriorityDef("neon-data", 900005000, description: "Used for critical neonKUBE databases pods")); list.Add(NeonApi = new PriorityDef("neon-api", 900004000, description: "Used for neonKUBE API pods")); list.Add(NeonApp = new PriorityDef("neon-app", 900003000, description: "Used for neonKUBE application and dashboard pods")); list.Add(NeonMonitor = new PriorityDef("neon-monitor", 900002000, description: "Used for neonKUBE monitoring infrastructure pods")); list.Add(NeonMin = new PriorityDef("neon-min", 900000000, description: "Minimum priority reserved by neonKUBE")); list.Add(UserVeryHigh = new PriorityDef("user-veryhigh", 5000, description: "Used for very-high priority user pods")); list.Add(UserHigh = new PriorityDef("user-high", 4000, description: "Used for high priority user pods")); list.Add(UserMedium = new PriorityDef("user-medium", 3000, description: "Used for medium priority user pods", isDefault: true)); list.Add(UserLow = new PriorityDef("user-low", 2000, description: "Used for low-priority user pods")); list.Add(UserVeryLow = new PriorityDef("user-verylow", 1000, description: "Used for very low priority user pods")); Values = list; Covenant.Assert(Values.Count(priorityDef => priorityDef.IsDefault) <= 1, "Only one priority class may be global."); }
/// <summary> /// Returns the URI to the Vault server running on the named manager node. /// </summary> /// <param name="managerName">The target manager name.</param> /// <returns>The Vault URI.</returns> public string GetVaultDirectUri(string managerName) { Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(managerName)); Covenant.Assert(Managers.Where(m => m.Name == managerName) != null, $"[{managerName}] does not identify a hive manager."); return($"https://{managerName}.{Hostnames.Vault}:{Vault.Port}"); }
/// <summary> /// <para> /// Starts or restarts the timer. /// </para> /// <para> /// The <paramref name="interval"/> must be specified as a positive interval when /// the timer is first started but this is optional thereafter, defaulting to /// value from the original <see cref="Start(TimeSpan, bool, Func{Task})"/> call. /// </para> /// </summary> /// <param name="interval">Optionally specifies the timer interval.</param> /// <param name="delayFirstTick"> /// The callback is called immediately by default. You can delay this until /// the interval has passed by passing this as <c>true</c>. /// </param> /// <param name="callback"> /// <para> /// Optionally specifies the timer callback. /// </para> /// <note> /// This must be specified if no callback was passed to the constructor or a previous /// call to <see cref="Start(TimeSpan, bool, Func{Task})"/>. /// </note> /// </param> /// <exception cref="InvalidOperationException"> /// Thrown if this is the first time <see cref="Start(TimeSpan, bool, Func{Task})"/> is called for the /// instance and <paramref name="interval"/> is not passed or when <paramref name="callback"/> is /// <c>null</c> and no callback was specified in constructor or a previous call to /// <see cref="Start(TimeSpan, bool, Func{Task})"/>. /// </exception> /// <exception cref="ObjectDisposedException">Thrown then the instance is disposed.</exception> public void Start(TimeSpan interval = default, bool delayFirstTick = false, Func <Task> callback = null) { Covenant.Requires <ArgumentException>(interval >= TimeSpan.Zero, nameof(interval)); if (callback == null && this.callback == null) { throw new InvalidOperationException($"[{nameof(callback)}] must be non-null when no callback was passed to the constructor or a previous call to [{nameof(Start)}()]."); } else if (callback != null) { this.callback = callback; } lock (syncLock) { CheckDisposed(); if (this.interval == TimeSpan.Zero) { // This is the first time this method has been called for the instance. Covenant.Assert(!IsRunning); if (interval == TimeSpan.Zero) { throw new InvalidOperationException($"[{nameof(interval)}] must be positive the first time [{nameof(Start)}()] is called."); } this.interval = interval; } else { // We're restarting the timer so signal any existing timer task to // exit and set the new interval (if any). if (IsRunning) { Covenant.Assert(cts != null); cts.Cancel(); timerTask.WaitWithoutAggregate(); cts = null; timerTask = null; } if (interval > TimeSpan.Zero) { this.interval = interval; } } // Start/Restart the timer. this.delayFirstTick = delayFirstTick; this.cts = new CancellationTokenSource(); this.timerTask = TimerLoopAsync(); } }
//--------------------------------------------------------------------- // Instance members /// <summary> /// Constructor. /// </summary> /// <param name="loaderAction"> /// The optional action that will initialize the static <see cref="Loader"/> property with /// the <see cref="IHostingLoader"/> implemention. /// </param> public HostingManagerFactory(Action loaderAction = null) { if (loaderAction != null) { loaderAction(); Covenant.Assert(Loader != null); } }
/// <summary> /// Resolves the type passed into a nice string taking generic types /// and arrays into account. This is used when generating workflow /// and activity stubs. /// </summary> /// <param name="type">The referenced type.</param> /// <returns>The type reference as a string or <c>null</c> if the type is not valid.</returns> public static string TypeToCSharp(Type type) { if (type == typeof(void)) { return("void"); } if (type.IsPrimitive || (!type.IsArray && !type.IsGenericType)) { return(GetTypeName(type)); } if (type.IsArray) { // We need to handle jagged arrays where the element type // is also an array. We'll accomplish this by walking down // the element types until we get to a non-array element type, // counting how many subarrays there were. var arrayDepth = 0; var elementType = type.GetElementType(); while (elementType.IsArray) { arrayDepth++; elementType = elementType.GetElementType(); } var arrayRef = TypeToCSharp(elementType); for (int i = 0; i <= arrayDepth; i++) { arrayRef += "[]"; } return(arrayRef); } else if (type.IsGenericType) { var genericRef = GetTypeName(type); var genericParams = string.Empty; foreach (var genericParamType in type.GetGenericArguments()) { if (genericParams.Length > 0) { genericParams += ", "; } genericParams += TypeToCSharp(genericParamType); } return($"{genericRef}<{genericParams}>"); } Covenant.Assert(false); // We should never get here. return(null); }
/// <summary> /// Returns the <see cref="ActivityRegistration"/> for any activity type and activity type name. /// </summary> /// <param name="activityType">The target activity type.</param> /// <param name="activityTypeName">The target activity type name.</param> /// <returns>The <see cref="ActivityRegistration"/>.</returns> private static ActivityRegistration GetActivityInvokeInfo(Type activityType, string activityTypeName) { Covenant.Requires <ArgumentNullException>(activityType != null, nameof(activityType)); Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(activityTypeName), nameof(activityTypeName)); var info = new ActivityRegistration(); // Locate the target method. Note that the activity type name will be // formatted like: // // CLIENT-ID::TYPE-NAME // or CLIENT-ID::TYPE-NAME::METHOD-NAME var activityTypeNameParts = activityTypeName.Split(CadenceHelper.ActivityTypeMethodSeparator.ToCharArray(), 3); var activityMethodName = (string)null; Covenant.Assert(activityTypeNameParts.Length >= 2); if (activityTypeNameParts.Length > 2) { activityMethodName = activityTypeNameParts[2]; } if (string.IsNullOrEmpty(activityMethodName)) { activityMethodName = null; } foreach (var method in activityType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var activityMethodAttribute = method.GetCustomAttribute <ActivityMethodAttribute>(); if (activityMethodAttribute == null) { continue; } var name = activityMethodAttribute.Name; if (string.IsNullOrEmpty(name)) { name = null; } if (name == activityMethodName) { info.ActivityMethod = method; break; } } if (info.ActivityMethod == null) { throw new ArgumentException($"Activity type [{activityType.FullName}] does not have an entry point method tagged with [ActivityMethod(Name = \"{activityMethodName}\")].", nameof(activityType)); } return(info); }
/// <inheritdoc/> public override void AddProvisioningSteps(SetupController <NodeDefinition> controller) { Covenant.Requires <ArgumentNullException>(controller != null, nameof(controller)); Covenant.Assert(cluster != null, $"[{nameof(BareMetalHostingManager)}] was created with the wrong constructor."); this.controller = controller; throw new NotImplementedException(); }
public async Task Constrained() { // Verify that we can constrain the number of tasks that run in // parallel to something less than the number of available threads // in the pool. var syncLock = new object(); var maxParallel = MaxPoolThreads - 2; var workItems = new List <int>(); var completed = new HashSet <int>(); var parallelCount = 0; var parallelCounts = new List <int>(); Covenant.Assert(maxParallel > 0, "Insufficient pool threads available."); for (int i = 0; i < maxParallel + 2; i++) { workItems.Add(i); } await Async.ForEachAsync(workItems, async item => { lock (syncLock) { parallelCount++; parallelCounts.Add(parallelCount); } await Task.Delay(delay); Interlocked.Decrement(ref parallelCount); lock (syncLock) { parallelCount--; completed.Add(item); } }, maxParallel : maxParallel); Assert.True(maxParallel >= parallelCounts.Max()); // Ensure that all work items completed. var allCompleted = true; foreach (var item in workItems) { if (!completed.Contains(item)) { allCompleted = false; break; } } Assert.True(allCompleted); }
public async Task Cancellation() { // Verify that cancellation tokens work. var syncLock = new object(); var maxParallel = MaxPoolThreads - 2; var workItems = new List <int>(); var cts = new CancellationTokenSource(); var completed = new HashSet <int>(); var parallelCount = 0; var parallelCounts = new List <int>(); Covenant.Assert(maxParallel > 0, "Insufficient pool threads available."); for (int i = 0; i < maxParallel + 2; i++) { workItems.Add(i); } var task = Async.ForEachAsync(workItems, async(item, cancellationToken) => { lock (syncLock) { parallelCount++; parallelCounts.Add(parallelCount); } await Task.Delay(delay); Interlocked.Decrement(ref parallelCount); cancellationToken.ThrowIfCancellationRequested(); lock (syncLock) { parallelCount--; completed.Add(item); } }, cancellationToken: cts.Token, maxParallel: maxParallel); // Wait 1/2 of the execution time for each work item // and cancel the operation. Then wait for the overall // operation to complete with an [OperationCanceledException]. await Task.Delay(TimeSpan.FromSeconds(delay.TotalSeconds / 2)); cts.Cancel(); await Assert.ThrowsAsync <OperationCanceledException>(async() => await task); // Verify Assert.True(maxParallel >= parallelCounts.Max()); Assert.Empty(completed); }
/// <summary> /// Strips the leading client ID from the workflow type key passed /// and returns the type name actually registered with Cadence. /// </summary> /// <param name="workflowTypeKey">The workflow type key.</param> /// <returns>The Cadence workflow type name.</returns> private static string GetWorkflowTypeNameFromKey(string workflowTypeKey) { Covenant.Requires<ArgumentNullException>(!string.IsNullOrEmpty(workflowTypeKey), nameof(workflowTypeKey)); var separatorPos = workflowTypeKey.IndexOf(CadenceHelper.WorkflowTypeMethodSeparator); Covenant.Assert(separatorPos >= 0); return workflowTypeKey.Substring(separatorPos + CadenceHelper.WorkflowTypeMethodSeparator.Length); }
/// <inheritdoc/> public object[] FromDataArray(byte[] content, params Type[] valueTypes) { Covenant.Requires <ArgumentNullException>(valueTypes != null, nameof(valueTypes)); if (valueTypes.Length == 0) { return(Array.Empty <object>()); } Covenant.Requires <ArgumentException>(content.Length > 0, nameof(content)); var jsonText = Encoding.UTF8.GetString(content); var jsonLines = jsonText.Split(newlineArray, StringSplitOptions.RemoveEmptyEntries); if (jsonLines.Length != valueTypes.Length) { throw new ArgumentException($"Number of arguments [{jsonLines.Length}] passed does not match the method parameter count [{valueTypes.Length}]."); } var output = new object[valueTypes.Length]; for (int i = 0; i < valueTypes.Length; i++) { var type = valueTypes[i]; var line = jsonLines[i]; var jToken = JToken.Parse(line); if (type.Implements <IRoundtripData>()) { switch (jToken.Type) { case JTokenType.Null: output[i] = null; break; case JTokenType.Object: output[i] = RoundtripDataFactory.CreateFrom(type, (JObject)jToken); break; default: Covenant.Assert(false, $"Unexpected JSON token [{jToken}]."); break; } } else { output[i] = NeonHelper.JsonDeserialize(type, line); } } return(output); }
/// <summary> /// Returns the <see cref="HostingManager"/> for a specific environment. /// </summary> /// <param name="cluster">The cluster being managed.</param> /// <param name="logFolder"> /// The folder where log files are to be written, otherwise or <c>null</c> or /// empty if logging is disabled. /// </param> /// <returns> /// The <see cref="HostingManager"/> or <c>null</c> if no hosting manager /// could be located for the specified cluster environment. /// </returns> public HostingManager GetManager(ClusterProxy cluster, string logFolder = null) { Covenant.Requires <ArgumentNullException>(cluster != null, nameof(cluster)); Covenant.Assert(environmentToHostingManager != null, $"[{nameof(HostingLoader)}] is not initialized. You must call [{nameof(HostingLoader)}.{nameof(HostingLoader.Initialize)}()] first."); if (!environmentToHostingManager.TryGetValue(cluster.Definition.Hosting.Environment, out var managerType)) { return(null); } return((HostingManager)Activator.CreateInstance(managerType, cluster, logFolder)); }
/// <inheritdoc/> public HostingManager GetManagerWithNodeImageUri(ClusterProxy cluster, string nodeImageUri, string logFolder = null) { Covenant.Requires <ArgumentNullException>(cluster != null, nameof(cluster)); Covenant.Assert(environmentToHostingManager != null, $"[{nameof(HostingLoader)}] is not initialized. You must call [{nameof(HostingLoader)}.{nameof(HostingLoader.Initialize)}()] first."); if (environmentToHostingManager.TryGetValue(cluster.Definition.Hosting.Environment, out var managerType)) { return((HostingManager)Activator.CreateInstance(managerType, cluster, nodeImageUri, (string)null, logFolder)); } throw new NotImplementedException($"[{nameof(HostingEnvironment)}={cluster.Definition.Hosting.Environment}]"); }
/// <summary> /// Initializes the package. /// </summary> /// <param name="cancellationToken">A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down.</param> /// <param name="progress">A provider for progress updates.</param> /// <returns>The tracking <see cref="Task"/>.</returns> protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress <ServiceProgressData> progress) { // When initialized asynchronously, the current thread may be a background thread at this point. // Do any initialization that requires the UI thread after switching to the UI thread. await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); // Basic initialization. Instance = this; dte = (DTE2)(await GetServiceAsync(typeof(SDTE))); // Get references to necessary the IDE services. SolutionService = await RaspberryDebuggerPackage.Instance.GetServiceAsync(typeof(IVsSolution)) as IVsSolution; if (SolutionService == null) { Covenant.Assert(false, "GetService(typeof(IVsSolution)) returns NULL."); } // Initialize the log panel. var debugWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow; var generalPaneGuid = VSConstants.GUID_OutWindowDebugPane; debugWindow.GetPane(ref generalPaneGuid, out debugPane); // Intercept the debugger commands and quickly decide whether the startup project is enabled // for Raspberry remote debugging so we can invoke our custom commands instead. We'll just // let the default command implementations do their thing when we're not doing Raspberry // debugging. debugStartCommandEvent = dte.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 0x0127]; debugStartWithoutDebuggingCommandEvent = dte.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 0x0170]; debugAttachToProcessCommandEvent = dte.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 0x00d5]; debugRestartCommandEvent = dte.Events.CommandEvents["{5EFC7975-14BC-11CF-9B2B-00AA00573819}", 0x0128]; debugStartCommandEvent.BeforeExecute += DebugStartCommandEvent_BeforeExecute; debugStartWithoutDebuggingCommandEvent.BeforeExecute += DebugStartWithoutDebuggingCommandEvent_BeforeExecute; debugAttachToProcessCommandEvent.BeforeExecute += AttachToProcessCommandEvent_BeforeExecute; debugRestartCommandEvent.BeforeExecute += DebugRestartCommandEvent_BeforeExecute; // Initialize the new commands. await SettingsCommand.InitializeAsync(this); await DebugStartCommand.InitializeAsync(this); await DebugStartWithoutDebuggingCommand.InitializeAsync(this); await DebugAttachToProcessCommand.InitializeAsync(this); }
/// <summary> /// Uploads the contents of a stream to an S3 bucket. /// </summary> /// <param name="input">The input stream.</param> /// <param name="targetUri"> /// The target S3 URI. This may be either an <b>s3://BUCKET/KEY</b> or a /// <b>https://s3.REGION.amazonaws.com/BUCKET/KEY</b> URI referencing an S3 /// bucket and key. /// </param> /// <param name="gzip">Optionally indicates that the target content encoding should be set to <b>gzip</b>.</param> /// <param name="metadata"> /// <para> /// Optionally specifies HTTP metadata headers to be returned when the object /// is downloaded from S3. This formatted as as comma separated a list of /// key/value pairs like: /// </para> /// <example> /// Content-Type=text,app-version=1.0.0 /// </example> /// <note> /// <para> /// AWS supports <b>system</b> as well as <b>custom</b> headers. System headers /// include standard HTTP headers such as <b>Content-Type</b> and <b>Content-Encoding</b>. /// Custom headers are required to include the <b>x-amz-meta-</b> prefix. /// </para> /// <para> /// You don't need to specify the <b>x-amz-meta-</b> prefix for setting custom /// headers; the AWS-CLI detects custom header names and adds the prefix automatically. /// This method will strip the prefix if present before calling the AWS-CLI to ensure /// the prefix doesn't end up being duplicated. /// </para> /// </note> /// </param> /// <param name="publicReadAccess">Optionally grant the upload public read access.</param> public static void S3Upload(Stream input, string targetUri, bool gzip = false, string metadata = null, bool publicReadAccess = false) { Covenant.Assert(input != null, nameof(input)); using (var tempFile = new TempFile()) { using (var output = new FileStream(tempFile.Path, FileMode.Create, FileAccess.ReadWrite)) { input.CopyTo(output); } S3Upload(tempFile.Path, targetUri, gzip: gzip, metadata: metadata, publicReadAccess: publicReadAccess); } }
/// <summary> /// Appends exception information to the file at <see cref="DebugLogPath"/>. This is intended for /// low-level debugging when normal logging via <see cref="LogManager"/> isn't suitable. /// </summary> /// <param name="e">The exception.</param> public static void LogDebug(Exception e) { Covenant.Assert(e != null, nameof(e)); lock (debugLogSyncRoot) { var folder = Path.GetDirectoryName(DebugLogPath); LogDebug(); LogDebug($"EXCEPTION: {e.GetType().FullName}"); LogDebug(e.StackTrace); LogDebug(); LogDebug(); } }
/// <inheritdoc/> public override string GetDataDisk(LinuxSshProxy node) { Covenant.Requires <ArgumentNullException>(node != null, nameof(node)); var unpartitonedDisks = node.ListUnpartitionedDisks(); if (unpartitonedDisks.Count() == 0) { return("PRIMARY"); } Covenant.Assert(unpartitonedDisks.Count() == 1, "VMs are assumed to have no more than one attached data disk."); return(unpartitonedDisks.Single()); }
/// <summary> /// Constructor. /// </summary> /// <param name="parentEntity">The <see cref="IDynamicEntity"/> that owns this list.</param> /// <param name="context">The <see cref="IDynamicEntityContext"/> or <c>null</c>.</param> /// <param name="jArray">The underlying <see cref="jArray"/>.</param> /// <param name="items">The initial items or <c>null</c> to initialize from <paramref name="jArray"/>.</param> public EntityListWrapper(IDynamicEntity parentEntity, IDynamicEntityContext context, JArray jArray, IEnumerable <TEntity> items) { Covenant.Requires <ArgumentNullException>(parentEntity != null); Covenant.Requires <ArgumentNullException>(jArray != null); this.parentEntity = parentEntity; this.context = context; this.jArray = jArray; this.itemChangedHandler = new EventHandler <EventArgs>(OnItemChanged); this.list = new ObservableCollection <TEntity>(); if (items != null) { Covenant.Assert(jArray.Count == 0); foreach (var item in items) { Add(item); } } else { foreach (var jToken in jArray) { if (jToken.Type == JTokenType.Object) { var item = DynamicEntity.Create <TEntity>((JObject)jToken, context); item.Changed += itemChangedHandler; // We need to bubble up nested change events list.Add(item); } else { list.Add(null); // Ignore anything that's not an object. } } } // We're going to listen to our own collection changed event to // bubble them up. list.CollectionChanged += (s, a) => { CollectionChanged?.Invoke(this, a); parentEntity._OnChanged(); }; }
/// <summary> /// Reads an integer or enum value as a enum. /// </summary> /// <param name="reader">The reader.</param> /// <param name="objectType">The value type.</param> /// <param name="existingValue">The existing value.</param> /// <param name="serializer">The serializer.</param> /// <returns>The value read.</returns> /// <remarks> /// <note> /// The <paramref name="serializer"/> parameter is ignored. /// </note> /// </remarks> public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { Covenant.Assert(objectType == typeof(TEnum)); if (reader.TokenType == JsonToken.Integer) { return((TEnum)(ValueType)Convert.ToInt32(reader.Value)); } else if (reader.TokenType == JsonToken.String) { return(NeonHelper.ParseEnum <TEnum>((string)reader.Value)); } else { throw new JsonSerializationException($"Cannot convert [{reader.TokenType}] to [{typeof(TEnum).FullName}]."); } }
/// <summary> /// Throws a local exception type, including the message passed. /// </summary> /// <param name="message">The exception message.</param> public void Throw(string message) { if (MessageConstructor != null) { throw (Exception)MessageConstructor.Invoke(new object[] { message }); } else if (MessageInnerConstructor != null) { throw (Exception)MessageInnerConstructor.Invoke(new object[] { message, null }); } else if (DefaultConstructor != null) { throw (Exception)DefaultConstructor.Invoke(Array.Empty <object>()); } Covenant.Assert(false); }
/// <summary> /// Constructor. /// </summary> /// <param name="parentEntity">The <see cref="IDynamicEntity"/> that owns this list.</param> /// <param name="context">The <see cref="IDynamicEntityContext"/> or <c>null</c>.</param> /// <param name="jArray">The underlying <see cref="jArray"/>.</param> /// <param name="items">The initial items or <c>null</c> to initialize from <paramref name="jArray"/>.</param> public LinkListWrapper(IDynamicEntity parentEntity, IDynamicEntityContext context, JArray jArray, IEnumerable <TEntity> items) { Covenant.Requires <ArgumentNullException>(parentEntity != null); Covenant.Requires <ArgumentNullException>(jArray != null); this.parentEntity = parentEntity; this.context = context; this.jArray = jArray; this.list = new ObservableCollection <LinkState>(); if (items != null) { Covenant.Assert(jArray.Count == 0); foreach (var item in items) { Add(item); } } else { foreach (var token in jArray) { list.Add(new LinkState() { Link = GetLink(token) }); } } // We're going to listen to our own collection changed event to // bubble them up. list.CollectionChanged += (s, a) => { if (!notifyDisabled) { CollectionChanged?.Invoke(this, a); parentEntity._OnChanged(); } }; }
/// <inheritdoc/> public void Dispose() { if (!IsDisposed) { try { Dispose(true); } catch { // Ignoring any exceptions. } IsDisposed = true; RefCount--; Covenant.Assert(RefCount >= 0, "Reference count underflow."); } }