public static bool ImageEquals(this V1PodTemplateSpec self, V1PodTemplateSpec other) { if (ReferenceEquals(null, other)) { return(false); } if (ReferenceEquals(self, other)) { return(true); } return(self.Spec.ImageEquals(other.Spec)); }
/// <summary> /// Creates a new <see cref="V1Deployment"/> for the specified <see cref="Resources.Channel"/> /// </summary> /// <param name="channel">The <see cref="Resources.Channel"/> to deploy</param> /// <returns>A new awaitable <see cref="Task"/></returns> protected virtual async Task CreateChannelDeploymentAsync(Resources.Channel channel) { V1Deployment deployment; try { this.Logger.LogInformation("Creating a new deployment for the channel with name '{resourceName}'...", channel.Name()); V1PodSpec podSpec = new V1PodSpec(); V1Container container = channel.Spec.Container; container.Env.Add(new V1EnvVar("SINK", $"http://gateway.{channel.Namespace()}.svc.cluster.local/events/")); podSpec.Containers = new List <V1Container>() { container }; V1ObjectMeta podMetadata = new V1ObjectMeta(); podMetadata.Annotations = new Dictionary <string, string>() { { "sidecar.istio.io/inject", "true" } }; V1PodTemplateSpec podTemplateSpec = new V1PodTemplateSpec(podMetadata, podSpec); podTemplateSpec.Metadata.Labels = new Dictionary <string, string>() { { "app", channel.Name() }, { "version", "1.0" } }; V1DeploymentSpec deploymentSpec = new V1DeploymentSpec(new V1LabelSelector(), podTemplateSpec); deploymentSpec.Selector.MatchLabels = new Dictionary <string, string>() { { "app", channel.Name() }, { "version", "1.0" } }; V1ObjectMeta deploymentMetadata = new V1ObjectMeta(namespaceProperty: channel.Namespace(), name: channel.Name()); deploymentMetadata.Labels = new Dictionary <string, string>() { { "type", EventingDefaults.Labels.Channel } }; deploymentMetadata.Name = channel.Name(); deploymentMetadata.NamespaceProperty = channel.Namespace(); deployment = new V1Deployment(KubernetesDefaults.ApiVersions.AppsV1, KubernetesDefaults.Kinds.Deployment, deploymentMetadata, deploymentSpec); await this.KubernetesClient.CreateNamespacedDeploymentAsync(deployment, channel.Namespace()); this.Logger.LogInformation("A new deployment for the channel with name '{resourceName}' has been successfully created.", channel.Name()); } catch (HttpOperationException ex) { this.Logger.LogError($"An error occured while creating the deployment for the channel with name '{{resourceName}}': the server responded with a non-success status code '{{statusCode}}'.{Environment.NewLine}Details: {{responseContent}}", channel.Name(), ex.Response.StatusCode, ex.Response.Content); throw; } }
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, TraceWriter log, ExecutionContext context) { log.Info("C# HTTP trigger function processed a request."); //var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(); var configpath = $"{context.FunctionAppDirectory}\\config\\config.txt"; var config = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeconfigPath: configpath); Console.WriteLine("Starting Request!"); IKubernetes client = new Kubernetes(config); var labels = new Dictionary <string, string>(); labels.Add("app", "raincraft"); var ports = new List <V1ContainerPort>(); ports.Add(new V1ContainerPort() { ContainerPort = 25565 }); ports.Add(new V1ContainerPort() { ContainerPort = 25575 }); var env = new List <V1EnvVar>(); env.Add(new V1EnvVar() { Name = "EULA", Value = "true" }); var mounts = new List <V1VolumeMount>(); mounts.Add(new V1VolumeMount() { Name = "minedb", MountPath = "/data" }); var volumes = new List <V1Volume>(); volumes.Add(new V1Volume() { Name = "minedb", PersistentVolumeClaim = new V1PersistentVolumeClaimVolumeSource() { ClaimName = "minevol2" } }); var spec = new V1PodSpec(); spec.Containers = new List <V1Container>(); spec.Containers.Add(new V1Container() { Name = "raincraft-pod", Image = "openhack/minecraft-server:2.0-alpine", Ports = ports, Env = env, VolumeMounts = mounts }); spec.Volumes = volumes; var template = new V1PodTemplateSpec() { Metadata = new V1ObjectMeta() { Name = "raincraft-pod", Labels = labels }, Spec = spec }; var deployment = new V1Deployment() { ApiVersion = "apps/v1", Kind = "Deployment", Metadata = new V1ObjectMeta() { Name = "raincraft", }, Spec = new V1DeploymentSpec() { Replicas = 1, Template = template, Selector = new V1LabelSelector() { MatchLabels = labels } } }; deployment.Validate(); var dresult = client.CreateNamespacedDeployment(deployment, "default"); var list = new List <string>(); //foreach (var i in client.ListNamespacedService("default").Items) //{ // if (i.Metadata.Labels.Contains(new KeyValuePair<string, string>("app", "minepod-service"))) // list.Add(i.Metadata.Name); //} var pods = client.ListNamespacedPod("default").Items; foreach (var i in pods) { if (i.Metadata.Labels.Contains(new KeyValuePair <string, string>("app", "raincraft"))) { list.Add(i.Metadata.Name); } } return(new OkObjectResult(list) as ActionResult); }
private async Task ManageDeployments(V1ServiceList currentServices, V1DeploymentList currentDeployments, EdgeDeploymentDefinition <TConfig> customObject) { var desiredModules = ModuleSet.Create(customObject.Spec.ToArray()); var moduleIdentities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModules, this.currentModules); // Pull current configuration from annotations. Dictionary <string, string> currentV1ServicesFromAnnotations = this.GetCurrentServiceConfig(currentServices); // strip out edgeAgent so edgeAgent doesn't update itself. // TODO: remove this filter. var agentDeploymentName = this.DeploymentName(CoreConstants.EdgeAgentModuleName); Dictionary <string, string> currentDeploymentsFromAnnotations = this.GetCurrentDeploymentConfig(currentDeployments) .ToDictionary( pair => pair.Key, pair => pair.Value); var desiredServices = new List <V1Service>(); var desiredDeployments = new List <V1Deployment>(); foreach (KubernetesModule <TConfig> module in customObject.Spec) { var moduleId = moduleIdentities[module.Name]; if (string.Equals(module.Type, "docker")) { // Default labels var labels = new Dictionary <string, string> { [Constants.K8sEdgeModuleLabel] = KubeUtils.SanitizeLabelValue(moduleId.ModuleId), [Constants.K8sEdgeDeviceLabel] = KubeUtils.SanitizeLabelValue(this.deviceId), [Constants.K8sEdgeHubNameLabel] = KubeUtils.SanitizeLabelValue(this.iotHubHostname) }; // Create a Service for every network interface of each module. (label them with hub, device and module id) Option <V1Service> moduleService = this.GetServiceFromModule(labels, module, moduleId); moduleService.ForEach(service => desiredServices.Add(service)); // Create a Pod for each module, and a proxy container. V1PodTemplateSpec v1PodSpec = this.GetPodFromModule(labels, module, moduleId); // if this is the edge agent's deployment then it needs to run under a specific service account if (moduleIdentities[module.Name].ModuleId == CoreConstants.EdgeAgentModuleIdentityName) { v1PodSpec.Spec.ServiceAccountName = this.serviceAccountName; } // Bundle into a deployment string deploymentName = this.DeploymentName(moduleIdentities[module.Name].ModuleId); // Deployment data var deploymentMeta = new V1ObjectMeta(name: deploymentName, labels: labels); var selector = new V1LabelSelector(matchLabels: labels); var deploymentSpec = new V1DeploymentSpec(replicas: 1, selector: selector, template: v1PodSpec); desiredDeployments.Add(new V1Deployment(metadata: deploymentMeta, spec: deploymentSpec)); } else { Events.InvalidModuleType(module); } } // Find current Services/Deployments which need to be removed and updated var servicesRemoved = new List <V1Service>(currentServices.Items); servicesRemoved.RemoveAll(s => desiredServices.Exists(i => string.Equals(i.Metadata.Name, s.Metadata.Name))); var deploymentsRemoved = new List <V1Deployment>(currentDeployments.Items); deploymentsRemoved.RemoveAll( d => { return(desiredDeployments.Exists(i => string.Equals(i.Metadata.Name, d.Metadata.Name))); }); var newServices = new List <V1Service>(); desiredServices.ForEach( s => { string creationString = JsonConvert.SerializeObject(s); if (currentV1ServicesFromAnnotations.ContainsKey(s.Metadata.Name)) { string serviceAnnotation = currentV1ServicesFromAnnotations[s.Metadata.Name]; // If configuration matches, no need to update service if (string.Equals(serviceAnnotation, creationString)) { return; } if (s.Metadata.Annotations == null) { s.Metadata.Annotations = new Dictionary <string, string>(); } s.Metadata.Annotations[Constants.CreationString] = creationString; servicesRemoved.Add(s); newServices.Add(s); Events.UpdateService(s.Metadata.Name); } else { if (s.Metadata.Annotations == null) { s.Metadata.Annotations = new Dictionary <string, string>(); } s.Metadata.Annotations[Constants.CreationString] = creationString; newServices.Add(s); Events.CreateService(s.Metadata.Name); } }); var deploymentsUpdated = new List <V1Deployment>(); var newDeployments = new List <V1Deployment>(); List <V1Deployment> currentDeploymentsList = currentDeployments.Items.ToList(); desiredDeployments.ForEach( d => { if (currentDeploymentsFromAnnotations.ContainsKey(d.Metadata.Name)) { V1Deployment current = currentDeploymentsList.Find(i => string.Equals(i.Metadata.Name, d.Metadata.Name)); string currentFromAnnotation = currentDeploymentsFromAnnotations[d.Metadata.Name]; string creationString = JsonConvert.SerializeObject(d); // If configuration matches, or this is edgeAgent deployment and the images match, // no need to do update deployment if (string.Equals(currentFromAnnotation, creationString) || (string.Equals(d.Metadata.Name, this.DeploymentName(CoreConstants.EdgeAgentModuleName)) && V1DeploymentEx.ImageEquals(current, d))) { return; } d.Metadata.ResourceVersion = current.Metadata.ResourceVersion; if (d.Metadata.Annotations == null) { var annotations = new Dictionary <string, string> { [Constants.CreationString] = creationString }; d.Metadata.Annotations = annotations; } else { d.Metadata.Annotations[Constants.CreationString] = creationString; } deploymentsUpdated.Add(d); Events.UpdateDeployment(d.Metadata.Name); } else { string creationString = JsonConvert.SerializeObject(d); var annotations = new Dictionary <string, string> { [Constants.CreationString] = creationString }; d.Metadata.Annotations = annotations; newDeployments.Add(d); Events.CreateDeployment(d.Metadata.Name); } }); // Remove the old IEnumerable <Task <V1Status> > removeServiceTasks = servicesRemoved.Select( i => { Events.DeletingService(i); return(this.client.DeleteNamespacedServiceAsync(i.Metadata.Name, this.k8sNamespace, new V1DeleteOptions())); }); await Task.WhenAll(removeServiceTasks); IEnumerable <Task <V1Status> > removeDeploymentTasks = deploymentsRemoved.Select( d => { Events.DeletingDeployment(d); return(this.client.DeleteNamespacedDeployment1Async(d.Metadata.Name, this.k8sNamespace, new V1DeleteOptions(propagationPolicy: "Foreground"), propagationPolicy: "Foreground")); }); await Task.WhenAll(removeDeploymentTasks); // Create the new. IEnumerable <Task <V1Service> > createServiceTasks = newServices.Select( s => { Events.CreatingService(s); return(this.client.CreateNamespacedServiceAsync(s, this.k8sNamespace)); }); await Task.WhenAll(createServiceTasks); IEnumerable <Task <V1Deployment> > createDeploymentTasks = newDeployments.Select( deployment => { Events.CreatingDeployment(deployment); return(this.client.CreateNamespacedDeploymentAsync(deployment, this.k8sNamespace)); }); await Task.WhenAll(createDeploymentTasks); // Update the existing - should only do this when different. IEnumerable <Task <V1Deployment> > updateDeploymentTasks = deploymentsUpdated.Select(deployment => this.client.ReplaceNamespacedDeploymentAsync(deployment, deployment.Metadata.Name, this.k8sNamespace)); await Task.WhenAll(updateDeploymentTasks); this.currentModules = desiredModules; }