import (
"strconv"
"strings"
)
webservice: {
type: "component"
annotations: {
"generates.output.spectrocloud.com/ip": "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"paths\":\".spec.clusterIP,.status.loadBalancer.ingress[0].ip\"}"
"generates.output.spectrocloud.com/ports": "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"paths\":\".spec.ports\"}"
}
labels: {
"componentdefinition.spectrocloud.com/type": "application"
"definition.spectrocloud.com/category": "Application-Workload"
}
description: "Describes long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers."
attributes: {
status: {
customStatus: {
ready: {
readyReplicas: *0 | int
unavailableReplicas: *0 | int
} & {
if context.output.status.readyReplicas != _|_ {
readyReplicas: context.output.status.readyReplicas
}
if context.output.status.unavailableReplicas != _|_ {
unavailableReplicas: context.output.status.unavailableReplicas
}
}
message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas); Unavailable:\(ready.unavailableReplicas)/\(context.output.spec.replicas)"
}
healthPolicy: {
ready: {
updatedReplicas: *0 | int
readyReplicas: *0 | int
replicas: *0 | int
unavailableReplicas: *0 | int
} & {
if context.output.status.updatedReplicas != _|_ {
updatedReplicas: context.output.status.updatedReplicas
}
if context.output.status.readyReplicas != _|_ {
readyReplicas: context.output.status.readyReplicas
}
if context.output.status.unavailableReplicas != _|_ {
unavailableReplicas: context.output.status.unavailableReplicas
}
if context.output.status.replicas != _|_ {
replicas: context.output.status.replicas
}
}
_isHealth: (context.output.spec.replicas == ready.readyReplicas) && (context.output.spec.replicas == ready.updatedReplicas) && (context.output.spec.replicas == ready.replicas) && (ready.unavailableReplicas == 0)
isHealth: *_isHealth | bool
if context.output.metadata.annotations != _|_ {
if context.output.metadata.annotations["wl.spectrocloud.com/disable-health-check"] != _|_ {
isHealth: true
}
}
}
}
}
}
template: {
mountsArray: [
if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {
{
mountPath: v.mountPath
if v.subPath != _|_ {
subPath: v.subPath
}
name: v.name
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap {
{
mountPath: v.mountPath
if v.subPath != _|_ {
subPath: v.subPath
}
name: v.name
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret {
{
mountPath: v.mountPath
if v.subPath != _|_ {
subPath: v.subPath
}
name: v.name
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir {
{
mountPath: v.mountPath
if v.subPath != _|_ {
subPath: v.subPath
}
name: v.name
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath {
{
mountPath: v.mountPath
if v.subPath != _|_ {
subPath: v.subPath
}
name: v.name
}
},
]
volumesList: [
if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {
{
name: v.name
persistentVolumeClaim: claimName: v.claimName
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap {
{
name: v.name
configMap: {
defaultMode: v.defaultMode
name: v.cmName
if v.items != _|_ {
items: v.items
}
}
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret {
{
name: v.name
secret: {
defaultMode: v.defaultMode
secretName: v.secretName
if v.items != _|_ {
items: v.items
}
}
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir {
{
name: v.name
emptyDir: medium: v.medium
}
},
if parameter.volumeMounts != _|_ && parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath {
{
name: v.name
hostPath: {
path: v.path
}
}
},
]
deDupVolumesArray: [
for val in [
for i, vi in volumesList {
for j, vj in volumesList if j < i && vi.name == vj.name {
_ignore: true
}
vi
},
] if val._ignore == _|_ {
val
},
]
output: {
apiVersion: "apps/v1"
kind: "Deployment"
spec: {
selector: matchLabels: {
"wl.spectrocloud.com/component": context.name
}
template: {
metadata: {
labels: {
if parameter.labels != _|_ {
parameter.labels
}
if parameter.addRevisionLabel {
"wl.spectrocloud.com/revision": context.revision
}
"wl.spectrocloud.com/name": context.workloadName
"wl.spectrocloud.com/component": context.name
}
if parameter.annotations != _|_ {
annotations: parameter.annotations
}
}
spec: {
containers: [{
name: context.name
image: parameter.image
if parameter["containerPort"] != _|_ && parameter["ports"] == _|_ {
ports: [{
containerPort: parameter.containerPort
}]
}
if parameter["ports"] != _|_ {
ports: [for v in parameter.ports {
{
containerPort: v.containerPort
protocol: v.protocol
if v.name != _|_ {
name: v.name
}
if v.name == _|_ {
_name: "port-" + strconv.FormatInt(v.containerPort, 10)
name: *_name | string
if v.protocol != "TCP" {
name: _name + "-" + strings.ToLower(v.protocol)
}
}
}}]
}
if parameter["imagePullPolicy"] != _|_ {
imagePullPolicy: parameter.imagePullPolicy
}
if parameter["cmd"] != _|_ {
command: parameter.cmd
}
if parameter["args"] != _|_ {
args: parameter.args
}
if parameter["env"] != _|_ {
env: parameter.env
}
if context["config"] != _|_ {
env: context.config
}
if parameter["cpu"] != _|_ {
if (parameter.limit.cpu != _|_) {
resources: {
requests: cpu: parameter.cpu
limits: cpu: parameter.limit.cpu
}
}
if (parameter.limit.cpu == _|_) {
resources: {
limits: cpu: parameter.cpu
requests: cpu: parameter.cpu
}
}
}
if parameter["memory"] != _|_ {
if (parameter.limit.memory != _|_) {
resources: {
limits: memory: parameter.limit.memory
requests: memory: parameter.memory
}
}
if (parameter.limit.memory == _|_) {
resources: {
limits: memory: parameter.memory
requests: memory: parameter.memory
}
}
}
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
volumeMounts: [for v in parameter.volumes {
{
mountPath: v.mountPath
name: v.name
}}]
}
if parameter["volumeMounts"] != _|_ {
volumeMounts: mountsArray
}
if parameter["livenessProbe"] != _|_ {
livenessProbe: parameter.livenessProbe
}
if parameter["readinessProbe"] != _|_ {
readinessProbe: parameter.readinessProbe
}
}]
if parameter["hostAliases"] != _|_ {
hostAliases: parameter.hostAliases
}
if parameter["imagePullSecrets"] != _|_ {
imagePullSecrets: [for v in parameter.imagePullSecrets {
name: v
},
]
}
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
volumes: [for v in parameter.volumes {
{
name: v.name
if v.type == "pvc" {
persistentVolumeClaim: claimName: v.claimName
}
if v.type == "configMap" {
configMap: {
defaultMode: v.defaultMode
name: v.cmName
if v.items != _|_ {
items: v.items
}
}
}
if v.type == "secret" {
secret: {
defaultMode: v.defaultMode
secretName: v.secretName
if v.items != _|_ {
items: v.items
}
}
}
if v.type == "emptyDir" {
emptyDir: medium: v.medium
}
}
}]
}
if parameter["volumeMounts"] != _|_ {
volumes: deDupVolumesArray
}
}
}
}
}
exposePorts: [
if parameter.ports != _|_ for v in parameter.ports if v.expose == true {
port: v.containerPort
targetPort: v.containerPort
if v.name != _|_ {
name: v.name
}
if v.name == _|_ {
_name: "port-" + strconv.FormatInt(v.containerPort, 10)
name: *_name | string
if v.protocol != "TCP" {
name: _name + "-" + strings.ToLower(v.protocol)
}
}
if v.nodePort != _|_ && parameter.exposeType == "NodePort" {
nodePort: v.nodePort
}
if v.protocol != _|_ {
protocol: v.protocol
}
},
]
outputs: {
if len(exposePorts) != 0 {
webserviceExpose: {
apiVersion: "v1"
kind: "Service"
metadata: {
name: context.name
annotations: {
"output.spectrocloud.com/ports": ".spec.ports"
if parameter.exposeType == "ClusterIP" {
"output.spectrocloud.com/ip": ".spec.clusterIP"
}
if parameter.exposeType == "LoadBalancer" {
"output.spectrocloud.com/ip": ".status.loadBalancer.ingress[0].ip"
}
}
}
spec: {
selector: "wl.spectrocloud.com/component": context.name
ports: exposePorts
type: parameter.exposeType
}
}
}
}
parameter: {
labels?: [string]: string
annotations?: [string]: string
image: string
imagePullPolicy?: "Always" | "Never" | "IfNotPresent"
imagePullSecrets?: [...string]
containerPort?: int
ports?: [...{
containerPort: int
name?: string
protocol: *"TCP" | "UDP" | "SCTP"
expose: *false | bool
nodePort?: int
}]
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer"
addRevisionLabel: *false | bool
cmd?: [...string]
args?: [...string]
env?: [...{
name: string
value?: string
valueFrom?: {
secretKeyRef?: {
name: string
key: string
}
configMapKeyRef?: {
name: string
key: string
}
fieldRef?: {
apiVersion: *"v1" | string
fieldPath: string
}
}
}]
cpu?: string
memory?: string
limit?: {
cpu?: string
memory?: string
}
volumeMounts?: {
pvc?: [...{
name: string
mountPath: string
subPath?: string
claimName: string
}]
configMap?: [...{
name: string
mountPath: string
subPath?: string
defaultMode: *420 | int
cmName: string
items?: [...{
key: string
path: string
mode: *511 | int
}]
}]
secret?: [...{
name: string
mountPath: string
subPath?: string
defaultMode: *420 | int
secretName: string
items?: [...{
key: string
path: string
mode: *511 | int
}]
}]
emptyDir?: [...{
name: string
mountPath: string
subPath?: string
medium: *"" | "Memory"
}]
hostPath?: [...{
name: string
mountPath: string
subPath?: string
path: string
}]
}
volumes?: [...{
name: string
mountPath: string
type: *"emptyDir" | "pvc" | "configMap" | "secret"
if type == "pvc" {
claimName: string
}
if type == "configMap" {
defaultMode: *420 | int
cmName: string
items?: [...{
key: string
path: string
mode: *511 | int
}]
}
if type == "secret" {
defaultMode: *420 | int
secretName: string
items?: [...{
key: string
path: string
mode: *511 | int
}]
}
if type == "emptyDir" {
medium: *"" | "Memory"
}
}]
livenessProbe?: #ExecHealthProbe | #HTTPHealthProbe | #TCPHealthProbe
readinessProbe?: #ExecHealthProbe | #HTTPHealthProbe | #TCPHealthProbe
hostAliases?: [...{
ip: string
hostnames!: [...string]
}]
}
#ExecHealthProbe: {
exec: {
command!: [...string]
}
initialDelaySeconds: *0 | int
periodSeconds: *10 | int
timeoutSeconds: *1 | int
successThreshold: *1 | int
failureThreshold: *3 | int
}
#HTTPHealthProbe: {
httpGet: {
path: string
port: int
host?: string
scheme?: *"HTTP" | string
httpHeaders?: [...{
name: string
value: string
}]
}
initialDelaySeconds: *0 | int
periodSeconds: *10 | int
timeoutSeconds: *1 | int
successThreshold: *1 | int
failureThreshold: *3 | int
}
#TCPHealthProbe: {
tcpSocket: {
port: int
}
initialDelaySeconds: *0 | int
periodSeconds: *10 | int
timeoutSeconds: *1 | int
successThreshold: *1 | int
failureThreshold: *3 | int
}
}