Compare commits

..

1 Commits

Author SHA1 Message Date
mudler
3cb37cd1c9 WIP 2022-09-06 18:46:27 +02:00
39 changed files with 216 additions and 975 deletions

View File

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

View File

@@ -1,19 +0,0 @@
---
name: 'test'
on:
push:
branches:
- master
tags:
- '*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Test
run: |
make kind-e2e-tests

View File

@@ -1,63 +0,0 @@
---
name: 'build tools container images'
on:
push:
branches:
- master
tags:
- '*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Prepare
id: prep
run: |
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
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/}
fi
TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:${SHORTREF}"
# If the VERSION looks like a version number, assume that
# this is the most recent version of the image and also
# tag it 'latest'.
if [[ $VERSION =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
TAGS="$TAGS,${DOCKER_IMAGE}:latest"
fi
# Set output parameters.
echo ::set-output name=tags::${TAGS}
echo ::set-output name=docker_image::${DOCKER_IMAGE}
- name: Set up QEMU
uses: docker/setup-qemu-action@master
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@master
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build
uses: docker/build-push-action@v2
with:
builder: ${{ steps.buildx.outputs.name }}
context: ./tools-image
file: ./tools-image/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.prep.outputs.tags }}

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/kairos/osbuilder:test
CLUSTER_NAME?="kairos-osbuilder-e2e"
IMG ?= quay.io/c3os/osbuilder:test
CLUSTER_NAME?="c3os-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
# kairos.io/osbuilder-bundle:$VERSION and kairos.io/osbuilder-catalog:$VERSION.
IMAGE_TAG_BASE ?= kairos.io/osbuilder
# c3os-x.io/osbuilder-operator-bundle:$VERSION and c3os-x.io/osbuilder-operator-catalog:$VERSION.
IMAGE_TAG_BASE ?= c3os-x.io/osbuilder-operator
# 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>)
@@ -172,7 +172,6 @@ $(LOCALBIN):
## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
GINKGO ?= $(LOCALBIN)/ginkgo
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
@@ -191,10 +190,6 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
$(CONTROLLER_GEN): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
ginkgo: $(GINKGO) ## Download ginkgo locally if necessary.
$(GINKGO): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
@@ -271,9 +266,9 @@ test_deps:
.PHONY: unit-tests
unit-tests: test_deps
$(GINKGO) -r -v --covermode=atomic --coverprofile=coverage.out -p -r ./pkg/...
ginkgo -r -v --covermode=atomic --coverprofile=coverage.out -p -r ./pkg/...
e2e-tests:
GINKGO=$(GINKGO) KUBE_VERSION=${KUBE_VERSION} $(ROOT_DIR)/script/test.sh
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: kind-setup install undeploy-dev deploy-dev e2e-tests

View File

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

110
README.md
View File

@@ -1,30 +1,94 @@
# osbuilder
# osartifactbuilder-operator
// TODO(user): Add simple overview of use/purpose
| :exclamation: | This is experimental! |
|-|:-|
## Description
// TODO(user): An in-depth paragraph about your project and overview of use
This is the Kairos osbuilder Kubernetes Native Extension.
## 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).
To install, use helm:
### Running on the cluster
1. Install Instances of Custom Resources:
```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!⎈
# 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
2. Build and push your image to the location specified by `IMG`:
```sh
make docker-build docker-push IMG=<some-registry>/osartifactbuilder-operator:tag
```
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.kairos.io
//+kubebuilder:object:generate=true
//+groupName=build.c3os-x.io
package v1alpha1
import (
@@ -26,7 +26,7 @@ import (
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "build.kairos.io", Version: "v1alpha1"}
GroupVersion = schema.GroupVersion{Group: "build.c3os-x.io", Version: "v1alpha1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

View File

@@ -36,9 +36,8 @@ type OSArtifactSpec struct {
GRUBConfig string `json:"grubConfig,omitempty"`
Bundles []string `json:"bundles,omitempty"`
PullOptions Pull `json:"pull,omitempty"`
OSRelease string `json:"osRelease,omitempty"`
PushOptions Push `json:"push,omitempty"`
PullOptions *Pull `json:"pull,omitempty"`
PushOptions *Push `json:"push,omitempty"`
}
type Push struct {

View File

@@ -25,27 +25,12 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LocalObjectReference) DeepCopyInto(out *LocalObjectReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalObjectReference.
func (in *LocalObjectReference) DeepCopy() *LocalObjectReference {
if in == nil {
return nil
}
out := new(LocalObjectReference)
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
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Spec = in.Spec
out.Status = in.Status
}
@@ -102,13 +87,6 @@ func (in *OSArtifactList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OSArtifactSpec) DeepCopyInto(out *OSArtifactSpec) {
*out = *in
if in.Bundles != nil {
in, out := &in.Bundles, &out.Bundles
*out = make([]string, len(*in))
copy(*out, *in)
}
in.PullOptions.DeepCopyInto(&out.PullOptions)
in.PushOptions.DeepCopyInto(&out.PushOptions)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OSArtifactSpec.
@@ -135,59 +113,3 @@ func (in *OSArtifactStatus) DeepCopy() *OSArtifactStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Pull) DeepCopyInto(out *Pull) {
*out = *in
if in.ContainerRegistryCredentials != nil {
in, out := &in.ContainerRegistryCredentials, &out.ContainerRegistryCredentials
*out = new(SecretKeySelector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pull.
func (in *Pull) DeepCopy() *Pull {
if in == nil {
return nil
}
out := new(Pull)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Push) DeepCopyInto(out *Push) {
*out = *in
if in.ContainerRegistryCredentials != nil {
in, out := &in.ContainerRegistryCredentials, &out.ContainerRegistryCredentials
*out = new(SecretKeySelector)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Push.
func (in *Push) DeepCopy() *Push {
if in == nil {
return nil
}
out := new(Push)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
*out = *in
out.LocalObjectReference = in.LocalObjectReference
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
if in == nil {
return nil
}
out := new(SecretKeySelector)
in.DeepCopyInto(out)
return out
}

View File

@@ -5,9 +5,9 @@ metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: osartifacts.build.kairos.io
name: osartifacts.build.c3os-x.io
spec:
group: build.kairos.io
group: build.c3os-x.io
names:
kind: OSArtifact
listKind: OSArtifactList
@@ -35,10 +35,6 @@ spec:
spec:
description: OSArtifactSpec defines the desired state of OSArtifact
properties:
bundles:
items:
type: string
type: array
cloudConfig:
description: 'TODO: treat cloudconfig as a secret, and take a secretRef
where to store it (optionally)'
@@ -51,40 +47,8 @@ spec:
type: string
iso:
type: boolean
osRelease:
type: string
pull:
properties:
containerRegistryCredentials:
properties:
key:
type: string
name:
type: string
namespace:
type: string
required:
- name
type: object
type: object
push:
properties:
containerRegistryCredentials:
properties:
key:
type: string
name:
type: string
namespace:
type: string
required:
- name
type: object
imageName:
type: string
push:
type: boolean
type: object
pullFromKube:
type: boolean
type: object
status:
description: OSArtifactStatus defines the observed state of OSArtifact

View File

@@ -2,7 +2,7 @@
# 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.kairos.io_osartifacts.yaml
- bases/build.c3os-x.io_osartifacts.yaml
#+kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:

View File

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

View File

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

View File

@@ -8,7 +8,7 @@ webhook:
port: 9443
leaderElection:
leaderElect: true
resourceName: 98ca89ca.kairos.io
resourceName: 98ca89ca.c3os-x.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/kairos/osbuilder
newName: quay.io/c3os/osbuilder
newTag: test

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ limitations under the License.
package controllers
import (
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -32,8 +32,7 @@ func (r *OSArtifactReconciler) genConfigMap(artifact buildv1alpha1.OSArtifact) *
OwnerReferences: genOwner(artifact),
},
Data: map[string]string{
"config": artifact.Spec.CloudConfig,
"grub.cfg": artifact.Spec.GRUBConfig,
"os-release": artifact.Spec.OSRelease,
"config": artifact.Spec.CloudConfig,
"grub.cfg": artifact.Spec.GRUBConfig,
}}
}

View File

@@ -19,7 +19,7 @@ package controllers
import (
"fmt"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
@@ -34,10 +34,10 @@ func genDeploymentLabel(s string) map[string]string {
// TODO: Handle registry auth
// TODO: This shells out, but needs ENV_VAR with key refs mapping
func unpackContainer(id, containerImage, pullImage string, pullOptions buildv1alpha1.Pull) v1.Container {
func unpackContainer(containerImage, pullImage string, pullOptions buildv1alpha1.Pull) v1.Container {
return v1.Container{
ImagePullPolicy: v1.PullAlways,
Name: fmt.Sprintf("pull-image-%s", id),
Name: "pull-image",
Image: containerImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
@@ -81,24 +81,23 @@ func createImageContainer(containerImage string, pushOptions buildv1alpha1.Push)
}
}
func osReleaseContainer(containerImage string) v1.Container {
func pushImageContainer(containerImage string, pushOptions buildv1alpha1.Push) v1.Container {
return v1.Container{
ImagePullPolicy: v1.PullAlways,
Name: "os-release",
Name: "push-image",
Image: containerImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
"cp -rfv /etc/os-release /rootfs/etc/os-release",
fmt.Sprintf(
"skopeo /public/image.tar %s",
pushOptions.ImageName,
),
},
VolumeMounts: []v1.VolumeMount{
{
Name: "config",
MountPath: "/etc/os-release",
SubPath: "os-release",
},
{
Name: "rootfs",
MountPath: "/rootfs",
Name: "public",
MountPath: "/public",
},
},
}
@@ -111,8 +110,6 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
OwnerReferences: genOwner(artifact),
}
pushImage := artifact.Spec.PushOptions.Push
privileged := false
serviceAccount := false
@@ -120,11 +117,11 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-iso",
Image: r.ToolImage,
Image: r.BuildImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"/entrypoint.sh --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /public dir:/rootfs",
"elemental --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /public dir:/rootfs",
artifact.Name,
),
},
@@ -139,7 +136,7 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
SubPath: "config",
},
{
Name: "config",
Name: "grub",
MountPath: "/iso/iso-overlay/boot/grub2/grub.cfg",
SubPath: "grub.cfg",
},
@@ -184,24 +181,14 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
},
}
pod.InitContainers = []v1.Container{unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName, artifact.Spec.PullOptions)}
for i, bundle := range artifact.Spec.Bundles {
pod.InitContainers = append(pod.InitContainers, unpackContainer(fmt.Sprint(i), r.ToolImage, bundle, artifact.Spec.PullOptions))
}
if artifact.Spec.OSRelease != "" {
pod.InitContainers = append(pod.InitContainers, osReleaseContainer(r.ToolImage))
pod.InitContainers = []v1.Container{buildIsoContainer, unpackContainer(r.ToolImage, artifact.Spec.ImageName, *artifact.Spec.PullOptions)}
for _, bundle := range artifact.Spec.Bundles {
pod.InitContainers = append(pod.InitContainers, unpackContainer(r.ToolImage, bundle, *artifact.Spec.PullOptions))
}
pod.InitContainers = append(pod.InitContainers, buildIsoContainer)
if pushImage {
pod.InitContainers = append(pod.InitContainers, createImageContainer(r.ToolImage, artifact.Spec.PushOptions))
}
pod.Containers = []v1.Container{servingContainer}
deploymentLabels := genDeploymentLabel(artifact.Name)

View File

@@ -21,7 +21,7 @@ import (
"fmt"
"time"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -38,9 +38,9 @@ import (
// OSArtifactReconciler reconciles a OSArtifact object
type OSArtifactReconciler struct {
client.Client
Scheme *runtime.Scheme
clientSet *kubernetes.Clientset
ServingImage, ToolImage string
Scheme *runtime.Scheme
clientSet *kubernetes.Clientset
ServingImage, BuildImage, ToolImage string
}
func genOwner(artifact buildv1alpha1.OSArtifact) []metav1.OwnerReference {
@@ -53,9 +53,9 @@ func genOwner(artifact buildv1alpha1.OSArtifact) []metav1.OwnerReference {
}
}
//+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
//+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
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
@@ -110,7 +110,6 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
logger.Error(err, "Failed while creating svc")
return ctrl.Result{}, err
}
return ctrl.Result{Requeue: true}, err
}
if err != nil {

View File

@@ -17,9 +17,10 @@ limitations under the License.
package controllers
import (
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
func genService(artifact buildv1alpha1.OSArtifact) *v1.Service {
@@ -31,8 +32,7 @@ func genService(artifact buildv1alpha1.OSArtifact) *v1.Service {
return &v1.Service{
ObjectMeta: objMeta,
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Ports: []v1.ServicePort{{Name: "http", Port: int32(80)}},
Ports: []v1.ServicePort{{Name: "http", Port: int32(80), TargetPort: intstr.FromInt(80)}},
Selector: genDeploymentLabel(artifact.Name),
},
}

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/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
//+kubebuilder:scaffold:imports
)

2
go.mod
View File

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

13
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/kairos-io/osbuilder/api/v1alpha1"
"github.com/kairos-io/osbuilder/controllers"
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
"github.com/c3os-io/osbuilder-operator/controllers"
//+kubebuilder:scaffold:imports
)
@@ -52,11 +52,11 @@ func main() {
var metricsAddr string
var enableLeaderElection bool
var probeAddr string
var serveImage, toolImage string
var buildImage, serveImage, toolImage string
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&buildImage, "build-image", "quay.io/costoolkit/elemental-cli:v0.0.15-ae4f000", "Build image.")
flag.StringVar(&serveImage, "serve-image", "nginx", "Serve image.")
// It needs luet inside
flag.StringVar(&toolImage, "tool-image", "quay.io/kairos/osbuilder-tools:latest", "Tool image.")
flag.StringVar(&toolImage, "tool-image", "quay.io/costoolkit/elemental-cli:v0.0.15-ae4f000", "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.kairos.io",
LeaderElectionID: "98ca89ca.c3os-x.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
@@ -98,6 +98,7 @@ func main() {
Client: mgr.GetClient(),
ServingImage: serveImage,
ToolImage: toolImage,
BuildImage: buildImage,
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")

View File

@@ -1,7 +1,7 @@
#!/bin/bash
KUBE_VERSION=${KUBE_VERSION:-v1.22.7}
CLUSTER_NAME="${CLUSTER_NAME:-kairos-osbuilder-e2e}"
CLUSTER_NAME="${CLUSTER_NAME:-c3os-osbuilder-e2e}"
if ! kind get clusters | grep "$CLUSTER_NAME"; then
cat << EOF > kind.config
@@ -29,4 +29,4 @@ kubectl wait --for=condition=Ready node/$CLUSTER_NAME-control-plane
export EXTERNAL_IP=$(kubectl get nodes -o jsonpath='{.items[].status.addresses[?(@.type == "InternalIP")].address}')
export BRIDGE_IP="172.18.0.1"
kubectl get nodes -o wide
cd $ROOT_DIR/tests && $GINKGO -r -v ./e2e
cd $ROOT_DIR/tests && ginkgo -r -v ./e2e

View File

@@ -1,39 +0,0 @@
package e2e_test
import (
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
kubectl "github.com/rancher-sandbox/ele-testhelpers/kubectl"
)
var _ = Describe("ISO build test", func() {
//k := kubectl.New()
Context("registration", func() {
AfterEach(func() {
kubectl.New().Delete("osartifacts", "-n", "default", "hello-kairos")
})
It("creates a simple iso", func() {
err := kubectl.Apply("", "../../tests/fixtures/simple.yaml")
Expect(err).ToNot(HaveOccurred())
Eventually(func() string {
b, _ := kubectl.GetData("default", "osartifacts", "hello-kairos", "jsonpath={.spec.imageName}")
return string(b)
}, 2*time.Minute, 2*time.Second).Should(Equal("quay.io/kairos/core-opensuse:latest"))
Eventually(func() string {
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-kairos"))
Eventually(func() string {
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

@@ -1,13 +1,39 @@
package e2e_test
import (
"testing"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
kubectl "github.com/rancher-sandbox/ele-testhelpers/kubectl"
)
func TestE2e(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "kairos-operator e2e test Suite")
}
var _ = Describe("ISO build test", func() {
//k := kubectl.New()
Context("registration", func() {
AfterEach(func() {
kubectl.New().Delete("osartifacts", "-n", "default", "hello-c3os")
})
It("creates a simple iso", func() {
err := kubectl.Apply("", "../../tests/fixtures/simple.yaml")
Expect(err).ToNot(HaveOccurred())
Eventually(func() string {
b, _ := kubectl.GetData("default", "osartifacts", "hello-c3os", "jsonpath={.spec.imageName}")
return string(b)
}, 2*time.Minute, 2*time.Second).Should(Equal("quay.io/c3os/c3os:opensuse-latest"))
Eventually(func() string {
b, _ := kubectl.GetData("default", "deployments", "hello-c3os", "jsonpath={.spec.template.metadata.labels.osbuild}")
return string(b)
}, 2*time.Minute, 2*time.Second).Should(Equal("workloadhello-c3os"))
Eventually(func() string {
b, _ := kubectl.GetData("default", "deployments", "hello-c3os", "jsonpath={.spec.status.unavailableReplicas}")
return string(b)
}, 15*time.Minute, 2*time.Second).ShouldNot(Equal("1"))
})
})
})

13
tests/e2e/e2e_test.go Normal file
View File

@@ -0,0 +1,13 @@
package e2e_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestE2e(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "c3os-operator e2e test Suite")
}

View File

@@ -1,52 +1,7 @@
apiVersion: build.kairos.io/v1alpha1
apiVersion: build.c3os-x.io/v1alpha1
kind: OSArtifact
metadata:
name: hello-kairos
name: hello-c3os
spec:
imageName: "quay.io/kairos/core-opensuse:latest"
iso: true
bundles:
- quay.io/kairos/packages:goreleaser-utils-1.11.1
grubConfig: |
search --file --set=root /boot/kernel.xz
set default=0
set timeout=10
set timeout_style=menu
set linux=linux
set initrd=initrd
if [ "${grub_cpu}" = "x86_64" -o "${grub_cpu}" = "i386" -o "${grub_cpu}" = "arm64" ];then
if [ "${grub_platform}" = "efi" ]; then
if [ "${grub_cpu}" != "arm64" ]; then
set linux=linuxefi
set initrd=initrdefi
fi
fi
fi
if [ "${grub_platform}" = "efi" ]; then
echo "Please press 't' to show the boot menu on this console"
fi
set font=($root)/boot/${grub_cpu}/loader/grub2/fonts/unicode.pf2
if [ -f ${font} ];then
loadfont ${font}
fi
menuentry "install" --class os --unrestricted {
echo Loading kernel...
$linux ($root)/boot/kernel.xz cdroot root=live:CDLABEL=COS_LIVE rd.live.dir=/ rd.live.squashimg=rootfs.squashfs console=tty1 console=ttyS0 rd.cos.disable vga=795 nomodeset nodepair.enable
echo Loading initrd...
$initrd ($root)/boot/rootfs.xz
}
if [ "${grub_platform}" = "efi" ]; then
hiddenentry "Text mode" --hotkey "t" {
set textmode=true
terminal_output console
}
fi
cloudConfig: |
#node-config
install:
device: "/dev/sda"
reboot: true
poweroff: true
auto: true # Required, for automated installations
imageName: "quay.io/c3os/c3os:opensuse-latest"
iso: true

View File

@@ -1,35 +0,0 @@
ARG ELEMENTAL_CLI_VERSION=0.20220921
ARG LEAP_VERSION=15.4
ARG LUET_VERSION=0.32.5
FROM quay.io/kairos/packages:elemental-cli-system-0.20220921 AS elemental
FROM quay.io/luet/base:$LUET_VERSION AS luet
## 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
FROM opensuse/leap:$LEAP_VERSION
COPY --from=elemental /usr/bin/elemental /usr/bin/elemental
COPY --from=luet /usr/bin/luet /usr/bin/luet
COPY --from=grub2 / /grub2
COPY --from=efi / /efi
RUN zypper ref && zypper dup -y
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
# ISO build
COPY ./config.yaml /config/manifest.yaml
COPY ./entrypoint.sh /entrypoint.sh
COPY ./add-cloud-init.sh /add-cloud-init.sh
# ARM
COPY ./build-arm-image.sh /build-arm-image.sh
COPY ./arm /arm
ENTRYPOINT [ "/entrypoint.sh" ]

View File

@@ -1,18 +0,0 @@
#!/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

@@ -1,21 +0,0 @@
#!/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

@@ -1,28 +0,0 @@
#!/bin/bash
partprobe
kpartx -va $DRIVE
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
set -ax
TEMPDIR="$(mktemp -d)"
echo $TEMPDIR
mount "${device}p1" "${TEMPDIR}"
sudo luet install --config $WORKDIR/luet.yaml -y --system-target $TEMPDIR firmware/u-boot-rpi64
sudo luet install --config $WORKDIR/luet.yaml -y --system-target $TEMPDIR firmware/raspberrypi-firmware
sudo luet install --config $WORKDIR/luet.yaml -y --system-target $TEMPDIR firmware/raspberrypi-firmware-config
sudo luet install --config $WORKDIR/luet.yaml -y --system-target $TEMPDIR firmware/raspberrypi-firmware-dt
umount "${TEMPDIR}"

View File

@@ -1,449 +0,0 @@
#!/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 " --final-repo: (optional) The luet repository used to download bits required for building"
echo " --repo-type: (optional) The luet repository type used to download bits required for building"
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
;;
--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)
# Create a luet config for grabbing packages from local and remote repositories (local with high prio)
cat << EOF > $WORKDIR/luet.yaml
repositories:
- name: cOS
enable: true
urls:
- $final_repo
type: $repo_type
priority: 90
EOF
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 $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
if [ -z "$manifest" ]; then
luet install --config $WORKDIR/luet.yaml -y --system-target $RECOVERY system/grub2-config
luet install --config $WORKDIR/luet.yaml -y --system-target $RECOVERY/grub2 system/grub2-artifacts
else
while IFS=$'\t' read -r name target ; do
if [ "$target" == "root/grub2" ]; then
luet install --no-spinner --system-target $RECOVERY/grub2 -y "$name"
fi
if [ "$target" == "root" ]; then
luet install --no-spinner --system-target $RECOVERY -y "$name"
fi
done < <("${YQ_PACKAGES_COMMAND[@]}" | jq -r ".raw_disk.$model.packages[] | [.name, .target] | @tsv")
fi
# Remove luet cache
rm -rf $RECOVERY/var $RECOVERY/grub2/var
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
if [ -z "$manifest" ]; then
luet install --config $WORKDIR/luet.yaml -y --system-target $EFI system/grub2-efi-image
else
while IFS=$'\t' read -r name target ; do
if [ "$target" == "efi" ]; then
luet install --no-spinner --system-target $EFI -y "$name"
fi
done < <("${YQ_PACKAGES_COMMAND[@]}" | jq -r ".raw_disk.$model.packages[] | [.name, .target] | @tsv")
fi
# Remove luet cache
rm -rf $EFI/var
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
# Set a OEM config file if specified
if [ -n "$config" ]; then
echo ">> Copying $config OEM config file"
mkdir $WORKDIR/persistent
mount $persistent $WORKDIR/persistent
mkdir $WORKDIR/persistent/cloud-config
get_url $config $WORKDIR/persistent/cloud-config/99_custom.yaml
umount $WORKDIR/persistent
fi
# 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

@@ -1,6 +0,0 @@
iso:
uefi:
- dir:/efi
image:
- dir:/efi
- dir:/grub2

View File

@@ -1,5 +0,0 @@
#!/bin/bash
set -ex
elemental --config-dir /config $@