Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add v1alpha2 API #673

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ GOPROXY ?= $(shell go env GOPROXY)
# Runnable tools
GO ?= go
BUF := $(GO) run github.com/bufbuild/buf/cmd/[email protected]
CONTROLLER_GEN := $(GO) run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.10
CONTROLLER_GEN := $(GO) run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11
GOFUMPT := $(GO) run mvdan.cc/[email protected]
KUSTOMIZE := $(GO) run sigs.k8s.io/kustomize/kustomize/[email protected]
SETUP_ENVTEST := $(GO) run sigs.k8s.io/controller-runtime/tools/[email protected]
Expand Down
45 changes: 45 additions & 0 deletions api/v1alpha2/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package v1alpha2

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// ConditionType identifies the type of condition.
type ConditionType string

// ConditionStatus expresses the current state of the condition.
type ConditionStatus string

const (
// ConditionStatusUnknown is the default status and indicates the condition cannot be
// evaluated as True or False.
ConditionStatusUnknown ConditionStatus = "Unknown"

// ConditionStatusTrue indicates the condition has been evaluated as true.
ConditionStatusTrue ConditionStatus = "True"

// ConditionStatusFalse indicates the condition has been evaluated as false.
ConditionStatusFalse ConditionStatus = "False"
)

// Condition defines an observation on a resource that is generally attainable by inspecting
// other status fields.
type Condition struct {
// Type of condition.
Type ConditionType `json:"type"`

// Status of the condition.
Status ConditionStatus `json:"status"`

// LastTransition is the last time the condition transitioned from one status to another.
LastTransition *metav1.Time `json:"lastTransitionTime"`

// Reason is a short CamelCase description for the conditions last transition.
// +optional
Reason *string `json:"reason,omitempty"`

// Message is a human readable message indicating details about the last transition.
// +optional
Message *string `json:"message,omitempty"`
}

// Conditions define a list of observations of a particular resource.
type Conditions []Condition
20 changes: 20 additions & 0 deletions api/v1alpha2/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// +groupName=tinkerbell.org
// +kubebuilder:object:generate=true

package v1alpha2

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects.
GroupVersion = schema.GroupVersion{Group: "tinkerbell.org", Version: "v1alpha2"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
178 changes: 178 additions & 0 deletions api/v1alpha2/hardware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package v1alpha2

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type HardwareSpec struct {
// NetworkInterfaces defines the desired DHCP and netboot configuration for a network interface.
// +kubebuilder:validation:MinPoperties=1
NetworkInterfaces NetworkInterfaces `json:"networkInterfaces,omitempty"`

// IPXE provides iPXE script override fields. This is useful for debugging or netboot
// customization.
// +optional.
IPXE *IPXE `json:"ipxe,omitempty"`

// OSIE describes the Operating System Installation Environment to be netbooted.
OSIE corev1.LocalObjectReference `json:"osie,omitempty"`

// KernelParams passed to the kernel when launching the OSIE. Parameters are joined with a
// space.
// +optional
KernelParams []string `json:"kernelParams,omitempty"`

// Instance describes instance specific data that is generally unused by Tinkerbell core.
// +optional
Instance *Instance `json:"instance,omitempty"`

// StorageDevices is a list of storage devices that will be available in the OSIE.
// +optional.
StorageDevices []StorageDevice `json:"storageDevices,omitempty"`

// BMCRef references a Rufio Machine object.
// +optional.
BMCRef *corev1.LocalObjectReference `json:"bmcRef,omitempty"`
}

// NetworkInterfaces maps a MAC address to a NetworkInterface.
type NetworkInterfaces map[MAC]NetworkInterface

// NetworkInterface is the desired configuration for a particular network interface.
type NetworkInterface struct {
// DHCP is the basic network information for serving DHCP requests.
DHCP DHCP `json:"dhcp,omitempty"`

// DisableDHCP disables DHCP for this interface. Implies DisableNetboot.
// +kubebuilder:default=false
DisableDHCP bool `json:"disableDhcp,omitempty"`

// DisableNetboot disables netbooting for this interface. The interface will still receive
// network information speified on by DHCP.
// +kubebuilder:default=false
DisableNetboot bool `json:"disableNetboot,omitempty"`
}

// DHCP describes basic network configuration to be served in DHCP OFFER responses. It can be
// considered a DHCP reservation.
type DHCP struct {
// IP is an IPv4 address to serve.
// +kubebuilder:validation:Pattern=`(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`
IP string `json:"ip,omitempty"`

// Netmask is an IPv4 netmask to serve.
// +kubebuilder+validation:Pattern=`^(255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)\.(0|128|192|224|240|248|252|254|255)`
Netmask string `json:"netmask,omitempty"`

// Gateway is the default gateway address to serve.
// +kubebuilder:validation:Pattern=`(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`
// +optional
Gateway *string `json:"gateway,omitempty"`

// +kubebuilder:validation:Pattern=`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9]"[A-Za-z0-9\-]*[A-Za-z0-9])$`
// +optional
Hostname *string `json:"hostname,omitempty"`

// VLANID is a VLAN ID between 0 and 4096.
// +kubebuilder:validation:Pattern=`^(([0-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))(,[1-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))*)$`
// +optional
VLANID *string `json:"vlanId,omitempty"`

// Nameservers to serve.
// +optional
Nameservers []Nameserver `json:"nameservers,omitempty"`

// Timeservers to serve.
// +optional
Timeservers []Timeserver `json:"timeservers,omitempty"`

// LeaseTimeSeconds to serve. 24h default. Maximum equates to max uint32 as defined by RFC 2132
// § 9.2 (https://www.rfc-editor.org/rfc/rfc2132.html#section-9.2).
// +kubebuilder:default=86400
// +kubebuilder:validation:Minimum=0
// +kubebuilder:validation:Maximum=4294967295
// +optional
LeaseTimeSeconds *int64 `json:"leaseTimeSeconds"`
}

// IPXE describes overrides for IPXE scripts. At least 1 option must be specified.
type IPXE struct {
// Content is an inline iPXE script.
// +optional
Content *string `json:"inline,omitempty"`

// URL is a URL to a hosted iPXE script.
// +optional
URL *string `json:"url,omitempty"`
}

// Instance describes instance specific data. Instance specific data is typically dependent on the
// permanent OS that a piece of hardware runs. This data is often served by an instance metadata
// service such as Tinkerbell's Hegel. The core Tinkerbell stack does not leverage this data.
type Instance struct {
// Userdata is data with a structure understood by the producer and consumer of the data.
// +optional
Userdata *string `json:"userdata,omitempty"`

// Vendordata is data with a structure understood by the producer and consumer of the data.
// +optional
Vendordata *string `json:"vendordata,omitempty"`
}

// MAC is a Media Access Control address. MACs must use lower case letters.
// +kubebuilder:validation:Pattern=`^([0-9a-f]{2}:){5}([0-9a-f]{2})$`
type MAC string

// Nameserver is an IP or hostname.
// +kubebuilder:validation:Pattern=`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
type Nameserver string

// Timeserver is an IP or hostname.
// +kubebuilder:validation:Pattern=`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$|^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
type Timeserver string

// StorageDevice describes a storage device path that will be present in the OSIE.
// StorageDevices must be valid Linux paths. They should not contain partitions.
//
// Good
//
// /dev/sda
// /dev/nvme0n1
//
// Bad (contains partitions)
//
// /dev/sda1
// /dev/nvme0n1p1
//
// Bad (invalid Linux path)
//
// \dev\sda
//
// +kubebuilder:validation:Pattern=`^(/[^/ ]*)+/?$`
type StorageDevice string

// +kubebuilder:object:root=true
// +kubebuilder:resource:categories=tinkerbell,path=hardware,shortName=hw
// +kubebuilder:printcolumn:name="BMC",type="string",JSONPath=".spec.bmcRef",description="Baseboard management computer attached to the Hardware"
// +kubebuilder:unservedversion

// Hardware is a logical representation of a machine that can execute Workflows.
type Hardware struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec HardwareSpec `json:"spec,omitempty"`
}

// +kubebuilder:object:root=true

type HardwareList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Hardware `json:"items"`
}

func init() {
SchemeBuilder.Register(&Hardware{}, &HardwareList{})
}
36 changes: 36 additions & 0 deletions api/v1alpha2/osie.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package v1alpha2

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

type OSIESpec struct {
// KernelURL is a URL to a kernel image.
KernelURL string `json:"kernelUrl,omitempty"`

// InitrdURL is a URL to an initrd image.
InitrdURL string `json:"initrdUrl,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:resource:categories=tinkerbell

// OSIE describes an Operating System Installation Environment. It is used by Tinkerbell
// to provision machines and should launch the Tink Worker component.
type OSIE struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec OSIESpec `json:"spec,omitempty"`
}

// +kubebuilder:object:root=true

type OSIEList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OSIE `json:"items"`
}

func init() {
SchemeBuilder.Register(&OSIE{}, &OSIEList{})
}
96 changes: 96 additions & 0 deletions api/v1alpha2/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package v1alpha2

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type TemplateSpec struct {
// Actions defines the set of actions to be run on a target machine. Actions are run sequentially
// in the order they are specified. At least 1 action must be specified. Names of actions
// must be unique within a Template.
// +kubebuilder:validation:MinItems=1
Actions []Action `json:"actions,omitempty"`

// Volumes to be mounted on all actions. If an action specifies the same volume it will take
// precedence.
// +optional
Volumes []Volume `json:"volumes,omitempty"`

// Env defines environment variables to be available in all actions. If an action specifies
// the same environment variable it will take precedence.
// +optional
Env map[string]string `json:"env,omitempty"`
}

// Action defines an individual action to be run on a target machine.
type Action struct {
// Name is a name for the action.
Name string `json:"name"`

// Image is an OCI image.
Image string `json:"image"`

// Cmd defines the command to use when launching the image.
// +optional
Cmd *string `json:"cmd,omitempty"`

// Args are a set of arguments to be passed to the container on launch.
// +optional
Args []string `json:"args,omitempty"`

// Env defines environment variables used when launching the container.
//+optional
Env map[string]string `json:"env,omitempty"`

// Volumes defines the volumes to mount into the container.
// +optional
Volumes []Volume `json:"volumes,omitempty"`

// NetworkNamespace defines the network namespace to run the container in. This enables access
// to the host network namespace.
// See https://man7.org/linux/man-pages/man7/namespaces.7.html.
// +optional
NetworkNamespace *string `json:"networkNamespace,omitempty"`
}

// Volume is a specification for mounting a volume in an action. Volumes take the form
// {SRC-VOLUME-NAME | SRC-HOST-DIR}:TGT-CONTAINER-DIR:OPTIONS. When specifying a VOLUME-NAME that
// does not exist it will be created for you. Examples:
//
// Read-only bind mount bound to /data
//
// /etc/data:/data:ro
//
// Writable volume name bound to /data
//
// shared_volume:/data
//
// See https://docs.docker.com/storage/volumes/ for additional details.
type Volume string

// +kubebuilder:object:root=true
// +kubebuilder:resource:categories=tinkerbell,shortName=tpl
// +kubebuilder:unservedversion

// Template defines a set of actions to be run on a target machine. The template is rendered
// prior to execution where it is exposed to Hardware and user defined data. Most fields within the
// TemplateSpec may contain templates values excluding .TemplateSpec.Actions[].Name.
// See https://pkg.go.dev/text/template for more details.
type Template struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec TemplateSpec `json:"spec,omitempty"`
}

// +kubebuilder:object:root=true

type TemplateList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Template `json:"items"`
}

func init() {
SchemeBuilder.Register(&Template{}, &TemplateList{})
}
Loading