Compare commits

...

37 Commits

Author SHA1 Message Date
mudler
78f2008759 Add netboot type 2022-11-24 18:35:27 +01:00
Ettore Di Giacinto
85adc00f5a Merge pull request #18 from Ognian/master
add --efi-dir option to build-arm-iamge.sh
2022-11-18 11:12:01 +01:00
Ognian
8a9b3e9f71 cp dir content not dir
Signed-off-by: Ognian <Ognian@users.noreply.github.com>
2022-11-16 17:24:57 +01:00
Ognian
78ff22e647 add --efi-dir option to build-arm-iamge.sh
This option allows modification of raspberry pi boot options.
see https://www.raspberrypi.com/documentation/computers/config_txt.html#what-is-config-txt

Signed-off-by: Ognian <Ognian@users.noreply.github.com>
2022-11-16 12:23:56 +01:00
Ettore Di Giacinto
4522e14e32 Merge pull request #17 from Ognian/master
propagate --local to elemental pull-image in build-arm-image.sh
2022-11-14 18:32:50 +01:00
Ognian
097b4a30db Merge pull request #1 from Ognian/Ognian-patch-1
propagate --local to elemental pull-image
2022-11-14 18:21:34 +01:00
Ognian
40560a4b02 propagate --local to elemental pull-image
fixes https://github.com/kairos-io/kairos/issues/419
2022-11-14 18:19:21 +01:00
Ettore Di Giacinto
4997cf18ee Fixup duplicated crd def 2022-11-07 22:25:58 +00:00
Ettore Di Giacinto
7ae1f7105a Add option to build netboot files and disk image size 2022-11-07 22:02:32 +00:00
Ettore Di Giacinto
ebbd1c9a1a Add netboot script 2022-11-07 21:23:20 +00:00
Ettore Di Giacinto
82847a139d ⬆️ Bump elemental-cli 2022-11-07 21:50:30 +01:00
Ettore Di Giacinto
f5611e684f ⬆️ Bump elemental 2022-11-07 19:27:08 +01:00
Ettore Di Giacinto
6b7ae5af02 add bc and qemu-tools 2022-11-05 18:17:22 +00:00
Ettore Di Giacinto
ece128a0b5 Fixup artifact names 2022-11-05 16:26:15 +00:00
Ettore Di Giacinto
4b2be221b3 Add kubesplit target 2022-11-03 23:46:36 +00:00
Ettore Di Giacinto
4f87e2329c Add logic to controller to build disks 2022-11-03 23:42:09 +00:00
Ettore Di Giacinto
dc6fb2c6be Set default menu 2022-11-04 00:22:44 +01:00
Ettore Di Giacinto
dc55928694 Add scripts to generate raw images
See: https://github.com/kairos-io/kairos/issues/377
2022-11-03 22:04:50 +00:00
Ettore Di Giacinto
1f932a7644 Fixup typo 2022-10-26 17:02:05 +02:00
Ettore Di Giacinto
5c9e0a35e4 Create cloud-config dir when preparing ARM, add default config 2022-10-26 11:37:13 +00:00
Ettore Di Giacinto
a2e9c158be Add pinebookpro 2022-10-26 11:21:19 +00:00
Ettore Di Giacinto
0bfe296c53 fix typos 2022-10-24 08:42:14 +00:00
Ettore Di Giacinto
669714d915 Merge pull request #12 from santhoshdaivajna/update_elemental_luet_version
update elemental-cli and luet versions
2022-10-24 10:24:13 +02:00
Ettore Di Giacinto
5e5b3af940 Update tools-image/Dockerfile 2022-10-24 10:23:48 +02:00
Ettore Di Giacinto
ca8065f94b Make GRUBConfig and CloudConfig optional fields 2022-10-24 08:21:12 +00:00
Santhosh
8706980f2b update elemental-cli and luet versions 2022-10-20 11:50:26 +05:30
Ettore Di Giacinto
2309c0f175 🐛 correctly copy artifacts
grub2 artifacts are expected in the grub2 directory
2022-10-19 21:32:01 +02:00
Ettore Di Giacinto
086dbca453 🐛 Copy artifacts from the correct location 2022-10-19 17:24:22 +02:00
Ettore Di Giacinto
658c87a111 Use internal artifacts 2022-10-19 12:53:13 +00:00
Ettore Di Giacinto
6cafc07e65 Update Dockerfile 2022-10-16 11:43:56 +02:00
Ettore Di Giacinto
f4a4829eb0 Add ARM build script in tools-image 2022-10-15 10:01:42 +00:00
Ettore Di Giacinto
92749af928 Add helper to rebake iso with config 2022-10-13 10:37:51 +00:00
Ettore Di Giacinto
44e07e8218 ⬆️ Bump osbuilder packages 2022-10-11 22:41:05 +02:00
Ettore Di Giacinto
4dcfcc4172 Update README.md 2022-09-23 23:07:09 +02:00
mudler
9ce274af56 Use artifacts from the kairos repository in the osbuilder image 2022-09-22 00:04:55 +02:00
Ettore Di Giacinto
ac60a3dc91 🤖 Fixup test 2022-09-19 10:16:50 +00:00
Ettore Di Giacinto
93769cf295 🎨 Rebrand to Kairos
See: https://github.com/kairos-io/kairos/issues/88
2022-09-19 10:06:14 +00:00
50 changed files with 1470 additions and 177 deletions

View File

@@ -18,7 +18,7 @@ jobs:
- name: Prepare
id: prep
run: |
DOCKER_IMAGE=quay.io/c3os/osbuilder
DOCKER_IMAGE=quay.io/kairos/osbuilder
VERSION=latest
SHORTREF=${GITHUB_SHA::8}
# If this is git tag, use the tag name as a docker tag

View File

@@ -18,7 +18,7 @@ jobs:
- name: Prepare
id: prep
run: |
DOCKER_IMAGE=quay.io/c3os/osbuilder-tools
DOCKER_IMAGE=quay.io/kairos/osbuilder-tools
VERSION=latest
SHORTREF=${GITHUB_SHA::8}
# If this is git tag, use the tag name as a docker tag

View File

@@ -4,8 +4,8 @@
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.0.1
IMG ?= quay.io/c3os/osbuilder:test
CLUSTER_NAME?="c3os-osbuilder-e2e"
IMG ?= quay.io/kairos/osbuilder:test
CLUSTER_NAME?="kairos-osbuilder-e2e"
export ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
# CHANNELS define the bundle channels used in the bundle.
@@ -31,8 +31,8 @@ BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
# This variable is used to construct full image tags for bundle and catalog images.
#
# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
# c3os-x.io/osbuilder-operator-bundle:$VERSION and c3os-x.io/osbuilder-operator-catalog:$VERSION.
IMAGE_TAG_BASE ?= c3os-x.io/osbuilder-operator
# kairos.io/osbuilder-bundle:$VERSION and kairos.io/osbuilder-catalog:$VERSION.
IMAGE_TAG_BASE ?= kairos.io/osbuilder
# BUNDLE_IMG defines the image:tag used for the bundle.
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
@@ -276,4 +276,10 @@ unit-tests: test_deps
e2e-tests:
GINKGO=$(GINKGO) KUBE_VERSION=${KUBE_VERSION} $(ROOT_DIR)/script/test.sh
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
kubesplit: manifests kustomize
rm -rf helm-chart
mkdir helm-chart
$(KUSTOMIZE) build config/default | kubesplit -helm helm-chart

17
PROJECT
View File

@@ -1,19 +1,28 @@
domain: c3os-x.io
domain: kairos.io
layout:
- go.kubebuilder.io/v3
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
projectName: osartifactbuilder-operator
repo: github.com/c3os-io/osbuilder-operator
repo: github.com/kairos-io/osbuilder
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: c3os-x.io
domain: kairos.io
group: build
kind: OSArtifact
path: github.com/c3os-io/osbuilder-operator/api/v1alpha1
path: github.com/kairos-io/osbuilder/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: kairos.io
group: build
kind: NetbootDeployment
path: github.com/kairos-io/osbuilder/api/v1alpha1
version: v1alpha1
version: "3"

110
README.md
View File

@@ -1,94 +1,30 @@
# osartifactbuilder-operator
// TODO(user): Add simple overview of use/purpose
# osbuilder
## Description
// TODO(user): An in-depth paragraph about your project and overview of use
| :exclamation: | This is experimental! |
|-|:-|
## Getting Started
Youll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster.
**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows).
This is the Kairos osbuilder Kubernetes Native Extension.
### Running on the cluster
1. Install Instances of Custom Resources:
To install, use helm:
```sh
kubectl apply -f config/samples/
```
# Adds the kairos repo to helm
$ helm repo add kairos https://kairos-io.github.io/helm-charts
"kairos" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "kairos" chart repository
Update Complete. ⎈Happy Helming!⎈
2. Build and push your image to the location specified by `IMG`:
```sh
make docker-build docker-push IMG=<some-registry>/osartifactbuilder-operator:tag
# Install the CRD chart
$ helm install kairos-crd kairos/kairos-crds
NAME: kairos-crd
LAST DEPLOYED: Tue Sep 6 20:35:34 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
# Installs osbuilder
$ helm install kairos-osbuilder kairos/osbuilder
```
3. Deploy the controller to the cluster with the image specified by `IMG`:
```sh
make deploy IMG=<some-registry>/osartifactbuilder-operator:tag
```
### Uninstall CRDs
To delete the CRDs from the cluster:
```sh
make uninstall
```
### Undeploy controller
UnDeploy the controller to the cluster:
```sh
make undeploy
```
## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project
### How it works
This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)
It uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/)
which provides a reconcile function responsible for synchronizing resources untile the desired state is reached on the cluster
### Test It Out
1. Install the CRDs into the cluster:
```sh
make install
```
2. Run your controller (this will run in the foreground, so switch to a new terminal if you want to leave it running):
```sh
make run
```
**NOTE:** You can also run this in one step by running: `make install run`
### Modifying the API definitions
If you are editing the API definitions, generate the manifests such as CRs or CRDs using:
```sh
make manifests
```
**NOTE:** Run `make --help` for more information on all potential `make` targets
More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
## License
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -15,8 +15,8 @@ limitations under the License.
*/
// Package v1alpha1 contains API Schema definitions for the build v1alpha1 API group
//+kubebuilder:object:generate=true
//+groupName=build.c3os-x.io
// +kubebuilder:object:generate=true
// +groupName=build.kairos.io
package v1alpha1
import (
@@ -26,7 +26,7 @@ import (
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "build.c3os-x.io", Version: "v1alpha1"}
GroupVersion = schema.GroupVersion{Group: "build.kairos.io", Version: "v1alpha1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

View File

@@ -0,0 +1,63 @@
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// NetbootDeploymentSpec defines the desired state of NetbootDeployment
type NetbootDeploymentSpec struct {
CloudConfig string `json:"cloudConfig,omitempty"`
CommandLine string `json:"cmdLine,omitempty"`
// TODO: Those below should be deprecated and reference an osbuild instead
}
// NetbootDeploymentStatus defines the observed state of NetbootDeployment
type NetbootDeploymentStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// NetbootDeployment is the Schema for the netbootdeployments API
type NetbootDeployment struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec NetbootDeploymentSpec `json:"spec,omitempty"`
Status NetbootDeploymentStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// NetbootDeploymentList contains a list of NetbootDeployment
type NetbootDeploymentList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []NetbootDeployment `json:"items"`
}
func init() {
SchemeBuilder.Register(&NetbootDeployment{}, &NetbootDeploymentList{})
}

View File

@@ -30,7 +30,18 @@ type OSArtifactSpec struct {
// Foo is an example field of OSArtifact. Edit osartifact_types.go to remove/update
ImageName string `json:"imageName,omitempty"`
ISO bool `json:"iso,omitempty"`
// This needs to be revisited
ISO bool `json:"iso,omitempty"`
//Disk-only stuff
DiskSize string `json:"diskSize,omitempty"`
CloudImage bool `json:"cloudImage,omitempty"`
AzureImage bool `json:"azureImage,omitempty"`
GCEImage bool `json:"gceImage,omitempty"`
Netboot bool `json:"netboot,omitempty"`
NetbootURL string `json:"netbootURL,omitempty"`
// TODO: treat cloudconfig as a secret, and take a secretRef where to store it (optionally)
CloudConfig string `json:"cloudConfig,omitempty"`
GRUBConfig string `json:"grubConfig,omitempty"`

View File

@@ -40,6 +40,95 @@ func (in *LocalObjectReference) DeepCopy() *LocalObjectReference {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetbootDeployment) DeepCopyInto(out *NetbootDeployment) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
out.Status = in.Status
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeployment.
func (in *NetbootDeployment) DeepCopy() *NetbootDeployment {
if in == nil {
return nil
}
out := new(NetbootDeployment)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NetbootDeployment) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetbootDeploymentList) DeepCopyInto(out *NetbootDeploymentList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]NetbootDeployment, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentList.
func (in *NetbootDeploymentList) DeepCopy() *NetbootDeploymentList {
if in == nil {
return nil
}
out := new(NetbootDeploymentList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NetbootDeploymentList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetbootDeploymentSpec) DeepCopyInto(out *NetbootDeploymentSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentSpec.
func (in *NetbootDeploymentSpec) DeepCopy() *NetbootDeploymentSpec {
if in == nil {
return nil
}
out := new(NetbootDeploymentSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetbootDeploymentStatus) DeepCopyInto(out *NetbootDeploymentStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentStatus.
func (in *NetbootDeploymentStatus) DeepCopy() *NetbootDeploymentStatus {
if in == nil {
return nil
}
out := new(NetbootDeploymentStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OSArtifact) DeepCopyInto(out *OSArtifact) {
*out = *in

View File

@@ -5,9 +5,9 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: osartifacts.build.c3os-x.io
name: osartifacts.build.kairos.io
spec:
group: build.c3os-x.io
group: build.kairos.io
names:
kind: OSArtifact
listKind: OSArtifactList
@@ -35,6 +35,8 @@ spec:
spec:
description: OSArtifactSpec defines the desired state of OSArtifact
properties:
azureImage:
type: boolean
bundles:
items:
type: string
@@ -43,6 +45,13 @@ spec:
description: 'TODO: treat cloudconfig as a secret, and take a secretRef
where to store it (optionally)'
type: string
cloudImage:
type: boolean
diskSize:
description: Disk-only stuff
type: string
gceImage:
type: boolean
grubConfig:
type: string
imageName:
@@ -50,7 +59,12 @@ spec:
to remove/update
type: string
iso:
description: This needs to be revisited
type: boolean
netboot:
type: boolean
netbootURL:
type: string
osRelease:
type: string
pull:

View File

@@ -2,18 +2,21 @@
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
- bases/build.c3os-x.io_osartifacts.yaml
- bases/build.kairos.io_osartifacts.yaml
- bases/build.kairos.io_netbootdeployments.yaml
#+kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_osartifacts.yaml
#- patches/webhook_in_netbootdeployments.yaml
#+kubebuilder:scaffold:crdkustomizewebhookpatch
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD
#- patches/cainjection_in_osartifacts.yaml
#- patches/cainjection_in_netbootdeployments.yaml
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
# the following config is for teaching kustomize how to do kustomization for CRDs.

View File

@@ -0,0 +1,7 @@
# The following patch adds a directive for certmanager to inject CA into the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
name: netbootdeployments.build.kairos.io

View File

@@ -4,4 +4,4 @@ kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
name: osartifacts.build.c3os-x.io
name: osartifacts.build.kairos.io

View File

@@ -0,0 +1,16 @@
# The following patch enables a conversion webhook for the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: netbootdeployments.build.kairos.io
spec:
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
namespace: system
name: webhook-service
path: /convert
conversionReviewVersions:
- v1

View File

@@ -2,7 +2,7 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: osartifacts.build.c3os-x.io
name: osartifacts.build.kairos.io
spec:
conversion:
strategy: Webhook

View File

@@ -8,7 +8,7 @@ webhook:
port: 9443
leaderElection:
leaderElect: true
resourceName: 98ca89ca.c3os-x.io
resourceName: 98ca89ca.kairos.io
# leaderElectionReleaseOnCancel defines if the leader should step down volume
# when the Manager ends. This requires the binary to immediately end when the
# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly

View File

@@ -12,5 +12,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
newName: quay.io/c3os/osbuilder
newName: quay.io/kairos/osbuilder
newTag: test

View File

@@ -0,0 +1,24 @@
# permissions for end users to edit netbootdeployments.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: netbootdeployment-editor-role
rules:
- apiGroups:
- build.kairos.io
resources:
- netbootdeployments
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- build.kairos.io
resources:
- netbootdeployments/status
verbs:
- get

View File

@@ -0,0 +1,20 @@
# permissions for end users to view netbootdeployments.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: netbootdeployment-viewer-role
rules:
- apiGroups:
- build.kairos.io
resources:
- netbootdeployments
verbs:
- get
- list
- watch
- apiGroups:
- build.kairos.io
resources:
- netbootdeployments/status
verbs:
- get

View File

@@ -5,7 +5,7 @@ metadata:
name: osartifact-editor-role
rules:
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts
verbs:
@@ -17,7 +17,7 @@ rules:
- update
- watch
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/status
verbs:

View File

@@ -5,7 +5,7 @@ metadata:
name: osartifact-viewer-role
rules:
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts
verbs:
@@ -13,7 +13,7 @@ rules:
- list
- watch
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/status
verbs:

View File

@@ -6,7 +6,7 @@ metadata:
name: manager-role
rules:
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts
verbs:
@@ -18,13 +18,13 @@ rules:
- update
- watch
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/finalizers
verbs:
- update
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/status
verbs:

View File

@@ -6,7 +6,7 @@ metadata:
name: manager-role
rules:
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts
verbs:
@@ -18,13 +18,13 @@ rules:
- update
- watch
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/finalizers
verbs:
- update
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/status
verbs:
@@ -32,7 +32,7 @@ rules:
- patch
- update
- apiGroups:
- build.c3os-x.io
- build.kairos.io
resources:
- osartifacts/finalizers
verbs:

View File

@@ -0,0 +1,6 @@
apiVersion: build.kairos.io/v1alpha1
kind: NetbootDeployment
metadata:
name: netbootdeployment-sample
spec:
# TODO(user): Add fields here

View File

@@ -1,4 +1,4 @@
apiVersion: build.c3os-x.io/v1alpha1
apiVersion: build.kairos.io/v1alpha1
kind: OSArtifact
metadata:
name: osartifact-sample

View File

@@ -1,4 +1,5 @@
## Append samples you want in your CSV to this file as resources ##
resources:
- build_v1alpha1_osartifact.yaml
- build_v1alpha1_netbootdeployment.yaml
#+kubebuilder:scaffold:manifestskustomizesamples

View File

@@ -17,7 +17,7 @@ limitations under the License.
package controllers
import (
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

View File

@@ -19,7 +19,7 @@ package controllers
import (
"fmt"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
@@ -104,7 +104,8 @@ func osReleaseContainer(containerImage string) v1.Container {
}
}
func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact) *appsv1.Deployment {
func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact, svc *v1.Service) *appsv1.Deployment {
// TODO: svc is unused, but could be used in the future to generate the Netboot URL
objMeta := metav1.ObjectMeta{
Name: artifact.Name,
Namespace: artifact.Namespace,
@@ -116,38 +117,134 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
privileged := false
serviceAccount := false
cmd := fmt.Sprintf(
"/entrypoint.sh --debug --name %s build-iso --date=false --output /public dir:/rootfs",
artifact.Name,
)
volumeMounts := []v1.VolumeMount{
{
Name: "public",
MountPath: "/public",
},
{
Name: "rootfs",
MountPath: "/rootfs",
},
}
if artifact.Spec.GRUBConfig != "" {
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: "config",
MountPath: "/iso/iso-overlay/boot/grub2/grub.cfg",
SubPath: "grub.cfg",
})
}
cloudImgCmd := fmt.Sprintf(
"/raw-images.sh /rootfs /public/%s.raw",
artifact.Name,
)
if artifact.Spec.CloudConfig != "" {
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: "config",
MountPath: "/iso/iso-overlay/cloud_config.yaml",
SubPath: "config",
})
cloudImgCmd += " /iso/iso-overlay/cloud_config.yaml"
}
if artifact.Spec.CloudConfig != "" || artifact.Spec.GRUBConfig != "" {
cmd = fmt.Sprintf(
"/entrypoint.sh --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /public dir:/rootfs",
artifact.Name,
)
}
buildIsoContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-iso",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
cmd,
},
VolumeMounts: volumeMounts,
}
buildCloudImageContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-cloud-image",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
cloudImgCmd,
},
VolumeMounts: volumeMounts,
}
if artifact.Spec.DiskSize != "" {
buildCloudImageContainer.Env = []v1.EnvVar{{
Name: "EXTEND",
Value: artifact.Spec.DiskSize,
}}
}
extractNetboot := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-netboot",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Env: []v1.EnvVar{{
Name: "URL",
Value: artifact.Spec.NetbootURL,
}},
Args: []string{
fmt.Sprintf(
"/entrypoint.sh --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /public dir:/rootfs",
"/netboot.sh /public/%s.iso /public/%s",
artifact.Name,
artifact.Name,
),
},
VolumeMounts: []v1.VolumeMount{
{
Name: "public",
MountPath: "/public",
},
{
Name: "config",
MountPath: "/iso/iso-overlay/cloud_config.yaml",
SubPath: "config",
},
{
Name: "config",
MountPath: "/iso/iso-overlay/boot/grub2/grub.cfg",
SubPath: "grub.cfg",
},
{
Name: "rootfs",
MountPath: "/rootfs",
},
VolumeMounts: volumeMounts,
}
buildAzureCloudImageContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-azure-cloud-image",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"/azure.sh /public/%s.raw /public/%s.vhd",
artifact.Name,
artifact.Name,
),
},
VolumeMounts: volumeMounts,
}
buildGCECloudImageContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-gce-cloud-image",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"/gce.sh /public/%s.raw /public/%s.gce.raw",
artifact.Name,
artifact.Name,
),
},
VolumeMounts: volumeMounts,
}
servingContainer := v1.Container{
@@ -195,11 +292,28 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
}
pod.InitContainers = append(pod.InitContainers, buildIsoContainer)
if artifact.Spec.ISO || artifact.Spec.Netboot {
pod.InitContainers = append(pod.InitContainers, buildIsoContainer)
}
if artifact.Spec.Netboot {
pod.InitContainers = append(pod.InitContainers, extractNetboot)
}
if artifact.Spec.CloudImage || artifact.Spec.AzureImage || artifact.Spec.GCEImage {
pod.InitContainers = append(pod.InitContainers, buildCloudImageContainer)
}
if artifact.Spec.AzureImage {
pod.InitContainers = append(pod.InitContainers, buildAzureCloudImageContainer)
}
if artifact.Spec.GCEImage {
pod.InitContainers = append(pod.InitContainers, buildGCECloudImageContainer)
}
if pushImage {
pod.InitContainers = append(pod.InitContainers, createImageContainer(r.ToolImage, artifact.Spec.PushOptions))
}
pod.Containers = []v1.Container{servingContainer}

View File

@@ -0,0 +1,99 @@
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"fmt"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (r *NetbootDeploymentReconciler) genDeployment(artifact buildv1alpha1.NetbootDeployment) *appsv1.Deployment {
// TODO: svc is unused, but could be used in the future to generate the Netboot URL
objMeta := metav1.ObjectMeta{
Name: artifact.Name,
Namespace: artifact.Namespace,
OwnerReferences: genNetbootOwner(artifact),
}
privileged := false
serviceAccount := false
servingContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "serve",
Args: []string{
"boot",
fmt.Sprintf(),
fmt.Sprintf(),
fmt.Sprintf(),
},
Image: r.Image,
VolumeMounts: []v1.VolumeMount{
{
Name: "config",
MountPath: "/files/config.yaml",
SubPath: "cloudconfig",
},
},
}
// boot /files/kairos-core-opensuse-kernel /files/kairos-core-opensuse-initrd --cmdline='rd.neednet=1 ip=dhcp rd.cos.disable root=live:https://github.com/kairos-io/provider-kairos/releases/download/v1.2.0/kairos-alpine-ubuntu-v1.2.0-k3sv1.20.15+k3s1.squashfs netboot nodepair.enable config_url={{ ID "/files/config.yaml" }} console=tty1 console=ttyS0 console=tty0'
pod := v1.PodSpec{
HostNetwork: true,
AutomountServiceAccountToken: &serviceAccount,
Volumes: []v1.Volume{
{
Name: "config",
VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{
LocalObjectReference: v1.LocalObjectReference{Name: fmt.Sprintf("%s-netboot", artifact.Name)}}},
},
},
}
pod.Containers = []v1.Container{servingContainer}
deploymentLabels := genNetDeploymentLabel(artifact.Name)
replicas := int32(1)
return &appsv1.Deployment{
ObjectMeta: objMeta,
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: deploymentLabels},
Replicas: &replicas,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: deploymentLabels,
},
Spec: pod,
},
},
}
}
func genNetDeploymentLabel(s string) map[string]string {
return map[string]string{
"netboot": "serve" + s,
}
}

View File

@@ -0,0 +1,145 @@
/*
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"context"
"fmt"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
)
// NetbootDeploymentReconciler reconciles a NetbootDeployment object
type NetbootDeploymentReconciler struct {
client.Client
clientSet *kubernetes.Clientset
Image string
Scheme *runtime.Scheme
}
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the NetbootDeployment object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
func (r *NetbootDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := log.FromContext(ctx)
var netboot buildv1alpha1.NetbootDeployment
if err := r.Get(ctx, req.NamespacedName, &netboot); err != nil {
if apierrors.IsNotFound(err) {
return ctrl.Result{}, nil
}
return ctrl.Result{}, err
}
logger.Info(fmt.Sprintf("Reconciling %v", netboot))
// generate configmap required for building a custom image
desiredConfigMap := r.genConfigMap(netboot)
logger.Info(fmt.Sprintf("Checking configmap %v", netboot))
cfgMap, err := r.clientSet.CoreV1().ConfigMaps(req.Namespace).Get(ctx, desiredConfigMap.Name, metav1.GetOptions{})
if cfgMap == nil || apierrors.IsNotFound(err) {
logger.Info(fmt.Sprintf("Creating service %v", desiredConfigMap))
cfgMap, err = r.clientSet.CoreV1().ConfigMaps(req.Namespace).Create(ctx, desiredConfigMap, metav1.CreateOptions{})
if err != nil {
logger.Error(err, "Failed while creating cfgmap")
return ctrl.Result{}, err
}
return ctrl.Result{Requeue: true}, err
}
if err != nil {
return ctrl.Result{Requeue: true}, err
}
desiredDeployment := r.genDeployment(netboot)
deployment, err := r.clientSet.AppsV1().Deployments(req.Namespace).Get(ctx, desiredDeployment.Name, metav1.GetOptions{})
if deployment == nil || apierrors.IsNotFound(err) {
logger.Info(fmt.Sprintf("Creating Deployment %v", deployment))
deployment, err = r.clientSet.AppsV1().Deployments(req.Namespace).Create(ctx, desiredDeployment, metav1.CreateOptions{})
if err != nil {
logger.Error(err, "Failed while creating deployment")
return ctrl.Result{}, nil
}
return ctrl.Result{Requeue: true}, nil
}
if err != nil {
return ctrl.Result{Requeue: true}, err
}
// TODO(user): your logic here
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *NetbootDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
clientset, err := kubernetes.NewForConfig(mgr.GetConfig())
if err != nil {
return err
}
r.clientSet = clientset
return ctrl.NewControllerManagedBy(mgr).
For(&buildv1alpha1.NetbootDeployment{}).
Complete(r)
}
func genNetbootOwner(artifact buildv1alpha1.NetbootDeployment) []metav1.OwnerReference {
return []metav1.OwnerReference{
*metav1.NewControllerRef(&artifact.ObjectMeta, schema.GroupVersionKind{
Group: buildv1alpha1.GroupVersion.Group,
Version: buildv1alpha1.GroupVersion.Version,
Kind: "NetbootDeployment",
}),
}
}
func (r *NetbootDeploymentReconciler) genConfigMap(artifact buildv1alpha1.NetbootDeployment) *v1.ConfigMap {
return &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-netboot", artifact.Name),
Namespace: artifact.Namespace,
OwnerReferences: genNetbootOwner(artifact),
},
Data: map[string]string{
"cloudconfig": artifact.Spec.CloudConfig,
}}
}

View File

@@ -21,7 +21,7 @@ import (
"fmt"
"time"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -53,9 +53,9 @@ func genOwner(artifact buildv1alpha1.OSArtifact) []metav1.OwnerReference {
}
}
//+kubebuilder:rbac:groups=build.c3os-x.io,resources=osartifacts,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=build.c3os-x.io,resources=osartifacts/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=build.c3os-x.io,resources=osartifacts/finalizers,verbs=update
//+kubebuilder:rbac:groups=build.kairos.io,resources=osartifacts,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=build.kairos.io,resources=osartifacts/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=build.kairos.io,resources=osartifacts/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
@@ -118,7 +118,7 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
logger.Info(fmt.Sprintf("Checking deployment %v", osbuild))
desiredDeployment := r.genDeployment(osbuild)
desiredDeployment := r.genDeployment(osbuild, svc)
deployment, err := r.clientSet.AppsV1().Deployments(req.Namespace).Get(ctx, desiredDeployment.Name, v1.GetOptions{})
if deployment == nil || apierrors.IsNotFound(err) {
logger.Info(fmt.Sprintf("Creating Deployment %v", deployment))

View File

@@ -17,7 +17,7 @@ limitations under the License.
package controllers
import (
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

View File

@@ -30,7 +30,7 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
//+kubebuilder:scaffold:imports
)

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/c3os-io/osbuilder-operator
module github.com/kairos-io/osbuilder
go 1.18

15
main.go
View File

@@ -31,8 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
"github.com/c3os-io/osbuilder-operator/controllers"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
"github.com/kairos-io/osbuilder/controllers"
//+kubebuilder:scaffold:imports
)
@@ -56,7 +56,7 @@ func main() {
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&serveImage, "serve-image", "nginx", "Serve image.")
// It needs luet inside
flag.StringVar(&toolImage, "tool-image", "quay.io/c3os/osbuilder-tools:latest", "Tool image.")
flag.StringVar(&toolImage, "tool-image", "quay.io/kairos/osbuilder-tools:latest", "Tool image.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
@@ -76,7 +76,7 @@ func main() {
Port: 9443,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "98ca89ca.c3os-x.io",
LeaderElectionID: "98ca89ca.kairos.io",
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
@@ -103,6 +103,13 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
os.Exit(1)
}
if err = (&controllers.NetbootDeploymentReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "NetbootDeployment")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {

View File

@@ -1,7 +1,7 @@
#!/bin/bash
KUBE_VERSION=${KUBE_VERSION:-v1.22.7}
CLUSTER_NAME="${CLUSTER_NAME:-c3os-osbuilder-e2e}"
CLUSTER_NAME="${CLUSTER_NAME:-kairos-osbuilder-e2e}"
if ! kind get clusters | grep "$CLUSTER_NAME"; then
cat << EOF > kind.config

View File

@@ -13,7 +13,7 @@ var _ = Describe("ISO build test", func() {
Context("registration", func() {
AfterEach(func() {
kubectl.New().Delete("osartifacts", "-n", "default", "hello-c3os")
kubectl.New().Delete("osartifacts", "-n", "default", "hello-kairos")
})
It("creates a simple iso", func() {
@@ -21,16 +21,16 @@ var _ = Describe("ISO build test", func() {
Expect(err).ToNot(HaveOccurred())
Eventually(func() string {
b, _ := kubectl.GetData("default", "osartifacts", "hello-c3os", "jsonpath={.spec.imageName}")
b, _ := kubectl.GetData("default", "osartifacts", "hello-kairos", "jsonpath={.spec.imageName}")
return string(b)
}, 2*time.Minute, 2*time.Second).Should(Equal("quay.io/c3os/c3os:opensuse-latest"))
}, 2*time.Minute, 2*time.Second).Should(Equal("quay.io/kairos/core-opensuse:latest"))
Eventually(func() string {
b, _ := kubectl.GetData("default", "deployments", "hello-c3os", "jsonpath={.spec.template.metadata.labels.osbuild}")
b, _ := kubectl.GetData("default", "deployments", "hello-kairos", "jsonpath={.spec.template.metadata.labels.osbuild}")
return string(b)
}, 2*time.Minute, 2*time.Second).Should(Equal("workloadhello-c3os"))
}, 2*time.Minute, 2*time.Second).Should(Equal("workloadhello-kairos"))
Eventually(func() string {
b, _ := kubectl.GetData("default", "deployments", "hello-c3os", "jsonpath={.spec.status.unavailableReplicas}")
b, _ := kubectl.GetData("default", "deployments", "hello-kairos", "jsonpath={.spec.status.unavailableReplicas}")
return string(b)
}, 15*time.Minute, 2*time.Second).ShouldNot(Equal("1"))
})

View File

@@ -9,5 +9,5 @@ import (
func TestE2e(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "c3os-operator e2e test Suite")
RunSpecs(t, "kairos-operator e2e test Suite")
}

View File

@@ -1,12 +1,12 @@
apiVersion: build.c3os-x.io/v1alpha1
apiVersion: build.kairos.io/v1alpha1
kind: OSArtifact
metadata:
name: hello-c3os
name: hello-kairos
spec:
imageName: "quay.io/c3os/c3os:opensuse-latest"
imageName: "quay.io/kairos/core-opensuse:latest"
iso: true
bundles:
- quay.io/c3os/packages:goreleaser-utils-1.11.1
- quay.io/kairos/packages:goreleaser-utils-1.11.1
grubConfig: |
search --file --set=root /boot/kernel.xz
set default=0

View File

@@ -1,23 +1,94 @@
ARG ELEMENTAL_CLI_VERSION=v0.0.15-ae4f000
ARG ELEMENTAL_CLI_VERSION=0.20221107.1
ARG LEAP_VERSION=15.4
ARG LUET_VERSION=0.32.5
FROM quay.io/costoolkit/elemental-cli:$ELEMENTAL_CLI_VERSION AS elemental
ARG LUET_VERSION=0.33.0
FROM quay.io/kairos/packages:elemental-cli-system-$ELEMENTAL_CLI_VERSION AS elemental
FROM quay.io/luet/base:$LUET_VERSION AS luet
FROM quay.io/costoolkit/releases-teal:grub2-live-0.0.3-2 AS grub2
FROM quay.io/costoolkit/releases-teal:grub2-efi-image-live-0.0.2-2 AS efi
### TODO: Replace those naked Dockerfiles copies with luet install so we can keep track of all versioning with 1 repository tag
### 1) Add the kairos repository with a reference
### 2) populate folders accordingly
## amd64 Live CD artifacts
FROM quay.io/kairos/packages:grub2-livecd-0.0.4 AS grub2
FROM quay.io/kairos/packages:grub2-efi-image-livecd-0.0.4 AS efi
## RPI64
## Firmware is in the amd64 repo (noarch)
FROM quay.io/kairos/packages:u-boot-rpi64-firmware-2021.01-5.1 AS rpi-u-boot
FROM quay.io/kairos/packages:raspberrypi-firmware-firmware-2021.03.10-2.1 AS rpi-firmware
FROM quay.io/kairos/packages:raspberrypi-firmware-config-firmware-2021.03.10-2.1 AS rpi-firmware-config
FROM quay.io/kairos/packages:raspberrypi-firmware-dt-firmware-2021.03.15-2.1 AS rpi-firmware-dt
## PineBook64 Pro
FROM quay.io/kairos/packages:u-boot-rockchip-arm-vendor-blob-0.1 AS pinebook-u-boot
## Generic ARM artifacts
FROM quay.io/kairos/packages-arm64:grub-efi-static-0.1 AS grub-efi
FROM quay.io/kairos/packages-arm64:grub-config-static-0.1 AS grub-config
FROM quay.io/kairos/packages-arm64:grub-artifacts-static-0.1 AS grub-artifacts
## RAW images
FROM quay.io/kairos/packages:grub-efi-static-0.1 AS grub-raw-efi
FROM quay.io/kairos/packages:grub-config-static-0.1 AS grub-raw-config
FROM quay.io/kairos/packages:grub-artifacts-static-0.1 AS grub-raw-artifacts
FROM opensuse/leap:$LEAP_VERSION
COPY --from=elemental /usr/bin/elemental /usr/bin/elemental
COPY --from=luet /usr/bin/luet /usr/bin/luet
# x86_64 ISOs
COPY --from=grub2 / /grub2
COPY --from=efi / /efi
# RAW images
COPY --from=grub-raw-efi / /raw/grub
COPY --from=grub-raw-config / /raw/grubconfig
COPY --from=grub-raw-artifacts / /raw/grubartifacts
# RPI64
COPY --from=rpi-u-boot / /rpi/u-boot
COPY --from=rpi-firmware / /rpi/rpi-firmware
COPY --from=rpi-firmware-config / /rpi/rpi-firmware-config
COPY --from=rpi-firmware-dt / /rpi/rpi-firmware-dt
# Pinebook
COPY --from=pinebook-u-boot / /pinebookpro/u-boot
# Generic
COPY --from=grub-efi / /arm/grub/efi
COPY --from=grub-config / /arm/grub/config
COPY --from=grub-artifacts / /arm/grub/artifacts
RUN zypper ref && zypper dup -y
RUN zypper ref && zypper in -y xfsprogs parted util-linux-systemd e2fsprogs util-linux udev rsync grub2 dosfstools grub2-x86_64-efi squashfs mtools xorriso lvm2
## ISO Build depedencies
RUN zypper ref && zypper in -y xfsprogs parted util-linux-systemd e2fsprogs curl util-linux udev rsync grub2 dosfstools grub2-x86_64-efi squashfs mtools xorriso lvm2
RUN mkdir /config
# Arm image build deps
RUN zypper in -y jq docker git curl gptfdisk kpartx sudo
# Netboot
RUN zypper in -y cdrtools
# cloud images
RUN zypper in -y bc qemu-tools
# ISO build config
COPY ./config.yaml /config/manifest.yaml
COPY ./entrypoint.sh /entrypoint.sh
COPY ./add-cloud-init.sh /add-cloud-init.sh
ENTRYPOINT [ "/entrypoint.sh" ]
# ARM helpers
COPY ./build-arm-image.sh /build-arm-image.sh
COPY ./arm /arm
# RAW images helpers
COPY ./gce.sh /gce.sh
COPY ./raw-images.sh /raw-images.sh
COPY ./azure.sh /azure.sh
COPY ./netboot.sh /netboot.sh
COPY defaults.yaml /defaults.yaml
ENTRYPOINT [ "/entrypoint.sh" ]

18
tools-image/add-cloud-init.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
# docker run --entrypoint /add-cloud-init.sh -v $PWD:/work -ti --rm test https://github.com/kairos-io/kairos/releases/download/v1.1.2/kairos-alpine-v1.1.2.iso /work/test.iso /work/config.yaml
set -ex
ISO=$1
OUT=$2
CONFIG=$3
case ${ISO} in
http*)
curl -L "${ISO}" -o in.iso
ISO=in.iso
;;
esac
# Needs xorriso >=1.5.4
xorriso -indev $ISO -outdev $OUT -map $CONFIG /config.yaml -boot_image any replay

View File

@@ -0,0 +1,21 @@
#!/bin/bash
image=$1
if [ -z "$image" ]; then
echo "No image specified"
exit 1
fi
if [ ! -e "$WORKDIR/luet.yaml" ]; then
ls -liah $WORKDIR
echo "No valid config file"
cat "$WORKDIR/luet.yaml"
exit 1
fi
sudo luet install --config $WORKDIR/luet.yaml -y --system-target $WORKDIR firmware/odroid-c2
# conv=notrunc ?
dd if=$WORKDIR/bl1.bin.hardkernel of=$image conv=fsync bs=1 count=442
dd if=$WORKDIR/bl1.bin.hardkernel of=$image conv=fsync bs=512 skip=1 seek=1
dd if=$WORKDIR/u-boot.odroidc2 of=$image conv=fsync bs=512 seek=97

View File

@@ -0,0 +1,19 @@
#!/bin/bash
image=$1
if [ -z "$image" ]; then
echo "No image specified"
exit 1
fi
LOADER_OFFSET=${LOADER_OFFSET:-"64"}
LOADER_IMAGE=${LOADER_IMAGE:-"idbloader.img"}
UBOOT_IMAGE=${UBOOT_IMAGE:-"u-boot.itb"}
UBOOT_OFFSET=${UBOOT_OFFSET:-"16384"}
echo "Writing idbloader"
dd conv=notrunc if=/pinebookpro/u-boot/usr/lib/u-boot/pinebook-pro-rk3399/${LOADER_IMAGE} of="$image" conv=fsync seek=${LOADER_OFFSET}
echo "Writing u-boot image"
dd conv=notrunc if=/pinebookpro/u-boot/usr/lib/u-boot/pinebook-pro-rk3399/${UBOOT_IMAGE} of="$image" conv=fsync seek=${UBOOT_OFFSET}
sync $image

24
tools-image/arm/boards/rpi64.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
partprobe
kpartx -va $DRIVE
image=$1
if [ -z "$image" ]; then
echo "No image specified"
exit 1
fi
set -ax
TEMPDIR="$(mktemp -d)"
echo $TEMPDIR
mount "${device}p1" "${TEMPDIR}"
for dir in /rpi/u-boot /rpi/rpi-firmware /rpi/rpi-firmware-config /rpi/rpi-firmware-dt
do
cp -rfv ${dir}/* $TEMPDIR
done
umount "${TEMPDIR}"

17
tools-image/azure.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
# Transform a raw image disk to azure vhd
RAWIMAGE="$1"
VHDDISK="${2:-disk.vhd}"
cp -rf $RAWIMAGE $VHDDISK.work
MB=$((1024*1024))
size=$(qemu-img info -f raw --output json "$RAWIMAGE" | gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}')
# shellcheck disable=SC2004
ROUNDED_SIZE=$(((($size+$MB-1)/$MB)*$MB))
echo "Resizing raw image to $ROUNDED_SIZE"
qemu-img resize -f raw "$VHDDISK.work" $ROUNDED_SIZE
echo "Converting $RAWIMAGE to $VHDDISK"
qemu-img convert -f raw -o subformat=fixed,force_size -O vpc "$VHDDISK.work" "$VHDDISK"
echo "Done"
rm -rf "$VHDDISK.work"

426
tools-image/build-arm-image.sh Executable file
View File

@@ -0,0 +1,426 @@
#!/bin/bash
## This is a re-adaptation of https://github.com/rancher/elemental-toolkit/blob/main/images/arm-img-builder.sh
set -ex
load_vars() {
model=${MODEL:-odroid_c2}
directory=${DIRECTORY:-}
output_image="${OUTPUT_IMAGE:-arm.img}"
# Img creation options. Size is in MB for all of the vars below
size="${SIZE:-7544}"
state_size="${STATE_SIZE:-4992}"
recovery_size="${RECOVERY_SIZE:-2192}"
default_active_size="${DEFAULT_ACTIVE_SIZE:-2400}"
## Repositories
final_repo="${FINAL_REPO:-quay.io/costoolkit/releases-teal-arm64}"
repo_type="${REPO_TYPE:-docker}"
# Warning: these default values must be aligned with the values provided
# in 'packages/cos-config/cos-config', provide an environment file using the
# --cos-config flag if different values are needed.
: "${OEM_LABEL:=COS_OEM}"
: "${RECOVERY_LABEL:=COS_RECOVERY}"
: "${ACTIVE_LABEL:=COS_ACTIVE}"
: "${PASSIVE_LABEL:=COS_PASSIVE}"
: "${PERSISTENT_LABEL:=COS_PERSISTENT}"
: "${SYSTEM_LABEL:=COS_SYSTEM}"
: "${STATE_LABEL:=COS_STATE}"
}
cleanup() {
sync
sync
sleep 5
sync
if [ -n "$EFI" ]; then
rm -rf $EFI
fi
if [ -n "$RECOVERY" ]; then
rm -rf $RECOVERY
fi
if [ -n "$STATEDIR" ]; then
rm -rf $STATEDIR
fi
if [ -n "$TARGET" ]; then
umount $TARGET || true
umount $LOOP || true
rm -rf $TARGET
fi
if [ -n "$WORKDIR" ]; then
rm -rf $WORKDIR
fi
if [ -n "$DRIVE" ]; then
umount $DRIVE || true
fi
if [ -n "$recovery" ]; then
umount $recovery || true
fi
if [ -n "$state" ]; then
umount $state || true
fi
if [ -n "$efi" ]; then
umount $efi || true
fi
if [ -n "$oem" ]; then
umount $oem || true
fi
losetup -D || true
}
ensure_dir_structure() {
local target=$1
for mnt in /sys /proc /dev /tmp /boot /usr/local /oem
do
if [ ! -d "${target}${mnt}" ]; then
mkdir -p ${target}${mnt}
fi
done
}
usage()
{
echo "Usage: $0 [options] image.img"
echo ""
echo "Example: $0 --cos-config cos-config --model odroid-c2 --docker-image <image> output.img"
echo ""
echo "Flags:"
echo " --cos-config: (optional) Specifies a cos-config file for required environment variables"
echo " --config: (optional) Specify a cloud-init config file to embed into the final image"
echo " --manifest: (optional) Specify a manifest file to customize efi/grub packages installed into the image"
echo " --size: (optional) Image size (MB)"
echo " --state-partition-size: (optional) Size of the state partition (MB)"
echo " --recovery-partition-size: (optional) Size of the recovery partition (MB)"
echo " --images-size: (optional) Size of the active/passive/recovery images (MB)"
echo " --docker-image: (optional) A container image which will be used for active/passive/recovery system"
echo " --local: (optional) Use local repository when building"
echo " --directory: (optional) A directory which will be used for active/passive/recovery system"
echo " --model: (optional) The board model"
echo " --efi-dir: (optional) A directory with files which will be added to the efi partition"
exit 1
}
get_url()
{
FROM=$1
TO=$2
case $FROM in
ftp*|http*|tftp*)
n=0
attempts=5
until [ "$n" -ge "$attempts" ]
do
curl -o $TO -fL ${FROM} && break
n=$((n+1))
echo "Failed to download, retry attempt ${n} out of ${attempts}"
sleep 2
done
;;
*)
cp -f $FROM $TO
;;
esac
}
trap "cleanup" 1 2 3 6 9 14 15 EXIT
load_vars
while [ "$#" -gt 0 ]; do
case $1 in
--cos-config)
shift 1
cos_config=$1
;;
--config)
shift 1
config=$1
;;
--manifest)
shift 1
manifest=$1
;;
--size)
shift 1
size=$1
;;
--local)
local_build=true
;;
--state-partition-size)
shift 1
state_size=$1
;;
--recovery-partition-size)
shift 1
recovery_size=$1
;;
--images-size)
shift 1
default_active_size=$1
;;
--docker-image)
shift 1
CONTAINER_IMAGE=$1
;;
--directory)
shift 1
directory=$1
;;
--model)
shift 1
model=$1
;;
--efi-dir)
shift 1
efi_dir=$1
;;
--final-repo)
shift 1
final_repo=$1
;;
--repo-type)
shift 1
repo_type=$1
;;
-h)
usage
;;
--help)
usage
;;
*)
if [ "$#" -gt 2 ]; then
usage
fi
output_image=$1
break
;;
esac
shift 1
done
if [ "$model" == "rpi64" ]; then
container_image=${CONTAINER_IMAGE:-quay.io/costoolkit/examples:rpi-latest}
else
# Odroid C2 image contains kernel-default-extra, might have broader support
container_image=${CONTAINER_IMAGE:-quay.io/costoolkit/examples:odroid-c2-latest}
fi
if [ -n "$cos_config"] && [ -e "$cos_config" ]; then
source "$cos_config"
fi
if [ -z "$output_image" ]; then
echo "No image file specified"
exit 1
fi
if [ -n "$manifest" ]; then
YQ_PACKAGES_COMMAND=(yq e -o=json "$manifest")
final_repo=${final_repo:-$(yq e ".raw_disk.$model.repo" "${manifest}")}
fi
echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
echo "Image Size: $size MB."
echo "Recovery Partition: $recovery_size."
echo "State Partition: $state_size MB."
echo "Images size (active/passive/recovery.img): $default_active_size MB."
echo "Model: $model"
if [ -n "$container_image" ] && [ -z "$directory" ]; then
echo "Container image: $container_image"
fi
if [ -n "$directory" ]; then
echo "Root from directory: $directory"
fi
echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
# Temp dir used during build
WORKDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
#ROOT_DIR=$(git rev-parse --show-toplevel)
TARGET=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
STATEDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
export WORKDIR
# Prepare active.img
echo ">> Preparing active.img"
mkdir -p ${STATEDIR}/cOS
dd if=/dev/zero of=${STATEDIR}/cOS/active.img bs=1M count=$default_active_size
mkfs.ext2 ${STATEDIR}/cOS/active.img -L ${ACTIVE_LABEL}
sync
LOOP=$(losetup --show -f ${STATEDIR}/cOS/active.img)
if [ -z "$LOOP" ]; then
echo "No device"
exit 1
fi
mount -t ext2 $LOOP $TARGET
ensure_dir_structure $TARGET
# Download the container image
if [ -z "$directory" ]; then
echo ">>> Downloading container image"
elemental pull-image $( (( $local_build == 'true')) && printf %s '--local' ) $container_image $TARGET
else
echo ">>> Copying files from $directory"
rsync -axq --exclude='host' --exclude='mnt' --exclude='proc' --exclude='sys' --exclude='dev' --exclude='tmp' ${directory}/ $TARGET
fi
umount $TARGET
sync
if [ -n "$LOOP" ]; then
losetup -d $LOOP
fi
echo ">> Preparing passive.img"
cp -rfv ${STATEDIR}/cOS/active.img ${STATEDIR}/cOS/passive.img
tune2fs -L ${PASSIVE_LABEL} ${STATEDIR}/cOS/passive.img
# Preparing recovery
echo ">> Preparing recovery.img"
RECOVERY=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
if [ -z "$RECOVERY" ]; then
echo "No recovery directory"
exit 1
fi
mkdir -p ${RECOVERY}/cOS
cp -rfv ${STATEDIR}/cOS/active.img ${RECOVERY}/cOS/recovery.img
tune2fs -L ${SYSTEM_LABEL} ${RECOVERY}/cOS/recovery.img
# Install real grub config to recovery
cp -rfv /arm/grub/config/* $RECOVERY
mkdir -p $RECOVERY/grub2
cp -rfv /arm/grub/artifacts/* $RECOVERY/grub2
sync
# Prepare efi files
echo ">> Preparing EFI partition"
EFI=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
if [ -z "$EFI" ]; then
echo "No EFI directory"
exit 1
fi
cp -rfv /arm/grub/efi/* $EFI
if [ -n "$EFI" ] && [ -n "$efi_dir" ]; then
echo "Copy $efi_dir to EFI directory"
cp -rfv $efi_dir/* $EFI
fi
echo ">> Writing image and partition table"
dd if=/dev/zero of="${output_image}" bs=1024000 count="${size}" || exit 1
if [ "$model" == "rpi64" ]; then
sgdisk -n 1:8192:+96M -c 1:EFI -t 1:0c00 ${output_image}
else
sgdisk -n 1:8192:+16M -c 1:EFI -t 1:0700 ${output_image}
fi
sgdisk -n 2:0:+${state_size}M -c 2:state -t 2:8300 ${output_image}
sgdisk -n 3:0:+${recovery_size}M -c 3:recovery -t 3:8300 ${output_image}
sgdisk -n 4:0:+64M -c 4:persistent -t 4:8300 ${output_image}
sgdisk -m 1:2:3:4 ${output_image}
if [ "$model" == "rpi64" ]; then
sfdisk --part-type ${output_image} 1 c
fi
# Prepare the image and copy over the files
export DRIVE=$(losetup -f "${output_image}" --show)
if [ -z "${DRIVE}" ]; then
echo "Cannot execute losetup for $output_image"
exit 1
fi
device=${DRIVE/\/dev\//}
if [ -z "$device" ]; then
echo "No device"
exit 1
fi
export device="/dev/mapper/${device}"
partprobe
kpartx -va $DRIVE
echo ">> Populating partitions"
efi=${device}p1
state=${device}p2
recovery=${device}p3
persistent=${device}p4
# Create partitions (RECOVERY, STATE, COS_PERSISTENT)
mkfs.vfat -F 32 ${efi}
fatlabel ${efi} COS_GRUB
mkfs.ext4 -F -L ${RECOVERY_LABEL} $recovery
mkfs.ext4 -F -L ${STATE_LABEL} $state
mkfs.ext4 -F -L ${PERSISTENT_LABEL} $persistent
mkdir $WORKDIR/state
mkdir $WORKDIR/recovery
mkdir $WORKDIR/efi
mount $recovery $WORKDIR/recovery
mount $state $WORKDIR/state
mount $efi $WORKDIR/efi
mkdir $WORKDIR/persistent
mount $persistent $WORKDIR/persistent
mkdir -p $WORKDIR/persistent/cloud-config
cp -rfv /defaults.yaml $WORKDIR/persistent/cloud-config/01_defaults.yaml
grub2-editenv $WORKDIR/state/grub_oem_env set "default_menu_entry=Kairos"
# Set a OEM config file if specified
if [ -n "$config" ]; then
echo ">> Copying $config OEM config file"
get_url $config $WORKDIR/persistent/cloud-config/99_custom.yaml
fi
umount $WORKDIR/persistent
# Copy over content
cp -arf $EFI/* $WORKDIR/efi
cp -arf $RECOVERY/* $WORKDIR/recovery
cp -arf $STATEDIR/* $WORKDIR/state
umount $WORKDIR/recovery
umount $WORKDIR/state
umount $WORKDIR/efi
sync
# Flash uboot and vendor-specific bits
echo ">> Performing $model specific bits.."
/arm/boards/$model.sh ${DRIVE}
kpartx -dv $DRIVE
umount $DRIVE || true
echo ">> Done writing $output_image"
echo ">> Creating SHA256 sum"
sha256sum $output_image > $output_image.sha256
cleanup

View File

@@ -0,0 +1,8 @@
name: "Default user"
stages:
initramfs:
- name: "Set default user/pass"
users:
kairos:
passwd: "kairos"

15
tools-image/gce.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Transform a raw image disk to gce compatible
RAWIMAGE="$1"
OUT="${2:-$RAWIMAGE.gce.raw}"
cp -rf $RAWIMAGE $OUT
GB=$((1024*1024*1024))
size=$(qemu-img info -f raw --output json "$OUT" | gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}')
# shellcheck disable=SC2004
ROUNDED_SIZE=$(echo "$size/$GB+1"|bc)
echo "Resizing raw image from \"$size\"MB to \"$ROUNDED_SIZE\"GB"
qemu-img resize -f raw "$OUT" "$ROUNDED_SIZE"G
echo "Compressing raw image $OUT to $OUT.tar.gz"
tar -c -z --format=oldgnu -f "$OUT".tar.gz $OUT

25
tools-image/netboot.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# Extracts squashfs, kernel, initrd and generates a ipxe template script
ISO=$1
OUTPUT_NAME=$2
ARTIFACT_NAME=$(basename $OUTPUT_NAME)
isoinfo -x /rootfs.squashfs -R -i $ISO > $OUTPUT_NAME.squashfs
isoinfo -x /boot/kernel -R -i $ISO > $OUTPUT_NAME-kernel
isoinfo -x /boot/initrd -R -i $ISO > $OUTPUT_NAME-initrd
URL=${URL:-https://github.com/kairos-io/kairos/releases/download}
cat > $OUTPUT_NAME.ipxe << EOF
#!ipxe
set url ${URL}/
set kernel $ARTIFACT_NAME-kernel
set initrd $ARTIFACT_NAME-initrd
set rootfs $ARTIFACT_NAME.squashfs
# set config https://example.com/machine-config
# set cmdline extra.values=1
kernel \${url}/\${kernel} initrd=\${initrd} ip=dhcp rd.cos.disable root=live:\${url}/\${rootfs} netboot nodepair.enable config_url=\${config} console=tty1 console=ttyS0 \${cmdline}
initrd \${url}/\${initrd}
boot
EOF

79
tools-image/raw-images.sh Executable file
View File

@@ -0,0 +1,79 @@
#!/bin/bash
# Generates EFI bootable images (statically)
# This is a re-adaptation of https://github.com/rancher/elemental-toolkit/blob/v0.8.10-1/images/img-builder.sh, which was dropped
# How to use:
# First extract the image which you want to create an image from:
### luet util unpack <image> rootfs
# Then convert it to a raw disk (EFI only):
### docker run -v $PWD:/output --entrypoint /raw-images.sh -ti --rm test-image /output/rootfs /output/foo.raw cloud-init.yaml
: "${OEM_LABEL:=COS_OEM}"
: "${RECOVERY_LABEL:=COS_RECOVERY}"
: "${EXTEND:=}"
DIRECTORY=$1
OUT=${2:-disk.raw}
CONFIG=$3
echo "Output: $OUT"
set -e
mkdir -p /build/root/grub2
mkdir /build/root/cOS
mkdir /build/efi
cp -rf /raw/grub/* /build/efi
cp -rf /raw/grubconfig/* /build/root
cp -rf /raw/grubartifacts/* /build/root/grub2
echo "Generating squashfs from $DIRECTORY"
mksquashfs $DIRECTORY recovery.squashfs -b 1024k -comp xz -Xbcj x86
mv recovery.squashfs /build/root/cOS/recovery.squashfs
grub2-editenv /build/root/grub_oem_env set "default_menu_entry=Kairos"
# Create a 2GB filesystem for RECOVERY including the contents for root (grub config and squasfs container)
truncate -s $((2048*1024*1024)) rootfs.part
mkfs.ext2 -L "${RECOVERY_LABEL}" -d /build/root rootfs.part
# Create the EFI partition FAT16 and include the EFI image and a basic grub.cfg
truncate -s $((20*1024*1024)) efi.part
mkfs.fat -F16 -n COS_GRUB efi.part
mcopy -s -i efi.part /build/efi/EFI ::EFI
# Create the grubenv forcing first boot to be on recovery system
mkdir -p /build/oem
cp /build/root/etc/cos/grubenv_firstboot /build/oem/grubenv
if [ -n "$CONFIG" ]; then
echo "Copying config file ($CONFIG)"
cp $CONFIG /build/oem
fi
# Create a 64MB filesystem for OEM volume
truncate -s $((64*1024*1024)) oem.part
mkfs.ext2 -L "${OEM_LABEL}" -d /build/oem oem.part
echo "Generating image $OUT"
# Create disk image, add 3MB of initial free space to disk, 1MB is for proper alignement, 2MB are for the hybrid legacy boot.
truncate -s $((3*1024*1024)) $OUT
{
cat efi.part
cat oem.part
cat rootfs.part
} >> $OUT
# Add an extra MB at the end of the disk for the gpt headers, in fact 34 sectors would be enough, but adding some more does not hurt.
truncate -s "+$((1024*1024))" $OUT
if [ -n "$EXTEND" ]; then
echo "Extending image of $EXTEND MB"
truncate -s "+$(($EXTEND*1024*1024))" $OUT
fi
# Create the partition table in $OUT (assumes sectors of 512 bytes)
sgdisk -n 1:2048:+2M -c 1:legacy -t 1:EF02 $OUT
sgdisk -n 2:0:+20M -c 2:UEFI -t 2:EF00 $OUT
sgdisk -n 3:0:+64M -c 3:oem -t 3:8300 $OUT
sgdisk -n 4:0:+2048M -c 4:root -t 4:8300 $OUT