Пример #1
0
        /// <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;
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        /// <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());
            }
        }
Пример #5
0
        /// <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 })));
        }
Пример #6
0
        /// <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 }));
        }
Пример #7
0
        /// <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"));
        }
Пример #8
0
        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);
            });
        }
Пример #9
0
        //---------------------------------------------------------------------
        // 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.");
        }
Пример #10
0
        /// <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}");
        }
Пример #11
0
        /// <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();
            }
        }
Пример #12
0
        //---------------------------------------------------------------------
        // 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);
            }
        }
Пример #13
0
        /// <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);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        /// <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();
        }
Пример #16
0
        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);
        }
Пример #17
0
        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);
        }
Пример #18
0
        /// <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);
        }
Пример #19
0
        /// <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);
        }
Пример #20
0
        /// <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));
        }
Пример #21
0
        /// <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}]");
        }
Пример #22
0
        /// <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);
        }
Пример #23
0
        /// <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);
            }
        }
Пример #24
0
        /// <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();
            }
        }
Пример #25
0
        /// <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());
        }
Пример #26
0
        /// <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();
            };
        }
Пример #27
0
        /// <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}].");
            }
        }
Пример #28
0
            /// <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);
            }
Пример #29
0
        /// <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();
                }
            };
        }
Пример #30
0
        /// <inheritdoc/>
        public void Dispose()
        {
            if (!IsDisposed)
            {
                try
                {
                    Dispose(true);
                }
                catch
                {
                    // Ignoring any exceptions.
                }

                IsDisposed = true;
                RefCount--;

                Covenant.Assert(RefCount >= 0, "Reference count underflow.");
            }
        }