/ Framework / KubernetesWorkflow / Recipe / ContainerRecipeFactory.cs
ContainerRecipeFactory.cs
  1  using System.Globalization;
  2  using Utils;
  3  
  4  namespace KubernetesWorkflow.Recipe
  5  {
  6      public abstract class ContainerRecipeFactory
  7      {
  8          private readonly List<Port> exposedPorts = new List<Port>();
  9          private readonly List<Port> internalPorts = new List<Port>();
 10          private readonly List<EnvVar> envVars = new List<EnvVar>();
 11          private readonly PodLabels podLabels = new PodLabels();
 12          private readonly PodAnnotations podAnnotations = new PodAnnotations();
 13          private readonly List<VolumeMount> volumeMounts = new List<VolumeMount>();
 14          private readonly List<object> additionals = new List<object>();
 15          private RecipeComponentFactory factory = null!;
 16          private ContainerResources resources = new ContainerResources();
 17          private SchedulingAffinity schedulingAffinity = new SchedulingAffinity();
 18          private CommandOverride commandOverride = new CommandOverride();
 19          private bool setCriticalPriority;
 20  
 21          public ContainerRecipe CreateRecipe(int index, int containerNumber, RecipeComponentFactory factory, StartupConfig config)
 22          {
 23              this.factory = factory;
 24              ContainerNumber = containerNumber;
 25              Index = index;
 26  
 27              Initialize(config);
 28  
 29              var recipe = new ContainerRecipe(DateTime.UtcNow, containerNumber, config.NameOverride, Image, resources, schedulingAffinity, commandOverride, setCriticalPriority,
 30                  exposedPorts.ToArray(),
 31                  internalPorts.ToArray(),
 32                  envVars.ToArray(),
 33                  podLabels.Clone(),
 34                  podAnnotations.Clone(),
 35                  volumeMounts.ToArray(),
 36                  ContainerAdditionals.CreateFromUserData(additionals));
 37  
 38              exposedPorts.Clear();
 39              internalPorts.Clear();
 40              envVars.Clear();
 41              podLabels.Clear();
 42              podAnnotations.Clear();
 43              volumeMounts.Clear();
 44              additionals.Clear();
 45              this.factory = null!;
 46              resources = new ContainerResources();
 47              schedulingAffinity = new SchedulingAffinity();
 48              commandOverride = new CommandOverride();
 49              setCriticalPriority = false;
 50  
 51              return recipe;
 52          }
 53  
 54          public abstract string AppName { get; }
 55          public abstract string Image { get; }
 56          protected int ContainerNumber { get; private set; } = 0;
 57          protected int Index { get; private set; } = 0;
 58          protected abstract void Initialize(StartupConfig config);
 59  
 60          protected Port AddExposedPort(string tag, PortProtocol protocol = PortProtocol.TCP)
 61          {
 62              return AddExposedPort(factory.CreateExternalPort(tag, protocol));
 63          }
 64  
 65          protected Port AddExposedPort(int number, string tag, PortProtocol protocol = PortProtocol.TCP)
 66          {
 67              return AddExposedPort(factory.CreateExternalPort(number, tag, protocol));
 68          }
 69  
 70          protected Port AddInternalPort(string tag = "", PortProtocol protocol = PortProtocol.TCP)
 71          {
 72              var p = factory.CreateInternalPort(tag, protocol);
 73              internalPorts.Add(p);
 74              return p;
 75          }
 76  
 77          protected void AddExposedPortAndVar(string name, string tag, PortProtocol protocol = PortProtocol.TCP)
 78          {
 79              AddEnvVar(name, AddExposedPort(tag, protocol));
 80          }
 81  
 82          protected void AddInternalPortAndVar(string name, string tag = "", PortProtocol protocol = PortProtocol.TCP)
 83          {
 84              AddEnvVar(name, AddInternalPort(tag, protocol));
 85          }
 86  
 87          protected void AddEnvVar(string name, string value)
 88          {
 89              envVars.Add(factory.CreateEnvVar(name, value));
 90          }
 91  
 92          protected void AddEnvVar(string name, int value)
 93          {
 94              envVars.Add(factory.CreateEnvVar(name, value.ToString(CultureInfo.InvariantCulture)));
 95          }
 96  
 97          protected void AddEnvVar(string name, Port value)
 98          {
 99              envVars.Add(factory.CreateEnvVar(name, value.Number));
100          }
101  
102          protected void AddPodLabel(string name, string value)
103          {
104              podLabels.Add(name, value);
105          }
106  
107          protected void AddPodAnnotation(string name, string value)
108          {
109              podAnnotations.Add(name, value);
110          }
111  
112          protected void AddVolume(string name, string mountPath, string? subPath = null, string? secret = null, string? hostPath = null)
113          {
114              var size = 10.MB().SizeInBytes.ToString();
115              volumeMounts.Add(new VolumeMount(name, mountPath, subPath, size, secret, hostPath));
116          }
117  
118          protected void AddVolume(string mountPath, ByteSize volumeSize)
119          {
120              volumeMounts.Add(new VolumeMount(
121                  $"autovolume-{Guid.NewGuid().ToString().ToLowerInvariant()}",
122                  mountPath,
123                  resourceQuantity: volumeSize.SizeInBytes.ToString()));
124          }
125  
126          protected void Additional(object userData)
127          {
128              additionals.Add(userData);
129          }
130  
131          protected void SetResourcesRequest(int milliCPUs, ByteSize memory)
132          {
133              SetResourcesRequest(new ContainerResourceSet(milliCPUs, memory));
134          }
135  
136          protected void SetSchedulingAffinity(string notIn)
137          {
138              schedulingAffinity = new SchedulingAffinity(notIn);
139          }
140  
141          protected void OverrideCommand(params string[] command)
142          {
143              commandOverride = new CommandOverride(command);
144          }
145  
146          protected void SetSystemCriticalPriority()
147          {
148              setCriticalPriority = true;
149          }
150  
151          // Disabled following a possible bug in the k8s cluster that will throttle containers much more than is
152          // called for if they have resource limits defined.
153          //protected void SetResourceLimits(int milliCPUs, ByteSize memory)
154          //{
155          //    SetResourceLimits(new ContainerResourceSet(milliCPUs, memory));
156          //}
157  
158          protected void SetResourcesRequest(ContainerResourceSet requests)
159          {
160              resources.Requests = requests;
161          }
162  
163          protected void SetResourceLimits(ContainerResourceSet limits)
164          {
165              resources.Limits = limits;
166          }
167  
168          private Port AddExposedPort(Port port)
169          {
170              exposedPorts.Add(port);
171              return port;
172          }
173      }
174  }