github.com/oam-dev/kubevela@v1.9.11/vela-templates/definitions/internal/component/webservice.cue (about) 1 import ( 2 "strconv" 3 "strings" 4 ) 5 6 webservice: { 7 type: "component" 8 annotations: {} 9 labels: {} 10 description: "Describes long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers." 11 attributes: { 12 workload: { 13 definition: { 14 apiVersion: "apps/v1" 15 kind: "Deployment" 16 } 17 type: "deployments.apps" 18 } 19 status: { 20 customStatus: #""" 21 ready: { 22 readyReplicas: *0 | int 23 } & { 24 if context.output.status.readyReplicas != _|_ { 25 readyReplicas: context.output.status.readyReplicas 26 } 27 } 28 message: "Ready:\(ready.readyReplicas)/\(context.output.spec.replicas)" 29 """# 30 healthPolicy: #""" 31 ready: { 32 updatedReplicas: *0 | int 33 readyReplicas: *0 | int 34 replicas: *0 | int 35 observedGeneration: *0 | int 36 } & { 37 if context.output.status.updatedReplicas != _|_ { 38 updatedReplicas: context.output.status.updatedReplicas 39 } 40 if context.output.status.readyReplicas != _|_ { 41 readyReplicas: context.output.status.readyReplicas 42 } 43 if context.output.status.replicas != _|_ { 44 replicas: context.output.status.replicas 45 } 46 if context.output.status.observedGeneration != _|_ { 47 observedGeneration: context.output.status.observedGeneration 48 } 49 } 50 _isHealth: (context.output.spec.replicas == ready.readyReplicas) && (context.output.spec.replicas == ready.updatedReplicas) && (context.output.spec.replicas == ready.replicas) && (ready.observedGeneration == context.output.metadata.generation || ready.observedGeneration > context.output.metadata.generation) 51 isHealth: *_isHealth | bool 52 if context.output.metadata.annotations != _|_ { 53 if context.output.metadata.annotations["app.oam.dev/disable-health-check"] != _|_ { 54 isHealth: true 55 } 56 } 57 """# 58 } 59 } 60 } 61 template: { 62 mountsArray: [ 63 if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc { 64 { 65 mountPath: v.mountPath 66 if v.subPath != _|_ { 67 subPath: v.subPath 68 } 69 name: v.name 70 } 71 }, 72 73 if parameter.volumeMounts != _|_ && parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap { 74 { 75 mountPath: v.mountPath 76 if v.subPath != _|_ { 77 subPath: v.subPath 78 } 79 name: v.name 80 } 81 }, 82 83 if parameter.volumeMounts != _|_ && parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret { 84 { 85 mountPath: v.mountPath 86 if v.subPath != _|_ { 87 subPath: v.subPath 88 } 89 name: v.name 90 } 91 }, 92 93 if parameter.volumeMounts != _|_ && parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir { 94 { 95 mountPath: v.mountPath 96 if v.subPath != _|_ { 97 subPath: v.subPath 98 } 99 name: v.name 100 } 101 }, 102 103 if parameter.volumeMounts != _|_ && parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath { 104 { 105 mountPath: v.mountPath 106 if v.subPath != _|_ { 107 subPath: v.subPath 108 } 109 name: v.name 110 } 111 }, 112 ] 113 114 volumesList: [ 115 if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc { 116 { 117 name: v.name 118 persistentVolumeClaim: claimName: v.claimName 119 } 120 }, 121 122 if parameter.volumeMounts != _|_ && parameter.volumeMounts.configMap != _|_ for v in parameter.volumeMounts.configMap { 123 { 124 name: v.name 125 configMap: { 126 defaultMode: v.defaultMode 127 name: v.cmName 128 if v.items != _|_ { 129 items: v.items 130 } 131 } 132 } 133 }, 134 135 if parameter.volumeMounts != _|_ && parameter.volumeMounts.secret != _|_ for v in parameter.volumeMounts.secret { 136 { 137 name: v.name 138 secret: { 139 defaultMode: v.defaultMode 140 secretName: v.secretName 141 if v.items != _|_ { 142 items: v.items 143 } 144 } 145 } 146 }, 147 148 if parameter.volumeMounts != _|_ && parameter.volumeMounts.emptyDir != _|_ for v in parameter.volumeMounts.emptyDir { 149 { 150 name: v.name 151 emptyDir: medium: v.medium 152 } 153 }, 154 155 if parameter.volumeMounts != _|_ && parameter.volumeMounts.hostPath != _|_ for v in parameter.volumeMounts.hostPath { 156 { 157 name: v.name 158 hostPath: { 159 path: v.path 160 } 161 } 162 }, 163 ] 164 165 deDupVolumesArray: [ 166 for val in [ 167 for i, vi in volumesList { 168 for j, vj in volumesList if j < i && vi.name == vj.name { 169 _ignore: true 170 } 171 vi 172 }, 173 ] if val._ignore == _|_ { 174 val 175 }, 176 ] 177 178 output: { 179 apiVersion: "apps/v1" 180 kind: "Deployment" 181 spec: { 182 selector: matchLabels: { 183 "app.oam.dev/component": context.name 184 } 185 186 template: { 187 metadata: { 188 labels: { 189 if parameter.labels != _|_ { 190 parameter.labels 191 } 192 if parameter.addRevisionLabel { 193 "app.oam.dev/revision": context.revision 194 } 195 "app.oam.dev/name": context.appName 196 "app.oam.dev/component": context.name 197 } 198 if parameter.annotations != _|_ { 199 annotations: parameter.annotations 200 } 201 } 202 203 spec: { 204 containers: [{ 205 name: context.name 206 image: parameter.image 207 if parameter["port"] != _|_ && parameter["ports"] == _|_ { 208 ports: [{ 209 containerPort: parameter.port 210 }] 211 } 212 if parameter["ports"] != _|_ { 213 ports: [ for v in parameter.ports { 214 { 215 containerPort: { 216 if v.containerPort != _|_ {v.containerPort} 217 if v.containerPort == _|_ {v.port} 218 } 219 protocol: v.protocol 220 if v.name != _|_ { 221 name: v.name 222 } 223 if v.name == _|_ { 224 _name: { 225 if v.containerPort != _|_ {"port-" + strconv.FormatInt(v.containerPort, 10)} 226 if v.containerPort == _|_ {"port-" + strconv.FormatInt(v.port, 10)} 227 } 228 name: *_name | string 229 if v.protocol != "TCP" { 230 name: _name + "-" + strings.ToLower(v.protocol) 231 } 232 } 233 }}] 234 } 235 236 if parameter["imagePullPolicy"] != _|_ { 237 imagePullPolicy: parameter.imagePullPolicy 238 } 239 240 if parameter["cmd"] != _|_ { 241 command: parameter.cmd 242 } 243 244 if parameter["args"] != _|_ { 245 args: parameter.args 246 } 247 248 if parameter["env"] != _|_ { 249 env: parameter.env 250 } 251 252 if context["config"] != _|_ { 253 env: context.config 254 } 255 256 if parameter["cpu"] != _|_ { 257 resources: { 258 limits: cpu: parameter.cpu 259 requests: cpu: parameter.cpu 260 } 261 } 262 263 if parameter["memory"] != _|_ { 264 resources: { 265 limits: memory: parameter.memory 266 requests: memory: parameter.memory 267 } 268 } 269 270 if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ { 271 volumeMounts: [ for v in parameter.volumes { 272 { 273 mountPath: v.mountPath 274 name: v.name 275 }}] 276 } 277 278 if parameter["volumeMounts"] != _|_ { 279 volumeMounts: mountsArray 280 } 281 282 if parameter["livenessProbe"] != _|_ { 283 livenessProbe: parameter.livenessProbe 284 } 285 286 if parameter["readinessProbe"] != _|_ { 287 readinessProbe: parameter.readinessProbe 288 } 289 290 }] 291 292 if parameter["hostAliases"] != _|_ { 293 // +patchKey=ip 294 hostAliases: parameter.hostAliases 295 } 296 297 if parameter["imagePullSecrets"] != _|_ { 298 imagePullSecrets: [ for v in parameter.imagePullSecrets { 299 name: v 300 }, 301 ] 302 } 303 304 if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ { 305 volumes: [ for v in parameter.volumes { 306 { 307 name: v.name 308 if v.type == "pvc" { 309 persistentVolumeClaim: claimName: v.claimName 310 } 311 if v.type == "configMap" { 312 configMap: { 313 defaultMode: v.defaultMode 314 name: v.cmName 315 if v.items != _|_ { 316 items: v.items 317 } 318 } 319 } 320 if v.type == "secret" { 321 secret: { 322 defaultMode: v.defaultMode 323 secretName: v.secretName 324 if v.items != _|_ { 325 items: v.items 326 } 327 } 328 } 329 if v.type == "emptyDir" { 330 emptyDir: medium: v.medium 331 } 332 } 333 }] 334 } 335 336 if parameter["volumeMounts"] != _|_ { 337 volumes: deDupVolumesArray 338 } 339 } 340 } 341 } 342 } 343 344 exposePorts: [ 345 if parameter.ports != _|_ for v in parameter.ports if v.expose == true { 346 port: v.port 347 if v.containerPort != _|_ {targetPort: v.containerPort} 348 if v.containerPort == _|_ {targetPort: v.port} 349 if v.name != _|_ {name: v.name} 350 if v.name == _|_ { 351 _name: { 352 if v.containerPort != _|_ { 353 "port-" + strconv.FormatInt(v.containerPort, 10) 354 } 355 if v.containerPort == _|_ { 356 "port-" + strconv.FormatInt(v.port, 10) 357 } 358 } 359 name: *_name | string 360 if v.protocol != "TCP" { 361 name: _name + "-" + strings.ToLower(v.protocol) 362 } 363 } 364 if v.nodePort != _|_ && parameter.exposeType == "NodePort" { 365 nodePort: v.nodePort 366 } 367 if v.protocol != _|_ { 368 protocol: v.protocol 369 } 370 }, 371 ] 372 373 outputs: { 374 if len(exposePorts) != 0 { 375 webserviceExpose: { 376 apiVersion: "v1" 377 kind: "Service" 378 metadata: name: context.name 379 spec: { 380 selector: "app.oam.dev/component": context.name 381 ports: exposePorts 382 type: parameter.exposeType 383 } 384 } 385 } 386 } 387 388 parameter: { 389 // +usage=Specify the labels in the workload 390 labels?: [string]: string 391 392 // +usage=Specify the annotations in the workload 393 annotations?: [string]: string 394 395 // +usage=Which image would you like to use for your service 396 // +short=i 397 image: string 398 399 // +usage=Specify image pull policy for your service 400 imagePullPolicy?: "Always" | "Never" | "IfNotPresent" 401 402 // +usage=Specify image pull secrets for your service 403 imagePullSecrets?: [...string] 404 405 // +ignore 406 // +usage=Deprecated field, please use ports instead 407 // +short=p 408 port?: int 409 410 // +usage=Which ports do you want customer traffic sent to, defaults to 80 411 ports?: [...{ 412 // +usage=Number of port to expose on the pod's IP address 413 port: int 414 // +usage=Number of container port to connect to, defaults to port 415 containerPort?: int 416 // +usage=Name of the port 417 name?: string 418 // +usage=Protocol for port. Must be UDP, TCP, or SCTP 419 protocol: *"TCP" | "UDP" | "SCTP" 420 // +usage=Specify if the port should be exposed 421 expose: *false | bool 422 // +usage=exposed node port. Only Valid when exposeType is NodePort 423 nodePort?: int 424 }] 425 426 // +ignore 427 // +usage=Specify what kind of Service you want. options: "ClusterIP", "NodePort", "LoadBalancer" 428 exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer" 429 430 // +ignore 431 // +usage=If addRevisionLabel is true, the revision label will be added to the underlying pods 432 addRevisionLabel: *false | bool 433 434 // +usage=Commands to run in the container 435 cmd?: [...string] 436 437 // +usage=Arguments to the entrypoint 438 args?: [...string] 439 440 // +usage=Define arguments by using environment variables 441 env?: [...{ 442 // +usage=Environment variable name 443 name: string 444 // +usage=The value of the environment variable 445 value?: string 446 // +usage=Specifies a source the value of this var should come from 447 valueFrom?: { 448 // +usage=Selects a key of a secret in the pod's namespace 449 secretKeyRef?: { 450 // +usage=The name of the secret in the pod's namespace to select from 451 name: string 452 // +usage=The key of the secret to select from. Must be a valid secret key 453 key: string 454 } 455 // +usage=Selects a key of a config map in the pod's namespace 456 configMapKeyRef?: { 457 // +usage=The name of the config map in the pod's namespace to select from 458 name: string 459 // +usage=The key of the config map to select from. Must be a valid secret key 460 key: string 461 } 462 } 463 }] 464 465 // +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core) 466 cpu?: string 467 468 // +usage=Specifies the attributes of the memory resource required for the container. 469 memory?: string 470 471 volumeMounts?: { 472 // +usage=Mount PVC type volume 473 pvc?: [...{ 474 name: string 475 mountPath: string 476 subPath?: string 477 // +usage=The name of the PVC 478 claimName: string 479 }] 480 // +usage=Mount ConfigMap type volume 481 configMap?: [...{ 482 name: string 483 mountPath: string 484 subPath?: string 485 defaultMode: *420 | int 486 cmName: string 487 items?: [...{ 488 key: string 489 path: string 490 mode: *511 | int 491 }] 492 }] 493 // +usage=Mount Secret type volume 494 secret?: [...{ 495 name: string 496 mountPath: string 497 subPath?: string 498 defaultMode: *420 | int 499 secretName: string 500 items?: [...{ 501 key: string 502 path: string 503 mode: *511 | int 504 }] 505 }] 506 // +usage=Mount EmptyDir type volume 507 emptyDir?: [...{ 508 name: string 509 mountPath: string 510 subPath?: string 511 medium: *"" | "Memory" 512 }] 513 // +usage=Mount HostPath type volume 514 hostPath?: [...{ 515 name: string 516 mountPath: string 517 subPath?: string 518 path: string 519 }] 520 } 521 522 // +usage=Deprecated field, use volumeMounts instead. 523 volumes?: [...{ 524 name: string 525 mountPath: string 526 // +usage=Specify volume type, options: "pvc","configMap","secret","emptyDir", default to emptyDir 527 type: *"emptyDir" | "pvc" | "configMap" | "secret" 528 if type == "pvc" { 529 claimName: string 530 } 531 if type == "configMap" { 532 defaultMode: *420 | int 533 cmName: string 534 items?: [...{ 535 key: string 536 path: string 537 mode: *511 | int 538 }] 539 } 540 if type == "secret" { 541 defaultMode: *420 | int 542 secretName: string 543 items?: [...{ 544 key: string 545 path: string 546 mode: *511 | int 547 }] 548 } 549 if type == "emptyDir" { 550 medium: *"" | "Memory" 551 } 552 }] 553 554 // +usage=Instructions for assessing whether the container is alive. 555 livenessProbe?: #HealthProbe 556 557 // +usage=Instructions for assessing whether the container is in a suitable state to serve traffic. 558 readinessProbe?: #HealthProbe 559 560 // +usage=Specify the hostAliases to add 561 hostAliases?: [...{ 562 ip: string 563 hostnames: [...string] 564 }] 565 } 566 567 #HealthProbe: { 568 569 // +usage=Instructions for assessing container health by executing a command. Either this attribute or the httpGet attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the httpGet attribute and the tcpSocket attribute. 570 exec?: { 571 // +usage=A command to be executed inside the container to assess its health. Each space delimited token of the command is a separate array element. Commands exiting 0 are considered to be successful probes, whilst all other exit codes are considered failures. 572 command: [...string] 573 } 574 575 // +usage=Instructions for assessing container health by executing an HTTP GET request. Either this attribute or the exec attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the tcpSocket attribute. 576 httpGet?: { 577 // +usage=The endpoint, relative to the port, to which the HTTP GET request should be directed. 578 path: string 579 // +usage=The TCP socket within the container to which the HTTP GET request should be directed. 580 port: int 581 host?: string 582 scheme?: *"HTTP" | string 583 httpHeaders?: [...{ 584 name: string 585 value: string 586 }] 587 } 588 589 // +usage=Instructions for assessing container health by probing a TCP socket. Either this attribute or the exec attribute or the httpGet attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the httpGet attribute. 590 tcpSocket?: { 591 // +usage=The TCP socket within the container that should be probed to assess container health. 592 port: int 593 } 594 595 // +usage=Number of seconds after the container is started before the first probe is initiated. 596 initialDelaySeconds: *0 | int 597 598 // +usage=How often, in seconds, to execute the probe. 599 periodSeconds: *10 | int 600 601 // +usage=Number of seconds after which the probe times out. 602 timeoutSeconds: *1 | int 603 604 // +usage=Minimum consecutive successes for the probe to be considered successful after having failed. 605 successThreshold: *1 | int 606 607 // +usage=Number of consecutive failures required to determine the container is not alive (liveness probe) or not ready (readiness probe). 608 failureThreshold: *3 | int 609 } 610 }