private async Task TransformProjectToContainer(Model.Application application, Model.Service service, ProjectRunInfo project)
        {
            var serviceDescription = service.Description;
            var serviceName        = serviceDescription.Name;

            service.Status.ProjectFilePath = project.ProjectFile.FullName;
            var targetFramework = project.TargetFramework;

            // Sometimes building can fail because of file locking (like files being open in VS)
            _logger.LogInformation("Publishing project {ProjectFile}", service.Status.ProjectFilePath);

            var publishCommand = $"publish \"{service.Status.ProjectFilePath}\" --framework {targetFramework} /nologo";

            service.Logs.OnNext($"dotnet {publishCommand}");

            var buildResult = await ProcessUtil.RunAsync("dotnet", publishCommand, throwOnError : false);

            service.Logs.OnNext(buildResult.StandardOutput);

            if (buildResult.ExitCode != 0)
            {
                _logger.LogInformation("Publishing {ProjectFile} failed with exit code {ExitCode}: \r\n" + buildResult.StandardOutput, service.Status.ProjectFilePath, buildResult.ExitCode);

                // Null out the RunInfo so that
                serviceDescription.RunInfo = null;
                return;
            }

            // We transform the project information into the following docker command:
            // docker run -w /app -v {publishDir}:/app -it {image} dotnet {outputfile}.dll

            // We swap the slashes since we're going to run on linux
            var containerImage = DetermineContainerImage(targetFramework);
            var outputFileName = project.AssemblyName + ".dll";
            var dockerRunInfo  = new DockerRunInfo(containerImage, $"dotnet {outputFileName} {project.Args}")
            {
                WorkingDirectory = "/app"
            };

            dockerRunInfo.VolumeMappings[project.PublishOutputPath] = "/app";

            // Make volume mapping works when running as a container
            foreach (var mapping in project.VolumeMappings)
            {
                dockerRunInfo.VolumeMappings[mapping.Key] = mapping.Value;
            }

            // Change the project into a container info
            serviceDescription.RunInfo = dockerRunInfo;
        }
        private async Task TransformProjectToContainer(Model.Application application, Model.Service service, ProjectRunInfo project)
        {
            var serviceDescription = service.Description;
            var serviceName        = serviceDescription.Name;

            var expandedProject = Environment.ExpandEnvironmentVariables(project.Project);
            var fullProjectPath = Path.GetFullPath(Path.Combine(application.ContextDirectory, expandedProject));

            service.Status.ProjectFilePath = fullProjectPath;

            // Sometimes building can fail because of file locking (like files being open in VS)
            _logger.LogInformation("Publishing project {ProjectFile}", service.Status.ProjectFilePath);

            service.Logs.OnNext($"dotnet publish \"{service.Status.ProjectFilePath}\" /nologo");

            var buildResult = await ProcessUtil.RunAsync("dotnet", $"publish \"{service.Status.ProjectFilePath}\" /nologo",
                                                         outputDataReceived : data => service.Logs.OnNext(data),
                                                         throwOnError : false);

            if (buildResult.ExitCode != 0)
            {
                _logger.LogInformation("Publishing {ProjectFile} failed with exit code {ExitCode}: " + buildResult.StandardOutput + buildResult.StandardError, service.Status.ProjectFilePath, buildResult.ExitCode);
                return;
            }

            var targetFramework = GetTargetFramework(service.Status.ProjectFilePath);

            // We transform the project information into the following docker command:
            // docker run -w /app -v {projectDir}:/app -it {image} dotnet /app/bin/Debug/{tfm}/publish/{outputfile}.dll
            var containerImage = DetermineContainerImage(targetFramework);
            var outputFileName = Path.GetFileNameWithoutExtension(service.Status.ProjectFilePath) + ".dll";
            var dockerRunInfo  = new DockerRunInfo(containerImage, $"dotnet /app/bin/Debug/{targetFramework}/publish/{outputFileName} {project.Args}")
            {
                WorkingDirectory = "/app"
            };

            dockerRunInfo.VolumeMappings[Path.GetDirectoryName(service.Status.ProjectFilePath) !] = "/app";
Exemplo n.º 3
0
        public void PopulateEnvironment(Service service, Action <string, string> set, string defaultHost = "localhost")
        {
            if (service.Description.Configuration != null)
            {
                // Inject normal configuration
                foreach (var pair in service.Description.Configuration)
                {
                    if (pair.Value is object)
                    {
                        set(pair.Name, pair.Value);
                    }
                    else if (pair.Source is object)
                    {
                        set(pair.Name, GetValueFromBinding(pair.Source));
                    }
                }
            }

            string GetValueFromBinding(EnvironmentVariableSource source)
            {
                if (!Services.TryGetValue(source.Service, out var service))
                {
                    throw new InvalidOperationException($"Could not find service '{source.Service}'.");
                }

                var binding = service.Description.Bindings.Where(b => b.Name == source.Binding).FirstOrDefault();

                if (binding == null)
                {
                    throw new InvalidOperationException($"Could not find binding '{source.Binding}' for service '{source.Service}'.");
                }

                // TODO finish
                if (source.Kind == EnvironmentVariableSource.SourceKind.Port && binding.Port != null)
                {
                    return(binding.Port.Value.ToString());
                }
                else if (source.Kind == EnvironmentVariableSource.SourceKind.Host)
                {
                    return(binding.Host ?? defaultHost);
                }
                else if (source.Kind == EnvironmentVariableSource.SourceKind.Url)
                {
                    return($"{binding.Protocol ?? "http"}://{binding.Host ?? defaultHost}" + (binding.Port.HasValue ? (":" + binding.Port) : string.Empty));
                }
                else if (source.Kind == EnvironmentVariableSource.SourceKind.ConnectionString && binding.ConnectionString != null)
                {
                    return(binding.ConnectionString);
                }

                throw new InvalidOperationException($"Unable to resolve the desired value '{source.Kind}' from binding '{source.Binding}' for service '{source.Service}'.");
            }

            void SetBinding(ServiceDescription targetService, ServiceBinding b)
            {
                var serviceName = targetService.Name.ToUpper();
                var configName  = "";
                var envName     = "";

                if (string.IsNullOrEmpty(b.Name))
                {
                    configName = serviceName;
                    envName    = serviceName;
                }
                else
                {
                    configName = $"{serviceName.ToUpper()}__{b.Name.ToUpper()}";
                    envName    = $"{serviceName.ToUpper()}_{b.Name.ToUpper()}";
                }

                if (!string.IsNullOrEmpty(b.ConnectionString))
                {
                    // Special case for connection strings
                    set($"CONNECTIONSTRING__{configName}", b.ConnectionString);
                }

                if (!string.IsNullOrEmpty(b.Protocol))
                {
                    // IConfiguration specific (double underscore ends up telling the configuration provider to use it as a separator)
                    set($"SERVICE__{configName}__PROTOCOL", b.Protocol);
                    set($"{envName}_SERVICE_PROTOCOL", b.Protocol);
                }

                if (b.Port != null)
                {
                    var port = (service.Description.RunInfo is DockerRunInfo &&
                                targetService.RunInfo is DockerRunInfo) ? b.ContainerPort ?? b.Port.Value : b.Port.Value;

                    set($"SERVICE__{configName}__PORT", port.ToString());
                    set($"{envName}_SERVICE_PORT", port.ToString());
                }

                // Use the container name as the host name if there's a single replica (current limitation)
                var host = b.Host ?? (service.Description.RunInfo is DockerRunInfo &&
                                      targetService.RunInfo is DockerRunInfo ? targetService.Name : defaultHost);

                set($"SERVICE__{configName}__HOST", host);
                set($"{envName}_SERVICE_HOST", host);
            }

            // Inject dependency information
            foreach (var s in Services.Values)
            {
                foreach (var b in s.Description.Bindings)
                {
                    SetBinding(s.Description, b);
                }
            }
        }
Exemplo n.º 4
0
        private static V1Service CreateServiceJson(Model.Service service)
        {
            var description = service.Description;
            var bindings    = description.Bindings;

            var v1bindingList = new List <V1ServiceBinding>();

            foreach (var binding in bindings)
            {
                v1bindingList.Add(new V1ServiceBinding()
                {
                    Name             = binding.Name,
                    ConnectionString = binding.ConnectionString,
                    AutoAssignPort   = binding.AutoAssignPort,
                    Port             = binding.Port,
                    ContainerPort    = binding.ContainerPort,
                    Host             = binding.Host,
                    Protocol         = binding.Protocol
                });
            }

            var v1ConfigurationSourceList = new List <V1ConfigurationSource>();

            foreach (var configSource in description.Configuration)
            {
                v1ConfigurationSourceList.Add(new V1ConfigurationSource()
                {
                    Name  = configSource.Name,
                    Value = configSource.Value
                });
            }

            var v1RunInfo = new V1RunInfo();

            if (description.RunInfo is DockerRunInfo dockerRunInfo)
            {
                v1RunInfo.Type           = V1RunInfoType.Docker;
                v1RunInfo.Image          = dockerRunInfo.Image;
                v1RunInfo.VolumeMappings = dockerRunInfo.VolumeMappings.Select(v => new V1DockerVolume
                {
                    Name   = v.Name,
                    Source = v.Source,
                    Target = v.Target
                }).ToList();

                v1RunInfo.WorkingDirectory = dockerRunInfo.WorkingDirectory;
                v1RunInfo.Args             = dockerRunInfo.Args;
            }
            else if (description.RunInfo is ExecutableRunInfo executableRunInfo)
            {
                v1RunInfo.Type             = V1RunInfoType.Executable;
                v1RunInfo.Args             = executableRunInfo.Args;
                v1RunInfo.Executable       = executableRunInfo.Executable;
                v1RunInfo.WorkingDirectory = executableRunInfo.WorkingDirectory;
            }
            else if (description.RunInfo is ProjectRunInfo projectRunInfo)
            {
                v1RunInfo.Type    = V1RunInfoType.Project;
                v1RunInfo.Args    = projectRunInfo.Args;
                v1RunInfo.Build   = projectRunInfo.Build;
                v1RunInfo.Project = projectRunInfo.ProjectFile.FullName;
            }

            var v1ServiceDescription = new V1ServiceDescription()
            {
                Bindings      = v1bindingList,
                Configuration = v1ConfigurationSourceList,
                Name          = description.Name,
                Replicas      = description.Replicas,
                RunInfo       = v1RunInfo
            };

            var replicateDictionary = new Dictionary <string, V1ReplicaStatus>();

            foreach (var replica in service.Replicas)
            {
                var replicaStatus = new V1ReplicaStatus()
                {
                    Name        = replica.Value.Name,
                    Ports       = replica.Value.Ports,
                    Environment = replica.Value.Environment
                };

                replicateDictionary[replica.Key] = replicaStatus;

                if (replica.Value is ProcessStatus processStatus)
                {
                    replicaStatus.Pid      = processStatus.Pid;
                    replicaStatus.ExitCode = processStatus.ExitCode;
                }
                else if (replica.Value is DockerStatus dockerStatus)
                {
                    replicaStatus.DockerCommand = dockerStatus.DockerCommand;
                    replicaStatus.ContainerId   = dockerStatus.ContainerId;
                }
            }

            var v1Status = new V1ServiceStatus()
            {
                ProjectFilePath  = service.Status.ProjectFilePath,
                ExecutablePath   = service.Status.ExecutablePath,
                Args             = service.Status.Args,
                WorkingDirectory = service.Status.WorkingDirectory,
            };

            var serviceJson = new V1Service()
            {
                ServiceType = service.ServiceType,
                Status      = v1Status,
                Description = v1ServiceDescription,
                Replicas    = replicateDictionary,
                Restarts    = service.Restarts
            };

            return(serviceJson);
        }
Exemplo n.º 5
0
        private static V1Service CreateServiceJson(Model.Service service)
        {
            var description = service.Description;
            var bindings    = description.Bindings;

            var v1bindingList = new List <V1ServiceBinding>();

            foreach (var binding in bindings)
            {
                v1bindingList.Add(new V1ServiceBinding()
                {
                    Name             = binding.Name,
                    ConnectionString = binding.ConnectionString,
                    AutoAssignPort   = binding.AutoAssignPort,
                    Port             = binding.Port,
                    InternalPort     = binding.InternalPort,
                    Host             = binding.Host,
                    Protocol         = binding.Protocol
                });
            }

            var v1ConfigurationSourceList = new List <V1ConfigurationSource>();

            foreach (var configSource in description.Configuration)
            {
                v1ConfigurationSourceList.Add(new V1ConfigurationSource()
                {
                    Name  = configSource.Name,
                    Value = configSource.Value
                });
            }

            var v1RunInfo = new V1RunInfo();

            if (description.RunInfo is DockerRunInfo dockerRunInfo)
            {
                v1RunInfo.Type             = V1RunInfoType.Docker;
                v1RunInfo.Image            = dockerRunInfo.Image;
                v1RunInfo.VolumeMappings   = dockerRunInfo.VolumeMappings;
                v1RunInfo.WorkingDirectory = dockerRunInfo.WorkingDirectory;
                v1RunInfo.Args             = dockerRunInfo.Args;
            }
            else if (description.RunInfo is ExecutableRunInfo executableRunInfo)
            {
                v1RunInfo.Type             = V1RunInfoType.Executable;
                v1RunInfo.Args             = executableRunInfo.Args;
                v1RunInfo.Executable       = executableRunInfo.Executable;
                v1RunInfo.WorkingDirectory = executableRunInfo.WorkingDirectory;
            }
            else if (description.RunInfo is ProjectRunInfo projectRunInfo)
            {
                v1RunInfo.Type    = V1RunInfoType.Project;
                v1RunInfo.Args    = projectRunInfo.Args;
                v1RunInfo.Build   = projectRunInfo.Build;
                v1RunInfo.Project = projectRunInfo.Project;
            }

            var v1ServiceDescription = new V1ServiceDescription()
            {
                Bindings      = v1bindingList,
                Configuration = v1ConfigurationSourceList,
                Name          = description.Name,
                Replicas      = description.Replicas,
                RunInfo       = v1RunInfo
            };

            var replicateDictionary = new Dictionary <string, V1ReplicaStatus>();

            foreach (var replica in service.Replicas)
            {
                replicateDictionary[replica.Key] = new V1ReplicaStatus()
                {
                    Name  = replica.Value.Name,
                    Ports = replica.Value.Ports
                };
            }

            var v1Status = new V1ServiceStatus()
            {
                ProjectFilePath  = service.Status.ProjectFilePath,
                ExecutablePath   = service.Status.ExecutablePath,
                Args             = service.Status.Args,
                WorkingDirectory = service.Status.WorkingDirectory,
            };

            var serviceJson = new V1Service()
            {
                ServiceType = service.ServiceType,
                Status      = v1Status,
                Description = v1ServiceDescription,
                Replicas    = replicateDictionary,
                Restarts    = service.Restarts
            };

            return(serviceJson);
        }