public ServiceResources(DeploymentV1 deployment, StatefulSetV1 statefulSet, ServiceV1 service, IngressV1Beta1 ingress, SecretV1 secret)
 {
     Deployment  = deployment;
     StatefulSet = statefulSet;
     Service     = service;
     Ingress     = ingress;
     Secret      = secret;
 }
        /// <summary>
        ///     Request creation of a <see cref="StatefulSetV1"/>.
        /// </summary>
        /// <param name="newStatefulSet">
        ///     A <see cref="StatefulSetV1"/> representing the StatefulSet to create.
        /// </param>
        /// <param name="cancellationToken">
        ///     An optional <see cref="CancellationToken"/> that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <see cref="StatefulSetV1"/> representing the current state for the newly-created StatefulSet.
        /// </returns>
        public async Task <StatefulSetV1> Create(StatefulSetV1 newStatefulSet, CancellationToken cancellationToken = default)
        {
            if (newStatefulSet == null)
            {
                throw new ArgumentNullException(nameof(newStatefulSet));
            }

            return(await Http
                   .PostAsJsonAsync(
                       Requests.Collection.WithTemplateParameters(new
            {
                Namespace = newStatefulSet?.Metadata?.Namespace ?? KubeClient.DefaultNamespace
            }),
                       postBody : newStatefulSet,
                       cancellationToken : cancellationToken
                       )
                   .ReadContentAsObjectV1Async <StatefulSetV1>("create v1/StatefulSet resource"));
        }
        private async Task <ServiceResources> DeployService(DeployCommand.Types.Service command, string kubeNamespace)
        {
            DeploymentV1  deployment  = null;
            StatefulSetV1 statefulSet = null;

            var secret = await CreateSecret();

            if (string.IsNullOrWhiteSpace(command.PersistentStoragePath))
            {
                deployment = await CreateDeployment();
            }
            else
            {
                statefulSet = await CreateStatefulSet();
            }

            var service = await CreateService();

            var ingress = await CreateServiceIngress();

            return(new ServiceResources(deployment, statefulSet, service, ingress, secret));

            async Task <SecretV1> CreateSecret()
            {
                if (!command.Secrets.Any())
                {
                    return(null);
                }

                var existingSecret = await kubeApiClient.SecretsV1().Get(command.Name, kubeNamespace);

                var secretResource = new SecretV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name      = command.Name,
                        Namespace = kubeNamespace,
                    },
                    Type = "Opaque",
                };

                if (existingSecret != null)
                {
                    foreach (var existingData in existingSecret.Data)
                    {
                        secretResource.Data[existingData.Key] = existingData.Value;
                    }
                }

                foreach (var secretCommand in command.Secrets.Where(s => s.Value != null))
                {
                    secretResource.Data[secretCommand.Name] = Convert.ToBase64String(Encoding.UTF8.GetBytes(secretCommand.Value));
                }

                foreach (var existingSecretNames in secretResource.Data.Keys)
                {
                    if (command.Secrets.All(secretCommand => secretCommand.Name != existingSecretNames))
                    {
                        secretResource.Data.Remove(existingSecretNames);
                    }
                }

                return(await kubeApiClient.Dynamic().Apply(secretResource, fieldManager: "clud", force: true));
            }

            async Task <DeploymentV1> CreateDeployment()
            {
                var deployment = new DeploymentV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name      = command.Name,
                        Namespace = kubeNamespace,
                    },
                    Spec = new DeploymentSpecV1
                    {
                        Selector = new LabelSelectorV1
                        {
                            MatchLabels = { { KubeNaming.AppLabelKey, command.Name } },
                        },
                        Replicas = command.Replicas,
                        Template = new PodTemplateSpecV1
                        {
                            Metadata = new ObjectMetaV1
                            {
                                Name      = command.Name,
                                Namespace = kubeNamespace,
                                Labels    = { { KubeNaming.AppLabelKey, command.Name } }
                            },
                            Spec = new PodSpecV1
                            {
                                Containers =
                                {
                                    new ContainerV1
                                    {
                                        Name  = command.Name,
                                        Image = DockerImageName(),
                                    }
                                },
                            },
                        }
                    }
                };

                AddEnvironmentVariables(deployment.Spec.Template.Spec.Containers.Single().Env);

                return(await kubeApiClient.Dynamic().Apply(deployment, fieldManager: "clud", force: true));
            }

            async Task <StatefulSetV1> CreateStatefulSet()
            {
                var statefulSet = new StatefulSetV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name      = command.Name,
                        Namespace = kubeNamespace,
                    },
                    Spec = new StatefulSetSpecV1
                    {
                        Selector = new LabelSelectorV1
                        {
                            MatchLabels = { { KubeNaming.AppLabelKey, command.Name } },
                        },
                        Template = new PodTemplateSpecV1
                        {
                            Metadata = new ObjectMetaV1
                            {
                                Name      = command.Name,
                                Namespace = kubeNamespace,
                                Labels    = { { KubeNaming.AppLabelKey, command.Name } }
                            },
                            Spec = new PodSpecV1
                            {
                                Containers =
                                {
                                    new ContainerV1
                                    {
                                        Name         = command.Name,
                                        Image        = DockerImageName(),
                                        VolumeMounts =   { new VolumeMountV1
                                                           {
                                                               Name      = command.Name,
                                                               MountPath = command.PersistentStoragePath,
                                                           } }
                                    },
                                },
                            },
                        },
                        VolumeClaimTemplates =
                        {
                            new PersistentVolumeClaimV1
                            {
                                Metadata = new ObjectMetaV1
                                {
                                    Name      = command.Name,
                                    Namespace = kubeNamespace,
                                },
                                Spec = new PersistentVolumeClaimSpecV1
                                {
                                    AccessModes ={ "ReadWriteOnce"                   },
                                    Resources   = new ResourceRequirementsV1
                                    {
                                        Requests ={ { "storage", "100Mi"              } },
                                    }
                                }
                            }
                        }
                    }
                };

                AddEnvironmentVariables(statefulSet.Spec.Template.Spec.Containers.Single().Env);

                return(await kubeApiClient.Dynamic().Apply(statefulSet, fieldManager: "clud", force: true));
            }

            string DockerImageName()
            {
                return(command.IsPublicDockerImage
                    ? command.DockerImage
                    : $"{KubeNaming.DockerRegistryLocation}/{command.DockerImage}");
            }

            void AddEnvironmentVariables(List <EnvVarV1> envVarV1s)
            {
                envVarV1s.AddRange(command.EnvironmentVariables.Select(env => new EnvVarV1
                {
                    Name  = env.Name,
                    Value = env.Value
                }));

                envVarV1s.AddRange(command.Secrets.Select(secret => new EnvVarV1
                {
                    Name      = secret.Name,
                    ValueFrom = new EnvVarSourceV1
                    {
                        SecretKeyRef = new SecretKeySelectorV1
                        {
                            Name     = command.Name,
                            Key      = secret.Name,
                            Optional = false,
                        }
                    }
                }));
            }

            async Task <ServiceV1> CreateService()
            {
                var service = new ServiceV1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name      = command.Name,
                        Namespace = kubeNamespace,
                    },
                    Spec = new ServiceSpecV1
                    {
                        Selector = { { KubeNaming.AppLabelKey, command.Name } },
                    },
                };

                if (command.HttpPort != null)
                {
                    service.Spec.Ports.Add(new ServicePortV1
                    {
                        Name     = KubeNaming.HttpPortName,
                        Protocol = "TCP",
                        Port     = command.HttpPort.Value
                    });
                }

                service.Spec.Ports.AddRange(command.TcpPorts.Select(port => new ServicePortV1
                {
                    Name     = $"tcp-{port}",
                    Protocol = "TCP",
                    Port     = port,
                }));

                service.Spec.Ports.AddRange(command.UdpPorts.Select(port => new ServicePortV1
                {
                    Name     = $"udp-{port}",
                    Protocol = "UDP",
                    Port     = port,
                }));

                return(await kubeApiClient.Dynamic().Apply(service, fieldManager: "clud", force: true));
            }

            async Task <IngressV1Beta1> CreateServiceIngress()
            {
                if (command.HttpPort == null)
                {
                    return(null);
                }

                var ingress = new IngressV1Beta1
                {
                    Metadata = new ObjectMetaV1
                    {
                        Name      = command.Name,
                        Namespace = kubeNamespace,
                    },
                    Spec = new IngressSpecV1Beta1
                    {
                        Rules =
                        {
                            new IngressRuleV1Beta1
                            {
                                Host = $"{command.Name}-{kubeNamespace}.{cludOptions.BaseHostname}",
                                Http = new HTTPIngressRuleValueV1Beta1
                                {
                                    Paths =
                                    {
                                        new HTTPIngressPathV1Beta1
                                        {
                                            Path    = "/",
                                            Backend = new IngressBackendV1Beta1
                                            {
                                                ServiceName = service.Metadata.Name,
                                                ServicePort = KubeNaming.HttpPortName,
                                            }
                                        }
                                    }
                                }
                            }
                        },
                    },
                };

                return(await kubeApiClient.Dynamic().Apply(ingress, fieldManager: "clud", force: true));
            }
        }