Overboard


Generate dynamic config

The real power of Overboard is not only the awesome declarative builder syntax enabled by F# but also that we can leverage the full power of a programming language instead of some hacky templating language.

In the example below we define a function that defines a deployment and a service based on the application name and port number passed to the function.

The function nomalizes the name by lowercasing it and stripping any special characters from it. This is a great way to standardize on naming conventions without always requiring that everyone always remembers the standards.

open System
open Overboard
open Overboard.Common
open Overboard.Workload
open Overboard.Service

/// Returns a deployment and service for `appName`
let publicApi appName portNumber =
    /// Lowercase the name and allow only letters and digits
    let normalize (name: string) =
        name.ToLowerInvariant().ToCharArray() 
        |> Array.filter Char.IsLetterOrDigit
        |> String
    let normalizedName = normalize appName
    let matchOn = ("app", normalizedName)
    k8s {
        deployment {
            $"{normalizedName}-deploy"
            _labels [matchOn]
            replicas 2
            add_matchLabel ("app", normalizedName)
            pod {
                $"{normalizedName}-pod"
                _labels [matchOn]
                container {
                    "nginx"
                    image "nginx"
                }
            }
        }
        service {
            $"{normalizedName}-service"
            _labels [matchOn]
            typeOf ServiceType.NodePort
            matchLabel matchOn
            servicePort {
                port portNumber
                protocol Protocol.TCP
            }
        }
    }

// Use the `publicApi` function to create 2 lists or resources and combine them into a new `K8s` instance. 
let k8sConfig = k8s {
    publicApi "Checkout" 80
    publicApi "Payments" 81
 }

// Get the output content and validation errors
let k8sOutput = KubeCtlWriter.toYaml k8sConfig

Output

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: checkout
  name: checkout-deploy
  namespace: default
spec:
  minReadySeconds: 0
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: checkout
  template:
    metadata:
      labels:
        app: checkout
      name: checkout-pod
      namespace: default
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 256Mi
      restartPolicy: Always

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: checkout
  name: checkout-service
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    app: checkout
  type: NodePort

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: payments
  name: payments-deploy
  namespace: default
spec:
  minReadySeconds: 0
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: payments
  template:
    metadata:
      labels:
        app: payments
      name: payments-pod
      namespace: default
    spec:
      containers:
      - image: nginx
        name: nginx
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
          requests:
            cpu: 500m
            memory: 256Mi
      restartPolicy: Always

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: payments
  name: payments-service
  namespace: default
spec:
  ports:
  - port: 81
    protocol: TCP
  selector:
    app: payments
  type: NodePort

val makeYaml: text: 'a -> string
val text: 'a
namespace System
namespace Overboard
namespace Overboard.Common
namespace Overboard.Workload
namespace Overboard.Service
val publicApi: appName: string -> portNumber: int -> K8s
 Returns a deployment and service for `appName`
val appName: string
val portNumber: int
val normalize: (string -> String)
 Lowercase the name and allow only letters and digits
val name: string
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>


--------------------
type string = String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
String.ToLowerInvariant() : string
type Array = interface ICollection interface IEnumerable interface IList interface IStructuralComparable interface IStructuralEquatable interface ICloneable member Clone: unit -> obj member CopyTo: array: Array * index: int -> unit + 1 overload member GetEnumerator: unit -> IEnumerator member GetLength: dimension: int -> int ...
<summary>Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the base class for all arrays in the common language runtime.</summary>
val filter: predicate: ('T -> bool) -> array: 'T[] -> 'T[]
<summary>Returns a new collection containing only the elements of the collection for which the given predicate returns "true".</summary>
<param name="predicate">The function to test the input elements.</param>
<param name="array">The input array.</param>
<returns>An array containing the elements for which the given predicate returns true.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
<example id="filter-1"><code lang="fsharp"> let inputs = [| 1; 2; 3; 4 |] inputs |&gt; Array.filter (fun elm -&gt; elm % 2 = 0) </code> Evaluates to <c>[| 2; 4 |]</c></example>
[<Struct>] type Char = member CompareTo: value: char -> int + 1 overload member Equals: obj: char -> bool + 1 overload member GetHashCode: unit -> int member GetTypeCode: unit -> TypeCode member ToString: unit -> string + 2 overloads static member ConvertFromUtf32: utf32: int -> string static member ConvertToUtf32: highSurrogate: char * lowSurrogate: char -> int + 1 overload static member GetNumericValue: c: char -> float + 1 overload static member GetUnicodeCategory: c: char -> UnicodeCategory + 1 overload static member IsAscii: c: char -> bool ...
<summary>Represents a character as a UTF-16 code unit.</summary>
Char.IsLetterOrDigit(c: char) : bool
Char.IsLetterOrDigit(s: string, index: int) : bool
Multiple items
type String = interface IEnumerable<char> interface IEnumerable interface ICloneable interface IComparable interface IComparable<string> interface IConvertible interface IEquatable<string> new: value: nativeptr<char> -> unit + 8 overloads member Clone: unit -> obj member CompareTo: value: obj -> int + 1 overload ...
<summary>Represents text as a sequence of UTF-16 code units.</summary>

--------------------
String(value: nativeptr<char>) : String
String(value: char[]) : String
String(value: ReadOnlySpan<char>) : String
String(value: nativeptr<sbyte>) : String
String(c: char, count: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: char[], startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
val normalizedName: String
val matchOn: string * String
val k8s: K8sBuilder
val deployment: DeploymentBuilder
custom operation: _labels ((string * string) list) Calls DeploymentBuilder.Labels
<summary> Labels for the Deployment </summary>
custom operation: replicas (int) Calls DeploymentBuilder.Replicas
custom operation: add_matchLabel (string * string) Calls DeploymentBuilder.MatchLabel
<summary> Add a single label selector to the Deployment. </summary>
val pod: PodBuilder
custom operation: _labels ((string * string) list) Calls PodBuilder.Labels
<summary> Labels for the Pod </summary>
val container: ContainerBuilder
<summary> A single application container that you want to run within a pod. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Container </summary>
custom operation: image (string) Calls ContainerBuilder.Image
val service: ServiceBuilder
custom operation: _labels ((string * string) list) Calls ServiceBuilder.Labels
<summary> Labels for the Service </summary>
custom operation: typeOf (ServiceType) Calls ServiceBuilder.Type
<summary> Type of the Service. </summary>
type ServiceType = | ClusterIP | ExternalName | NodePort | LoadBalancer override ToString: unit -> string
union case ServiceType.NodePort: ServiceType
custom operation: matchLabel (string * string) Calls ServiceBuilder.MatchLabel
<summary> Add a single label selector to the Service. </summary>
val servicePort: ServicePortBuilder
custom operation: port (int) Calls ServicePortBuilder.Port
custom operation: protocol (Protocol) Calls ServicePortBuilder.Protocol
type Protocol = | TCP | UDP | SCTP override ToString: unit -> string static member combine: p1: Protocol -> p2: Protocol -> Protocol
union case Protocol.TCP: Protocol
val k8sConfig: K8s
val k8sOutput: K8sOutput
module KubeCtlWriter from Overboard.K8s
val toYaml: k8s: K8s -> K8sOutput
K8sOutput.content: string