Exemple #1
0
        // Build image dependency tree
        public DockerImageNode BuildImageTree(IList <ImageInspectResponse> images,
                                              IList <ContainerListResponse> containerListResponses,
                                              IList <ContainerInspectResponse> containerInspectResponses,
                                              ImageInspectResponse image)
        {
            var containerList = containerListResponses.Where(r => string.Equals(r.ImageID, image.ID)).ToList();
            IList <ContainerInspectResponse> containers = new List <ContainerInspectResponse>();

            foreach (var container in containerList)
            {
                containers.Add(containerInspectResponses.Where(c => string.Equals(c.ID, container.ID)).FirstOrDefault());
            }

            var dockerImageNode = new DockerImageNode()
            {
                InspectResponse = image,
                Children        = new List <DockerImageNode>(),
                Containers      = containers,
            };

            var children = images.Where(i => string.Equals(i.Parent, image.ID)).ToList();

            foreach (var child in children)
            {
                var childNode = BuildImageTree(images, containerListResponses, containerInspectResponses, child);
                childNode.Parent = dockerImageNode;
                dockerImageNode.Children.Add(childNode);
            }

            return(dockerImageNode);
        }
        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="imageID"></param>
        /// <returns></returns>
        private async Task <string> GetImageVersionAsync(string imageID)
        {
            if (this._imageVersionMap.TryGetValue(imageID, out string versionString))
            {
                return(versionString);
            }

            ImageInspectResponse imageInfo = await this._dockerClient.Images.InspectImageAsync(imageID);

            string version = imageInfo.Config.Env.First(env => env.StartsWith("VERSION")).Split("=")[1];

            if (!this._imageVersionMap.ContainsKey(imageID))
            {
                this._imageVersionMap.TryAdd(imageID, version);
            }
            return(version);
        }
        public PlcOpcUaServer()
        {
            Uri dockerUri = null;

            try
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    dockerUri = new Uri("tcp://localhost:2375");
                }
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    dockerUri = new Uri("unix:///var/run/docker.sock");
                }
                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    dockerUri = new Uri("not supported");
                }
                _dockerClient = new DockerClientConfiguration(dockerUri).CreateClient();
            }
            catch
            {
                throw new Exception($"Please adjust your docker deamon endpoint '{dockerUri}' for your configuration.");
            }

            // cleanup all PLC containers
            CleanupContainerAsync().Wait();

            // pull the latest image
            ImagesCreateParameters createParameters = new ImagesCreateParameters();

            createParameters.FromImage = _plcImage;
            createParameters.Tag       = "latest";
            try
            {
                _dockerClient.Images.CreateImageAsync(createParameters, new AuthConfig(), new Progress <JSONMessage>()).Wait();
            }
            catch (Exception)
            {
                throw new Exception($"Cannot pull image '{_plcImage}");
            }

            ImageInspectResponse imageInspectResponse = _dockerClient.Images.InspectImageAsync(_plcImage).Result;

            // create a new container
            CreateContainerParameters containerParams = new CreateContainerParameters();

            containerParams.Image    = _plcImage;
            containerParams.Hostname = "opcplc";
            containerParams.Name     = "opcplc";
            containerParams.Cmd      = new string[]
            {
                "--aa",
                "--pn", $"{_plcPort}"
            };
            // workaround .NET2.1 issue for private key access
            if (imageInspectResponse.Os.Equals("windows", StringComparison.InvariantCultureIgnoreCase))
            {
                containerParams.Cmd.Add("--at");
                containerParams.Cmd.Add("X509Store");
            }
            containerParams.ExposedPorts = new Dictionary <string, EmptyStruct>();
            containerParams.ExposedPorts.Add(new KeyValuePair <string, EmptyStruct>($"{_plcPort}/tcp", new EmptyStruct()));
            containerParams.HostConfig = new HostConfig();
            PortBinding portBinding = new PortBinding();

            portBinding.HostPort = _plcPort;
            portBinding.HostIP   = null;
            List <PortBinding> portBindings = new List <PortBinding>();

            portBindings.Add(portBinding);
            containerParams.HostConfig.PortBindings = new Dictionary <string, IList <PortBinding> >();
            containerParams.HostConfig.PortBindings.Add($"{_plcPort}/tcp", portBindings);
            CreateContainerResponse response = null;

            try
            {
                response        = _dockerClient.Containers.CreateContainerAsync(containerParams).Result;
                _plcContainerId = response.ID;
            }
            catch (Exception)
            {
                throw;
            }

            try
            {
                _dockerClient.Containers.StartContainerAsync(_plcContainerId, new ContainerStartParameters()).Wait();
            }
            catch (Exception)
            {
                throw;
            }
        }
Exemple #4
0
        /// <summary>
        /// Pull and verify a new docker image and update the docker-compose file
        /// </summary>
        /// <param name="act">The action containing the new chainspec url and checksum</param>
        /// <param name="expectedState">The expected state that the action was derived from</param>
        /// <exception cref="UpdateVerificationException">
        /// Thrown when update is not able to be verified. Reasons:
        /// <list type="bullet">
        /// <item>The image is not able to be pulled</item>
        /// <item>Checksum of the downloaded content doesn't match</item>
        /// </list>
        /// </exception>
        public void UpdateDocker(StateChangeAction act, NodeState expectedState)
        {
            if (act.Mode != UpdateMode.Docker)
            {
                throw new UpdateVerificationException("Action with wrong update mode passed");
            }

            if (string.IsNullOrWhiteSpace(act.Payload) || string.IsNullOrWhiteSpace(act.PayloadHash))
            {
                throw new UpdateVerificationException("Payload or hash are empty");
            }

            if (act.Payload != expectedState.DockerImage || act.PayloadHash != expectedState.DockerChecksum)
            {
                throw new UpdateVerificationException("Action vs. node state mismatch");
            }


            Log($"Pulling new parity image [{act.Payload}] ..");

            // Prepare progress logging stub
            Progress <JSONMessage> progress = new Progress <JSONMessage>();

            try
            {
                // pull docker image
                _dcc.PullImage(new ImagesCreateParameters
                {
                    FromImage = act.Payload.Split(':')[0],
                    Tag       = act.Payload.Split(':')[1]
                }, null, progress);
            }
            catch (Exception e)
            {
                throw new UpdateVerificationException("Unable to pull new image.", e);
            }

            // verify docker image id against expected hash
            ImageInspectResponse inspectResult = _dcc.InspectImage(act.Payload);
            string dockerHash = inspectResult.ID.Replace("sha256:", string.Empty);

            if (dockerHash != act.PayloadHash)
            {
                Log("Image hashes don't match. Cancel update.");
                _dcc.DeleteImage(act.Payload);
                Log("Pulled imaged removed.");
                throw new UpdateVerificationException("Docker image hashes don't match.");
            }

            // Image is legit. update docker compose
            Log("Image valid. Updating stack.");

            NodeState stateBeforeUpgrade = _configProvider.ReadCurrentState();

            // Write new config file and try to upgrade
            _configProvider.WriteNewState(expectedState);

            // restart/upgrade stack
            try
            {
                _dcc.ApplyChangesToStack(_stackPath, false);
            }
            catch
            {
                // Stack upgrade didn't work - rollback to last config file and rethrow
                _configProvider.WriteNewState(stateBeforeUpgrade);
                throw;
            }
        }
        public async Task MonitorEventsFiltered_Succeeds()
        {
            string newTag = $"MonitorTests-{Guid.NewGuid().ToString().Substring(1, 10)}";
            string newImageRespositoryName = Guid.NewGuid().ToString();

            await _client.Images.TagImageAsync(
                $"{_repositoryName}:{_tag}",
                new ImageTagParameters
            {
                RepositoryName = newImageRespositoryName,
                Tag            = newTag
            },
                _cts.Token
                );

            ImageInspectResponse image = await _client.Images.InspectImageAsync(
                $"{newImageRespositoryName}:{newTag}",
                _cts.Token
                );

            var progressCalledCounter = 0;

            var eventsParams = new ContainerEventsParameters()
            {
                Filters = new Dictionary <string, IDictionary <string, bool> >()
                {
                    {
                        "event", new Dictionary <string, bool>()
                        {
                            {
                                "tag", true
                            },
                            {
                                "untag", true
                            }
                        }
                    },
                    {
                        "type", new Dictionary <string, bool>()
                        {
                            {
                                "image", true
                            }
                        }
                    },
                    {
                        "image", new Dictionary <string, bool>()
                        {
                            {
                                image.ID, true
                            }
                        }
                    }
                }
            };

            var progress = new Progress <Message>((m) =>
            {
                progressCalledCounter++;
                Assert.True(m.Status == "tag" || m.Status == "untag");
                _output.WriteLine($"MonitorEventsFiltered_Succeeds: Message received: {m.Action} - {m.Status} {m.From} - {m.Type}");
            });

            using var cts = CancellationTokenSource.CreateLinkedTokenSource(_cts.Token);
            var task = Task.Run(() => _client.System.MonitorEventsAsync(eventsParams, progress, cts.Token));

            await _client.Images.CreateImageAsync(new ImagesCreateParameters { FromImage = $"{_repositoryName}:{_tag}" }, null, new Progress <JSONMessage>());

            await _client.Images.TagImageAsync($"{_repositoryName}:{_tag}", new ImageTagParameters { RepositoryName = _repositoryName, Tag = newTag });

            await _client.Images.DeleteImageAsync($"{_repositoryName}:{newTag}", new ImageDeleteParameters());

            var createContainerResponse = await _client.Containers.CreateContainerAsync(new CreateContainerParameters { Image = $"{_repositoryName}:{_tag}" });

            await _client.Containers.RemoveContainerAsync(createContainerResponse.ID, new ContainerRemoveParameters(), cts.Token);

            await Task.Delay(TimeSpan.FromSeconds(1));

            cts.Cancel();

            await Assert.ThrowsAsync <TaskCanceledException>(() => task);

            Assert.Equal(2, progressCalledCounter);
            Assert.True(task.IsCanceled);
        }