What makes CUE useful in Dagger ?

Using CUE dagger
Reading Time: 5 minutes

Introduction

Dagger is a devkit used in CICD using BuildKit and CUE for platform independent pipeline creation. The language CUE stands for Configure,Unify and Execute. It is a logical configuration language. This means it can create template with scripting as well.

We will see various feature that are useful for Dagger environment in CUE. We will using CUE Playground for the code used. You can also install CUE on local system after installing GoLang.

Prerequisites

  1. If using CUE Playground, all required is the Internet.
  2. If Locally then, Go and CUE installed on System.

Features of CUE for Dagger

CUE is a superset of JSON

This means whatever that is written in JSON can be written in CUE. The following line is written in same way in JSON and CUE.

{
  "Vaibhav": {
    "Name": "Vaibhav Kumar",
    "Age": 22
  }
}

But CUE has some more power, like define the template as we will be seeing in Definations. One other power is writing the expression in a single line

Vaibhav: Name: "Vaibhav Kumar"

It is similar to JSON in following way:

{
    "Vaibhav": {
        "Name": "Vaibhav Kumar"
    }
}
CUE playground

Types as the Values

When we give an input or expression in CUE it should obey some restrictions. As Dagger will be used for CICD process, it expects values to be defined or constraints. So we give the type of it in CUE as following:

Vaibhav: {
  Name: string // type 
  Age: int
}

Vaibhav: {
  Name: "Vaibhav kumar"
  Age: 22
}

Since the type string and int do not require quotes, we say types as values.

CUE Playground

Now if we miss or change any value other than type defined, it gives error. as following:

CUE Playground

Concrete values

This is for fixed values which are not definitions or rules. It is actual data for workflow. This is exported in CICD . In last example, if we miss any value it shows error in following way:

Vaibhav: {
  Name: string
  Age: int
}

Vaibhav: {
  Name: "Vaibhav Kumar"
  //Age: 22 we have commented this line
}
CUE Playground

Definitions

Till now we were defining for one Person, but in CICD we need rules for multiple persons. We can create a template or blueprint in CUE called Definations. they have the symbol ‘#’ for this. We will be doing in following way:

#Person: {
  Name: string
  Email: string
  Age?: int
}

Vaibhav: #Person & {
  Name: "Vaibhav Kumar"
  Email: "vaibhav.kumar@knoldus.com"
}

Shivam: #Person & {
  Name: "Shivam Pateriya"
  Email: "shivam.pateriya@knoldus.com"
  Age: 23
}

To use Defination Person we need to abstact it using symbol ‘&‘ . Note: There a symbol ‘?’ after ‘Age’. This makes it optional to define when used. And we do not get an error using above code as following:

CUE Playground

Unification

It is the speciality of CUE which allows to use constraints and concrete values in a single file. This was seen in last example as well. We can add more constraints as in following code:

import (
  "strings"
)

#Person: {
  // further constrain to a min and max length
  Name: string & strings.MinRunes(3) & strings.MaxRunes(22)

  // we don't need string because the regex handles that
  Email: =~"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"

  // further constrain to realistic ages
  Age?: int & >0 & <140
}

Vaibhav: #Person & {
  Name: "Vaibhav Kumar"
  Email: "vaibhav.kumar@knoldus.com"
  Age: 22
}

We have defined import in later part.

CUE Playground

Inheritance

CUE does not allow overrides. An this is due to reason that it leads to unwanted and difficult to debug side effects. While other languages like Python, you define classes where an Inherited class values are not permanent. You cannot override them in CUE. In following example, if uncomment the Job line it give conflict value error.

#Person: {
  
  Name: string
  Email: string
  Age?: int
  Job?: string
}

#Engineer: #Person & {
  Job: "Engineer" // Job is further constrained to required and exactly this value
}

Vaibhav: #Engineer & {
  Name: "Vaibhav Kumar"
  Email: "vaibhav.kumar@knoldus.com"
  Age: 22
  //Job: "Pilot"
}
CUE Playground

Since it is only for concrete values, we can add options and a default value to allow changes.As done below:

#Person: {
  
  Name: string
  Email: string
  Age?: int
  Job?: string
}

#Engineer: #Person & {
  Job: string | *"Engineer" 
}

Vaibhav: #Engineer & {
  Name: "Vaibhav Kumar"
  Email: "vaibhav.kumar@knoldus.com"
  Age: 22
  Job: "Pilot"
}

Here default value is Engineer but if provided it would allow input as different Job.

CUE Playground

Embedding

CUE allows embedding of one definition in another. As seen in last example. We can also extend the definition as following:

#Person: {
  
  Name: string
  Email: string
  Age?: int
  Job?: string
}

#Engineer: {

  Domain: "Backend" | "Frontend" | "DevOps"
  #Person & {
    Job: "Engineer" 
  }
}
Vaibhav: #Engineer & {
  Name: "Vaibhav Kumar"
  Email: "vaibhav.kumar@knoldus.com"
  Age: 22
  Domain: "DevOps"
}
CUE Playground

Packages

Like programming languages Python, Java etc. , CUE also import packages. The are reusable, predefined code or scripts. One example has used “strings” package. When you explore Dagger, it has used this feature to use the predefined binaries, created in Dagger Universe. This overcomes the docker problem of various repositories to use for a project.Dagger team create and verifies these packages.

Conclusion

These features have enabled CUE as the scripting partner to dagger. You do not need to master CUE to move to dagger. We can start with this much understanding only.

References

  1. https://docs.dagger.io/
  2. https://cuelang.org/
  3. https://cuetorials.com/
footer

Written by 

Explorer of new technologies: from DevOps to Web 3