mirror of
https://github.com/kairos-io/osbuilder.git
synced 2026-01-04 15:04:25 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cb37cd1c9 |
26
.github/workflows/bump_repos.yml
vendored
26
.github/workflows/bump_repos.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: Bump repositories
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: 0 20 * * *
|
|
||||||
workflow_dispatch:
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Install earthly
|
|
||||||
uses: Luet-lab/luet-install-action@v1
|
|
||||||
with:
|
|
||||||
repository: quay.io/kairos/packages
|
|
||||||
packages: utils/earthly
|
|
||||||
- name: Bump cos 🔧
|
|
||||||
run: earthly +bump-repositories
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v5
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.PAT_TOKEN }}
|
|
||||||
push-to-fork: ci-forks/osbuilder
|
|
||||||
commit-message: ':arrow_up: Update repositories'
|
|
||||||
title: ':arrow_up: Update repositories'
|
|
||||||
body: Bump of Kairos repositories
|
|
||||||
signoff: true
|
|
||||||
4
.github/workflows/image.yml
vendored
4
.github/workflows/image.yml
vendored
@@ -13,12 +13,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Prepare
|
- name: Prepare
|
||||||
id: prep
|
id: prep
|
||||||
run: |
|
run: |
|
||||||
DOCKER_IMAGE=quay.io/kairos/osbuilder
|
DOCKER_IMAGE=quay.io/c3os/osbuilder
|
||||||
VERSION=latest
|
VERSION=latest
|
||||||
SHORTREF=${GITHUB_SHA::8}
|
SHORTREF=${GITHUB_SHA::8}
|
||||||
# If this is git tag, use the tag name as a docker tag
|
# If this is git tag, use the tag name as a docker tag
|
||||||
|
|||||||
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: 'test'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: Test
|
|
||||||
run: |
|
|
||||||
make kind-e2e-tests
|
|
||||||
63
.github/workflows/tool-image.yml
vendored
63
.github/workflows/tool-image.yml
vendored
@@ -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@v3
|
|
||||||
|
|
||||||
- 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 }}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build the manager binary
|
# Build the manager binary
|
||||||
FROM golang:1.20 as builder
|
FROM golang:1.18 as builder
|
||||||
|
|
||||||
WORKDIR /workspace
|
WORKDIR /workspace
|
||||||
# Copy the Go Modules manifests
|
# Copy the Go Modules manifests
|
||||||
|
|||||||
22
Earthfile
22
Earthfile
@@ -1,22 +0,0 @@
|
|||||||
VERSION 0.6
|
|
||||||
|
|
||||||
last-commit-packages:
|
|
||||||
FROM quay.io/skopeo/stable
|
|
||||||
RUN dnf install -y jq
|
|
||||||
WORKDIR build
|
|
||||||
RUN skopeo list-tags docker://quay.io/kairos/packages | jq -rc '.Tags | map(select( (. | contains("-repository.yaml")) )) | sort_by(. | sub("v";"") | sub("-repository.yaml";"") | sub("-";"") | split(".") | map(tonumber) ) | .[-1]' > REPO_AMD64
|
|
||||||
RUN skopeo list-tags docker://quay.io/kairos/packages-arm64 | jq -rc '.Tags | map(select( (. | contains("-repository.yaml")) )) | sort_by(. | sub("v";"") | sub("-repository.yaml";"") | sub("-";"") | split(".") | map(tonumber) ) | .[-1]' > REPO_ARM64
|
|
||||||
SAVE ARTIFACT REPO_AMD64 REPO_AMD64
|
|
||||||
SAVE ARTIFACT REPO_ARM64 REPO_ARM64
|
|
||||||
|
|
||||||
bump-repositories:
|
|
||||||
FROM mikefarah/yq
|
|
||||||
WORKDIR build
|
|
||||||
COPY +last-commit-packages/REPO_AMD64 REPO_AMD64
|
|
||||||
COPY +last-commit-packages/REPO_ARM64 REPO_ARM64
|
|
||||||
ARG REPO_AMD64=$(cat REPO_AMD64)
|
|
||||||
ARG REPO_ARM64=$(cat REPO_ARM64)
|
|
||||||
COPY tools-image/luet.yaml luet.yaml
|
|
||||||
RUN yq eval ".repositories[0] |= . * { \"reference\": \"${REPO_AMD64}\" }" -i luet.yaml
|
|
||||||
RUN yq eval ".repositories[1] |= . * { \"reference\": \"${REPO_ARM64}\" }" -i luet.yaml
|
|
||||||
SAVE ARTIFACT luet.yaml AS LOCAL tools-image/luet.yaml
|
|
||||||
30
Makefile
30
Makefile
@@ -4,8 +4,8 @@
|
|||||||
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
|
# - 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)
|
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
|
||||||
VERSION ?= 0.0.1
|
VERSION ?= 0.0.1
|
||||||
IMG ?= quay.io/kairos/osbuilder:test
|
IMG ?= quay.io/c3os/osbuilder:test
|
||||||
CLUSTER_NAME?="kairos-osbuilder-e2e"
|
CLUSTER_NAME?="c3os-osbuilder-e2e"
|
||||||
export ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
export ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
# CHANNELS define the bundle channels used in the bundle.
|
# 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.
|
# 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
|
# 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.
|
# c3os-x.io/osbuilder-operator-bundle:$VERSION and c3os-x.io/osbuilder-operator-catalog:$VERSION.
|
||||||
IMAGE_TAG_BASE ?= kairos.io/osbuilder
|
IMAGE_TAG_BASE ?= c3os-x.io/osbuilder-operator
|
||||||
|
|
||||||
# BUNDLE_IMG defines the image:tag used for the bundle.
|
# 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>)
|
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
|
||||||
@@ -147,12 +147,13 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
|
|||||||
.PHONY: deploy
|
.PHONY: deploy
|
||||||
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||||
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||||
# TODO: No need to build and then apply. `kubectl apply -k config/default` does the trick
|
|
||||||
$(KUSTOMIZE) build config/default | kubectl apply -f -
|
$(KUSTOMIZE) build config/default | kubectl apply -f -
|
||||||
|
|
||||||
|
|
||||||
.PHONY: deploy-dev
|
.PHONY: deploy-dev
|
||||||
deploy-dev: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
deploy-dev: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||||
kubectl apply -k config/dev
|
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
|
||||||
|
$(KUSTOMIZE) build config/dev | kubectl apply -f -
|
||||||
|
|
||||||
.PHONY: undeploy
|
.PHONY: undeploy
|
||||||
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||||
@@ -171,7 +172,6 @@ $(LOCALBIN):
|
|||||||
|
|
||||||
## Tool Binaries
|
## Tool Binaries
|
||||||
KUSTOMIZE ?= $(LOCALBIN)/kustomize
|
KUSTOMIZE ?= $(LOCALBIN)/kustomize
|
||||||
GINKGO ?= $(LOCALBIN)/ginkgo
|
|
||||||
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
|
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
|
||||||
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||||
|
|
||||||
@@ -190,10 +190,6 @@ controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessar
|
|||||||
$(CONTROLLER_GEN): $(LOCALBIN)
|
$(CONTROLLER_GEN): $(LOCALBIN)
|
||||||
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
|
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
|
.PHONY: envtest
|
||||||
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
|
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
|
||||||
$(ENVTEST): $(LOCALBIN)
|
$(ENVTEST): $(LOCALBIN)
|
||||||
@@ -270,15 +266,9 @@ test_deps:
|
|||||||
|
|
||||||
.PHONY: unit-tests
|
.PHONY: unit-tests
|
||||||
unit-tests: test_deps
|
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:
|
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
|
||||||
|
|
||||||
|
|
||||||
kubesplit: manifests kustomize
|
|
||||||
rm -rf helm-chart
|
|
||||||
mkdir helm-chart
|
|
||||||
$(KUSTOMIZE) build config/default | kubesplit -helm helm-chart
|
|
||||||
8
PROJECT
8
PROJECT
@@ -1,19 +1,19 @@
|
|||||||
domain: kairos.io
|
domain: c3os-x.io
|
||||||
layout:
|
layout:
|
||||||
- go.kubebuilder.io/v3
|
- go.kubebuilder.io/v3
|
||||||
plugins:
|
plugins:
|
||||||
manifests.sdk.operatorframework.io/v2: {}
|
manifests.sdk.operatorframework.io/v2: {}
|
||||||
scorecard.sdk.operatorframework.io/v2: {}
|
scorecard.sdk.operatorframework.io/v2: {}
|
||||||
projectName: osartifactbuilder-operator
|
projectName: osartifactbuilder-operator
|
||||||
repo: github.com/kairos-io/osbuilder
|
repo: github.com/c3os-io/osbuilder-operator
|
||||||
resources:
|
resources:
|
||||||
- api:
|
- api:
|
||||||
crdVersion: v1
|
crdVersion: v1
|
||||||
namespaced: true
|
namespaced: true
|
||||||
controller: true
|
controller: true
|
||||||
domain: kairos.io
|
domain: c3os-x.io
|
||||||
group: build
|
group: build
|
||||||
kind: OSArtifact
|
kind: OSArtifact
|
||||||
path: github.com/kairos-io/osbuilder/api/v1alpha1
|
path: github.com/c3os-io/osbuilder-operator/api/v1alpha1
|
||||||
version: v1alpha1
|
version: v1alpha1
|
||||||
version: "3"
|
version: "3"
|
||||||
|
|||||||
169
README.md
169
README.md
@@ -1,87 +1,94 @@
|
|||||||
<h1 align="center">
|
# osartifactbuilder-operator
|
||||||
<br>
|
// TODO(user): Add simple overview of use/purpose
|
||||||
<img width="184" alt="kairos-white-column 5bc2fe34" src="https://user-images.githubusercontent.com/2420543/193010398-72d4ba6e-7efe-4c2e-b7ba-d3a826a55b7d.png"><br>
|
|
||||||
osbuilder
|
|
||||||
<br>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h3 align="center">Kubernetes Native Extension to build Linux distributions artifacts from container images</h3>
|
## Description
|
||||||
<p align="center">
|
// TODO(user): An in-depth paragraph about your project and overview of use
|
||||||
<a href="https://opensource.org/licenses/">
|
|
||||||
<img src="https://img.shields.io/badge/licence-APL2-brightgreen"
|
|
||||||
alt="license">
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/kairos-io/osbuilder/issues"><img src="https://img.shields.io/github/issues/kairos-io/osbuilder"></a>
|
|
||||||
<a href="https://kairos.io/docs/" target=_blank> <img src="https://img.shields.io/badge/Documentation-blue"
|
|
||||||
alt="docs"></a>
|
|
||||||
<img src="https://img.shields.io/badge/made%20with-Go-blue">
|
|
||||||
<img src="https://goreportcard.com/badge/github.com/kairos-io/osbuilder" alt="go report card" />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
You’ll 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).
|
||||||
|
|
||||||
With Kairos you can build immutable, bootable Kubernetes and OS images for your edge devices as easily as writing a Dockerfile. Optional P2P mesh with distributed ledger automates node bootstrapping and coordination. Updating nodes is as easy as CI/CD: push a new image to your container registry and let secure, risk-free A/B atomic upgrades do the rest.
|
### Running on the cluster
|
||||||
|
1. Install Instances of Custom Resources:
|
||||||
|
|
||||||
|
```sh
|
||||||
<table>
|
kubectl apply -f config/samples/
|
||||||
<tr>
|
|
||||||
<th align="center">
|
|
||||||
<img width="640" height="1px">
|
|
||||||
<p>
|
|
||||||
<small>
|
|
||||||
Documentation
|
|
||||||
</small>
|
|
||||||
</p>
|
|
||||||
</th>
|
|
||||||
<th align="center">
|
|
||||||
<img width="640" height="1">
|
|
||||||
<p>
|
|
||||||
<small>
|
|
||||||
Contribute
|
|
||||||
</small>
|
|
||||||
</p>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
📚 [Getting started with Kairos](https://kairos.io/docs/getting-started) <br> :bulb: [Examples](https://kairos.io/docs/examples) <br> :movie_camera: [Video](https://kairos.io/docs/media/) <br> :open_hands:[Engage with the Community](https://kairos.io/community/)
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
🙌[ CONTRIBUTING.md ]( https://github.com/kairos-io/kairos/blob/master/CONTRIBUTING.md ) <br> :raising_hand: [ GOVERNANCE ]( https://github.com/kairos-io/kairos/blob/master/GOVERNANCE.md ) <br>:construction_worker:[Code of conduct](https://github.com/kairos-io/kairos/blob/master/CODE_OF_CONDUCT.md)
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
| :exclamation: | This is experimental! |
|
|
||||||
|-|:-|
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
To install, use helm:
|
|
||||||
|
|
||||||
```
|
|
||||||
# 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Documentation available at: https://kairos.io/docs/advanced/build/
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package v1alpha2 contains API Schema definitions for the build v1alpha2 API group
|
// Package v1alpha1 contains API Schema definitions for the build v1alpha1 API group
|
||||||
// +kubebuilder:object:generate=true
|
//+kubebuilder:object:generate=true
|
||||||
// +groupName=build.kairos.io
|
//+groupName=build.c3os-x.io
|
||||||
package v1alpha2
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// GroupVersion is group version used to register these objects
|
// GroupVersion is group version used to register these objects
|
||||||
GroupVersion = schema.GroupVersion{Group: "build.kairos.io", Version: "v1alpha2"}
|
GroupVersion = schema.GroupVersion{Group: "build.c3os-x.io", Version: "v1alpha1"}
|
||||||
|
|
||||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||||
@@ -14,65 +14,62 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package v1alpha2
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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.
|
||||||
|
|
||||||
// OSArtifactSpec defines the desired state of OSArtifact
|
// OSArtifactSpec defines the desired state of OSArtifact
|
||||||
type OSArtifactSpec struct {
|
type OSArtifactSpec struct {
|
||||||
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
|
|
||||||
|
// Foo is an example field of OSArtifact. Edit osartifact_types.go to remove/update
|
||||||
ImageName string `json:"imageName,omitempty"`
|
ImageName string `json:"imageName,omitempty"`
|
||||||
|
ISO bool `json:"iso,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"`
|
||||||
|
|
||||||
ISO bool `json:"iso,omitempty"`
|
Bundles []string `json:"bundles,omitempty"`
|
||||||
|
PullOptions *Pull `json:"pull,omitempty"`
|
||||||
|
PushOptions *Push `json:"push,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
//Disk-only stuff
|
type Push struct {
|
||||||
DiskSize string `json:"diskSize,omitempty"`
|
Push bool `json:"push,omitempty"`
|
||||||
CloudImage bool `json:"cloudImage,omitempty"`
|
ImageName string `json:"imageName,omitempty"`
|
||||||
AzureImage bool `json:"azureImage,omitempty"`
|
ContainerRegistryCredentials *SecretKeySelector `json:"containerRegistryCredentials,omitempty"`
|
||||||
GCEImage bool `json:"gceImage,omitempty"`
|
}
|
||||||
|
|
||||||
Netboot bool `json:"netboot,omitempty"`
|
type Pull struct {
|
||||||
NetbootURL string `json:"netbootURL,omitempty"`
|
ContainerRegistryCredentials *SecretKeySelector `json:"containerRegistryCredentials,omitempty"`
|
||||||
|
}
|
||||||
CloudConfigRef *SecretKeySelector `json:"cloudConfigRef,omitempty"`
|
type LocalObjectReference struct {
|
||||||
GRUBConfig string `json:"grubConfig,omitempty"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
Bundles []string `json:"bundles,omitempty"`
|
|
||||||
OSRelease string `json:"osRelease,omitempty"`
|
|
||||||
|
|
||||||
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
|
||||||
Exporters []batchv1.JobSpec `json:"exporters,omitempty"`
|
|
||||||
Volume *corev1.PersistentVolumeClaimSpec `json:"volume,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SecretKeySelector struct {
|
type SecretKeySelector struct {
|
||||||
Name string `json:"name"`
|
LocalObjectReference `json:",inline"`
|
||||||
|
// +optional
|
||||||
|
Namespace string `json:"namespace,omitempty"`
|
||||||
// +optional
|
// +optional
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtifactPhase string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Pending = "Pending"
|
|
||||||
Building = "Building"
|
|
||||||
Exporting = "Exporting"
|
|
||||||
Ready = "Ready"
|
|
||||||
Error = "Error"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OSArtifactStatus defines the observed state of OSArtifact
|
// OSArtifactStatus defines the observed state of OSArtifact
|
||||||
type OSArtifactStatus struct {
|
type OSArtifactStatus struct {
|
||||||
// +kubebuilder:default=Pending
|
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||||
Phase ArtifactPhase `json:"phase,omitempty"`
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
|
Phase string `json:"phase,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//+kubebuilder:object:root=true
|
//+kubebuilder:object:root=true
|
||||||
//+kubebuilder:subresource:status
|
//+kubebuilder:subresource:status
|
||||||
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
|
||||||
|
|
||||||
// OSArtifact is the Schema for the osartifacts API
|
// OSArtifact is the Schema for the osartifacts API
|
||||||
type OSArtifact struct {
|
type OSArtifact struct {
|
||||||
@@ -19,11 +19,9 @@ limitations under the License.
|
|||||||
|
|
||||||
// Code generated by controller-gen. DO NOT EDIT.
|
// Code generated by controller-gen. DO NOT EDIT.
|
||||||
|
|
||||||
package v1alpha2
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ func (in *OSArtifact) DeepCopyInto(out *OSArtifact) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
out.Spec = in.Spec
|
||||||
out.Status = in.Status
|
out.Status = in.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,33 +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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *OSArtifactSpec) DeepCopyInto(out *OSArtifactSpec) {
|
func (in *OSArtifactSpec) DeepCopyInto(out *OSArtifactSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.CloudConfigRef != nil {
|
|
||||||
in, out := &in.CloudConfigRef, &out.CloudConfigRef
|
|
||||||
*out = new(SecretKeySelector)
|
|
||||||
**out = **in
|
|
||||||
}
|
|
||||||
if in.Bundles != nil {
|
|
||||||
in, out := &in.Bundles, &out.Bundles
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.ImagePullSecrets != nil {
|
|
||||||
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
|
||||||
*out = make([]v1.LocalObjectReference, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
if in.Exporters != nil {
|
|
||||||
in, out := &in.Exporters, &out.Exporters
|
|
||||||
*out = make([]batchv1.JobSpec, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if in.Volume != nil {
|
|
||||||
in, out := &in.Volume, &out.Volume
|
|
||||||
*out = new(v1.PersistentVolumeClaimSpec)
|
|
||||||
(*in).DeepCopyInto(*out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OSArtifactSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OSArtifactSpec.
|
||||||
@@ -142,18 +113,3 @@ func (in *OSArtifactStatus) DeepCopy() *OSArtifactStatus {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
66
config/crd/bases/build.c3os-x.io_osartifacts.yaml
Normal file
66
config/crd/bases/build.c3os-x.io_osartifacts.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.9.0
|
||||||
|
creationTimestamp: null
|
||||||
|
name: osartifacts.build.c3os-x.io
|
||||||
|
spec:
|
||||||
|
group: build.c3os-x.io
|
||||||
|
names:
|
||||||
|
kind: OSArtifact
|
||||||
|
listKind: OSArtifactList
|
||||||
|
plural: osartifacts
|
||||||
|
singular: osartifact
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: OSArtifact is the Schema for the osartifacts API
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
|
of an object. Servers should convert recognized schemas to the latest
|
||||||
|
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: 'Kind is a string value representing the REST resource this
|
||||||
|
object represents. Servers may infer this from the endpoint the client
|
||||||
|
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: OSArtifactSpec defines the desired state of OSArtifact
|
||||||
|
properties:
|
||||||
|
cloudConfig:
|
||||||
|
description: 'TODO: treat cloudconfig as a secret, and take a secretRef
|
||||||
|
where to store it (optionally)'
|
||||||
|
type: string
|
||||||
|
grubConfig:
|
||||||
|
type: string
|
||||||
|
imageName:
|
||||||
|
description: Foo is an example field of OSArtifact. Edit osartifact_types.go
|
||||||
|
to remove/update
|
||||||
|
type: string
|
||||||
|
iso:
|
||||||
|
type: boolean
|
||||||
|
pullFromKube:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: OSArtifactStatus defines the observed state of OSArtifact
|
||||||
|
properties:
|
||||||
|
phase:
|
||||||
|
description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
|
||||||
|
of cluster Important: Run "make" to regenerate code after modifying
|
||||||
|
this file'
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
# since it depends on service name and namespace that are out of this kustomize package.
|
# since it depends on service name and namespace that are out of this kustomize package.
|
||||||
# It should be run by config/default
|
# It should be run by config/default
|
||||||
resources:
|
resources:
|
||||||
- bases/build.kairos.io_osartifacts.yaml
|
- bases/build.c3os-x.io_osartifacts.yaml
|
||||||
#+kubebuilder:scaffold:crdkustomizeresource
|
#+kubebuilder:scaffold:crdkustomizeresource
|
||||||
|
|
||||||
patchesStrategicMerge:
|
patchesStrategicMerge:
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ kind: CustomResourceDefinition
|
|||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||||
name: osartifacts.build.kairos.io
|
name: osartifacts.build.c3os-x.io
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
apiVersion: apiextensions.k8s.io/v1
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
kind: CustomResourceDefinition
|
kind: CustomResourceDefinition
|
||||||
metadata:
|
metadata:
|
||||||
name: osartifacts.build.kairos.io
|
name: osartifacts.build.c3os-x.io
|
||||||
spec:
|
spec:
|
||||||
conversion:
|
conversion:
|
||||||
strategy: Webhook
|
strategy: Webhook
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ bases:
|
|||||||
- ../crd
|
- ../crd
|
||||||
- ../rbac
|
- ../rbac
|
||||||
- ../manager
|
- ../manager
|
||||||
- ../nginx
|
|
||||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||||
# crd/kustomization.yaml
|
# crd/kustomization.yaml
|
||||||
#- ../webhook
|
#- ../webhook
|
||||||
@@ -73,16 +72,3 @@ vars:
|
|||||||
# kind: Service
|
# kind: Service
|
||||||
# version: v1
|
# version: v1
|
||||||
# name: webhook-service
|
# name: webhook-service
|
||||||
|
|
||||||
vars:
|
|
||||||
- name: NGINX_NAMESPACE
|
|
||||||
objref:
|
|
||||||
kind: Namespace
|
|
||||||
name: system
|
|
||||||
apiVersion: v1
|
|
||||||
|
|
||||||
- name: ARTIFACT_COPIER_ROLE
|
|
||||||
objref:
|
|
||||||
kind: Role
|
|
||||||
name: artifactCopier
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
|
|||||||
@@ -38,7 +38,3 @@ spec:
|
|||||||
- "--health-probe-bind-address=:8081"
|
- "--health-probe-bind-address=:8081"
|
||||||
- "--metrics-bind-address=127.0.0.1:8080"
|
- "--metrics-bind-address=127.0.0.1:8080"
|
||||||
- "--leader-elect"
|
- "--leader-elect"
|
||||||
- "--copy-to-namespace=$(NGINX_NAMESPACE)"
|
|
||||||
- "--copy-role=$(ARTIFACT_COPIER_ROLE)"
|
|
||||||
- --copy-to-pod-label=app.kubernetes.io/name=osbuilder-nginx
|
|
||||||
- --copy-to-path="/usr/share/nginx/html"
|
|
||||||
|
|||||||
@@ -1,7 +1,74 @@
|
|||||||
bases:
|
# Adds namespace to all resources.
|
||||||
- ../default
|
namespace: osartifactbuilder-operator-system
|
||||||
|
|
||||||
images:
|
# Value of this field is prepended to the
|
||||||
- name: quay.io/kairos/osbuilder
|
# names of all resources, e.g. a deployment named
|
||||||
newName: quay.io/kairos/osbuilder
|
# "wordpress" becomes "alices-wordpress".
|
||||||
newTag: test
|
# Note that it should also match with the prefix (text before '-') of the namespace
|
||||||
|
# field above.
|
||||||
|
namePrefix: osartifactbuilder-operator-
|
||||||
|
|
||||||
|
# Labels to add to all resources and selectors.
|
||||||
|
#commonLabels:
|
||||||
|
# someName: someValue
|
||||||
|
|
||||||
|
bases:
|
||||||
|
- ../crd
|
||||||
|
- ../rbac
|
||||||
|
- ../manager
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||||
|
# crd/kustomization.yaml
|
||||||
|
#- ../webhook
|
||||||
|
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||||
|
#- ../certmanager
|
||||||
|
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
|
||||||
|
#- ../prometheus
|
||||||
|
|
||||||
|
patchesStrategicMerge:
|
||||||
|
# Protect the /metrics endpoint by putting it behind auth.
|
||||||
|
# If you want your controller-manager to expose the /metrics
|
||||||
|
# endpoint w/o any authn/z, please comment the following line.
|
||||||
|
- manager_auth_proxy_patch.yaml
|
||||||
|
|
||||||
|
# Mount the controller config file for loading manager configurations
|
||||||
|
# through a ComponentConfig type
|
||||||
|
#- manager_config_patch.yaml
|
||||||
|
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||||
|
# crd/kustomization.yaml
|
||||||
|
#- manager_webhook_patch.yaml
|
||||||
|
|
||||||
|
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
|
||||||
|
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
|
||||||
|
# 'CERTMANAGER' needs to be enabled to use ca injection
|
||||||
|
#- webhookcainjection_patch.yaml
|
||||||
|
|
||||||
|
# the following config is for teaching kustomize how to do var substitution
|
||||||
|
vars:
|
||||||
|
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||||
|
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
|
||||||
|
# objref:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert # this name should match the one in certificate.yaml
|
||||||
|
# fieldref:
|
||||||
|
# fieldpath: metadata.namespace
|
||||||
|
#- name: CERTIFICATE_NAME
|
||||||
|
# objref:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert # this name should match the one in certificate.yaml
|
||||||
|
#- name: SERVICE_NAMESPACE # namespace of the service
|
||||||
|
# objref:
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: webhook-service
|
||||||
|
# fieldref:
|
||||||
|
# fieldpath: metadata.namespace
|
||||||
|
#- name: SERVICE_NAME
|
||||||
|
# objref:
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: webhook-service
|
||||||
|
|||||||
40
config/dev/manager_auth_proxy_patch.yaml
Normal file
40
config/dev/manager_auth_proxy_patch.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# This patch inject a sidecar container which is a HTTP proxy for the
|
||||||
|
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: kube-rbac-proxy
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
# TODO(user): uncomment for common cases that do not require escalating privileges
|
||||||
|
# capabilities:
|
||||||
|
# drop:
|
||||||
|
# - "ALL"
|
||||||
|
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.11.0
|
||||||
|
args:
|
||||||
|
- "--secure-listen-address=0.0.0.0:8443"
|
||||||
|
- "--upstream=http://127.0.0.1:8080/"
|
||||||
|
- "--logtostderr=true"
|
||||||
|
- "--v=0"
|
||||||
|
ports:
|
||||||
|
- containerPort: 8443
|
||||||
|
protocol: TCP
|
||||||
|
name: https
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 5m
|
||||||
|
memory: 64Mi
|
||||||
|
- name: manager
|
||||||
|
args:
|
||||||
|
- "--health-probe-bind-address=:8081"
|
||||||
|
- "--metrics-bind-address=127.0.0.1:8080"
|
||||||
|
- "--leader-elect"
|
||||||
21
config/dev/manager_config_patch.yaml
Normal file
21
config/dev/manager_config_patch.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: manager
|
||||||
|
imagePullPolicy: Never
|
||||||
|
args:
|
||||||
|
- "--config=controller_manager_config.yaml"
|
||||||
|
volumeMounts:
|
||||||
|
- name: manager-config
|
||||||
|
mountPath: /controller_manager_config.yaml
|
||||||
|
subPath: controller_manager_config.yaml
|
||||||
|
volumes:
|
||||||
|
- name: manager-config
|
||||||
|
configMap:
|
||||||
|
name: manager-config
|
||||||
@@ -8,7 +8,7 @@ webhook:
|
|||||||
port: 9443
|
port: 9443
|
||||||
leaderElection:
|
leaderElection:
|
||||||
leaderElect: true
|
leaderElect: true
|
||||||
resourceName: 98ca89ca.kairos.io
|
resourceName: 98ca89ca.c3os-x.io
|
||||||
# leaderElectionReleaseOnCancel defines if the leader should step down volume
|
# leaderElectionReleaseOnCancel defines if the leader should step down volume
|
||||||
# when the Manager ends. This requires the binary to immediately end when the
|
# when the Manager ends. This requires the binary to immediately end when the
|
||||||
# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
resources:
|
resources:
|
||||||
- manager.yaml
|
- manager.yaml
|
||||||
|
|
||||||
namespace: system
|
|
||||||
|
|
||||||
generatorOptions:
|
generatorOptions:
|
||||||
disableNameSuffixHash: true
|
disableNameSuffixHash: true
|
||||||
|
|
||||||
@@ -14,5 +12,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
images:
|
images:
|
||||||
- name: controller
|
- name: controller
|
||||||
newName: quay.io/kairos/osbuilder
|
newName: quay.io/c3os/osbuilder
|
||||||
newTag: test
|
newTag: test
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ apiVersion: apps/v1
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: controller-manager
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
labels:
|
labels:
|
||||||
control-plane: controller-manager
|
control-plane: controller-manager
|
||||||
spec:
|
spec:
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: nginx-public
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 3Gi
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: osbuilder-nginx
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/name: osbuilder-nginx
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app.kubernetes.io/name: osbuilder-nginx
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: nginx
|
|
||||||
name: nginx
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: "/usr/share/nginx/html"
|
|
||||||
name: nginx-public
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
serviceAccountName: controller-manager
|
|
||||||
terminationGracePeriodSeconds: 10
|
|
||||||
volumes:
|
|
||||||
- name: nginx-public
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: nginx-public
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
resources:
|
|
||||||
- deployment.yaml
|
|
||||||
- service.yaml
|
|
||||||
- role.yaml
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: artifactCopier
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- pods
|
|
||||||
verbs:
|
|
||||||
- list
|
|
||||||
- get
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- pods/exec
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: osbuilder-nginx
|
|
||||||
spec:
|
|
||||||
type: NodePort
|
|
||||||
selector:
|
|
||||||
app.kubernetes.io/name: osbuilder-nginx
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
||||||
@@ -16,3 +16,6 @@ resources:
|
|||||||
- auth_proxy_role.yaml
|
- auth_proxy_role.yaml
|
||||||
- auth_proxy_role_binding.yaml
|
- auth_proxy_role_binding.yaml
|
||||||
- auth_proxy_client_clusterrole.yaml
|
- auth_proxy_client_clusterrole.yaml
|
||||||
|
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- role_custom.yaml
|
||||||
@@ -5,7 +5,7 @@ metadata:
|
|||||||
name: osartifact-editor-role
|
name: osartifact-editor-role
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts
|
- osartifacts
|
||||||
verbs:
|
verbs:
|
||||||
@@ -17,7 +17,7 @@ rules:
|
|||||||
- update
|
- update
|
||||||
- watch
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts/status
|
- osartifacts/status
|
||||||
verbs:
|
verbs:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ metadata:
|
|||||||
name: osartifact-viewer-role
|
name: osartifact-viewer-role
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts
|
- osartifacts
|
||||||
verbs:
|
verbs:
|
||||||
@@ -13,7 +13,7 @@ rules:
|
|||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts/status
|
- osartifacts/status
|
||||||
verbs:
|
verbs:
|
||||||
|
|||||||
@@ -6,50 +6,7 @@ metadata:
|
|||||||
name: manager-role
|
name: manager-role
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- build.c3os-x.io
|
||||||
resources:
|
|
||||||
- configmaps
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- get
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- persistentvolumeclaims
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- pods
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
resources:
|
|
||||||
- secrets
|
|
||||||
verbs:
|
|
||||||
- get
|
|
||||||
- apiGroups:
|
|
||||||
- batch
|
|
||||||
resources:
|
|
||||||
- jobs
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- delete
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- build.kairos.io
|
|
||||||
resources:
|
resources:
|
||||||
- osartifacts
|
- osartifacts
|
||||||
verbs:
|
verbs:
|
||||||
@@ -61,13 +18,13 @@ rules:
|
|||||||
- update
|
- update
|
||||||
- watch
|
- watch
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts/finalizers
|
- osartifacts/finalizers
|
||||||
verbs:
|
verbs:
|
||||||
- update
|
- update
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- build.kairos.io
|
- build.c3os-x.io
|
||||||
resources:
|
resources:
|
||||||
- osartifacts/status
|
- osartifacts/status
|
||||||
verbs:
|
verbs:
|
||||||
|
|||||||
56
config/rbac/role_custom.yaml
Normal file
56
config/rbac/role_custom.yaml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
name: manager-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- build.c3os-x.io
|
||||||
|
resources:
|
||||||
|
- osartifacts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- build.c3os-x.io
|
||||||
|
resources:
|
||||||
|
- osartifacts/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- build.c3os-x.io
|
||||||
|
resources:
|
||||||
|
- osartifacts/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- build.c3os-x.io
|
||||||
|
resources:
|
||||||
|
- osartifacts/finalizers
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
- configmaps
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- "apps"
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- update
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
apiVersion: build.kairos.io/v1alpha1
|
apiVersion: build.c3os-x.io/v1alpha1
|
||||||
kind: OSArtifact
|
kind: OSArtifact
|
||||||
metadata:
|
metadata:
|
||||||
name: osartifact-sample
|
name: osartifact-sample
|
||||||
|
|||||||
@@ -17,20 +17,22 @@ limitations under the License.
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) genConfigMap(artifact *osbuilder.OSArtifact) *v1.ConfigMap {
|
func (r *OSArtifactReconciler) genConfigMap(artifact buildv1alpha1.OSArtifact) *v1.ConfigMap {
|
||||||
return &v1.ConfigMap{
|
return &v1.ConfigMap{
|
||||||
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: artifact.Name,
|
Name: artifact.Name,
|
||||||
Namespace: artifact.Namespace,
|
Namespace: artifact.Namespace,
|
||||||
|
OwnerReferences: genOwner(artifact),
|
||||||
},
|
},
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"grub.cfg": artifact.Spec.GRUBConfig,
|
"config": artifact.Spec.CloudConfig,
|
||||||
"os-release": artifact.Spec.OSRelease,
|
"grub.cfg": artifact.Spec.GRUBConfig,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|||||||
211
controllers/deployment.go
Normal file
211
controllers/deployment.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
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/c3os-io/osbuilder-operator/api/v1alpha1"
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genDeploymentLabel(s string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"osbuild": "workload" + s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle registry auth
|
||||||
|
// TODO: This shells out, but needs ENV_VAR with key refs mapping
|
||||||
|
func unpackContainer(containerImage, pullImage string, pullOptions buildv1alpha1.Pull) v1.Container {
|
||||||
|
return v1.Container{
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
Name: "pull-image",
|
||||||
|
Image: containerImage,
|
||||||
|
Command: []string{"/bin/bash", "-cxe"},
|
||||||
|
Args: []string{
|
||||||
|
fmt.Sprintf(
|
||||||
|
"luet util unpack %s %s",
|
||||||
|
pullImage,
|
||||||
|
"/rootfs",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "rootfs",
|
||||||
|
MountPath: "/rootfs",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createImageContainer(containerImage string, pushOptions buildv1alpha1.Push) v1.Container {
|
||||||
|
return v1.Container{
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
Name: "create-image",
|
||||||
|
Image: containerImage,
|
||||||
|
Command: []string{"/bin/bash", "-cxe"},
|
||||||
|
Args: []string{
|
||||||
|
fmt.Sprintf(
|
||||||
|
"tar -czvpf test.tar -C /rootfs . && luet util pack %s test.tar image.tar && mv image.tar /public",
|
||||||
|
pushOptions.ImageName,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "rootfs",
|
||||||
|
MountPath: "/rootfs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
MountPath: "/public",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushImageContainer(containerImage string, pushOptions buildv1alpha1.Push) v1.Container {
|
||||||
|
return v1.Container{
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
Name: "push-image",
|
||||||
|
Image: containerImage,
|
||||||
|
Command: []string{"/bin/bash", "-cxe"},
|
||||||
|
Args: []string{
|
||||||
|
fmt.Sprintf(
|
||||||
|
"skopeo /public/image.tar %s",
|
||||||
|
pushOptions.ImageName,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
MountPath: "/public",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact) *appsv1.Deployment {
|
||||||
|
objMeta := metav1.ObjectMeta{
|
||||||
|
Name: artifact.Name,
|
||||||
|
Namespace: artifact.Namespace,
|
||||||
|
OwnerReferences: genOwner(artifact),
|
||||||
|
}
|
||||||
|
|
||||||
|
privileged := false
|
||||||
|
serviceAccount := false
|
||||||
|
|
||||||
|
buildIsoContainer := v1.Container{
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||||
|
Name: "build-iso",
|
||||||
|
Image: r.BuildImage,
|
||||||
|
Command: []string{"/bin/bash", "-cxe"},
|
||||||
|
Args: []string{
|
||||||
|
fmt.Sprintf(
|
||||||
|
"elemental --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /public dir:/rootfs",
|
||||||
|
artifact.Name,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
MountPath: "/public",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config",
|
||||||
|
MountPath: "/iso/iso-overlay/cloud_config.yaml",
|
||||||
|
SubPath: "config",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "grub",
|
||||||
|
MountPath: "/iso/iso-overlay/boot/grub2/grub.cfg",
|
||||||
|
SubPath: "grub.cfg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rootfs",
|
||||||
|
MountPath: "/rootfs",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
servingContainer := v1.Container{
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||||
|
Name: "serve",
|
||||||
|
Ports: []v1.ContainerPort{v1.ContainerPort{Name: "http", ContainerPort: 80}},
|
||||||
|
Image: r.ServingImage,
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
MountPath: "/usr/share/nginx/html",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pod := v1.PodSpec{
|
||||||
|
AutomountServiceAccountToken: &serviceAccount,
|
||||||
|
Volumes: []v1.Volume{
|
||||||
|
{
|
||||||
|
Name: "public",
|
||||||
|
VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rootfs",
|
||||||
|
VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "config",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||||
|
LocalObjectReference: v1.LocalObjectReference{Name: artifact.Name}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
pod.Containers = []v1.Container{servingContainer}
|
||||||
|
|
||||||
|
deploymentLabels := genDeploymentLabel(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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
/*
|
|
||||||
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"
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
|
|
||||||
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func unpackContainer(id, containerImage, pullImage string) corev1.Container {
|
|
||||||
return corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
Name: fmt.Sprintf("pull-image-%s", id),
|
|
||||||
Image: containerImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
fmt.Sprintf(
|
|
||||||
"luet util unpack %s %s",
|
|
||||||
pullImage,
|
|
||||||
"/rootfs",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "rootfs",
|
|
||||||
MountPath: "/rootfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func pushImageName(artifact *osbuilder.OSArtifact) string {
|
|
||||||
pushName := artifact.Spec.ImageName
|
|
||||||
if pushName != "" {
|
|
||||||
return pushName
|
|
||||||
}
|
|
||||||
return artifact.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func createImageContainer(containerImage string, artifact *osbuilder.OSArtifact) corev1.Container {
|
|
||||||
imageName := pushImageName(artifact)
|
|
||||||
|
|
||||||
return corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
Name: "create-image",
|
|
||||||
Image: containerImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
fmt.Sprintf(
|
|
||||||
"tar -czvpf test.tar -C /rootfs . && luet util pack %[1]s test.tar %[2]s.tar && chmod +r %[2]s.tar && mv %[2]s.tar /artifacts",
|
|
||||||
imageName,
|
|
||||||
artifact.Name,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "rootfs",
|
|
||||||
MountPath: "/rootfs",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "artifacts",
|
|
||||||
MountPath: "/artifacts",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func osReleaseContainer(containerImage string) corev1.Container {
|
|
||||||
return corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
Name: "os-release",
|
|
||||||
Image: containerImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
"cp -rfv /etc/os-release /rootfs/etc/os-release",
|
|
||||||
},
|
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "config",
|
|
||||||
MountPath: "/etc/os-release",
|
|
||||||
SubPath: "os-release",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "rootfs",
|
|
||||||
MountPath: "/rootfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) newArtifactPVC(artifact *osbuilder.OSArtifact) *corev1.PersistentVolumeClaim {
|
|
||||||
if artifact.Spec.Volume == nil {
|
|
||||||
artifact.Spec.Volume = &corev1.PersistentVolumeClaimSpec{
|
|
||||||
AccessModes: []corev1.PersistentVolumeAccessMode{
|
|
||||||
corev1.ReadWriteOnce,
|
|
||||||
},
|
|
||||||
Resources: corev1.ResourceRequirements{
|
|
||||||
Requests: map[corev1.ResourceName]resource.Quantity{
|
|
||||||
"storage": resource.MustParse("10Gi"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pvc := &corev1.PersistentVolumeClaim{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: artifact.Name + "-artifacts",
|
|
||||||
Namespace: artifact.Namespace,
|
|
||||||
},
|
|
||||||
Spec: *artifact.Spec.Volume,
|
|
||||||
}
|
|
||||||
|
|
||||||
return pvc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder.OSArtifact) *corev1.Pod {
|
|
||||||
cmd := fmt.Sprintf(
|
|
||||||
"/entrypoint.sh --debug --name %s build-iso --date=false --output /artifacts dir:/rootfs",
|
|
||||||
artifact.Name,
|
|
||||||
)
|
|
||||||
|
|
||||||
volumeMounts := []corev1.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "artifacts",
|
|
||||||
MountPath: "/artifacts",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "rootfs",
|
|
||||||
MountPath: "/rootfs",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.GRUBConfig != "" {
|
|
||||||
volumeMounts = append(volumeMounts, corev1.VolumeMount{
|
|
||||||
Name: "config",
|
|
||||||
MountPath: "/iso/iso-overlay/boot/grub2/grub.cfg",
|
|
||||||
SubPath: "grub.cfg",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
cloudImgCmd := fmt.Sprintf(
|
|
||||||
"/raw-images.sh /rootfs /artifacts/%s.raw",
|
|
||||||
artifact.Name,
|
|
||||||
)
|
|
||||||
|
|
||||||
if artifact.Spec.CloudConfigRef != nil {
|
|
||||||
volumeMounts = append(volumeMounts, corev1.VolumeMount{
|
|
||||||
Name: "cloudconfig",
|
|
||||||
MountPath: "/iso/iso-overlay/cloud_config.yaml",
|
|
||||||
SubPath: artifact.Spec.CloudConfigRef.Key,
|
|
||||||
})
|
|
||||||
|
|
||||||
cloudImgCmd += " /iso/iso-overlay/cloud_config.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.CloudConfigRef != nil || artifact.Spec.GRUBConfig != "" {
|
|
||||||
cmd = fmt.Sprintf(
|
|
||||||
"/entrypoint.sh --debug --name %s build-iso --date=false --overlay-iso /iso/iso-overlay --output /artifacts dir:/rootfs",
|
|
||||||
artifact.Name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
buildIsoContainer := corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
SecurityContext: &corev1.SecurityContext{Privileged: ptr(true)},
|
|
||||||
Name: "build-iso",
|
|
||||||
Image: r.ToolImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
cmd,
|
|
||||||
},
|
|
||||||
VolumeMounts: volumeMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
buildCloudImageContainer := corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
SecurityContext: &corev1.SecurityContext{Privileged: ptr(true)},
|
|
||||||
Name: "build-cloud-image",
|
|
||||||
Image: r.ToolImage,
|
|
||||||
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
cloudImgCmd,
|
|
||||||
},
|
|
||||||
VolumeMounts: volumeMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.DiskSize != "" {
|
|
||||||
buildCloudImageContainer.Env = []corev1.EnvVar{{
|
|
||||||
Name: "EXTEND",
|
|
||||||
Value: artifact.Spec.DiskSize,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
extractNetboot := corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
SecurityContext: &corev1.SecurityContext{Privileged: ptr(true)},
|
|
||||||
Name: "build-netboot",
|
|
||||||
Image: r.ToolImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Env: []corev1.EnvVar{{
|
|
||||||
Name: "URL",
|
|
||||||
Value: artifact.Spec.NetbootURL,
|
|
||||||
}},
|
|
||||||
Args: []string{
|
|
||||||
fmt.Sprintf(
|
|
||||||
"/netboot.sh /artifacts/%s.iso /artifacts/%s",
|
|
||||||
artifact.Name,
|
|
||||||
artifact.Name,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
VolumeMounts: volumeMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
buildAzureCloudImageContainer := corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
SecurityContext: &corev1.SecurityContext{Privileged: ptr(true)},
|
|
||||||
Name: "build-azure-cloud-image",
|
|
||||||
Image: r.ToolImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
fmt.Sprintf(
|
|
||||||
"/azure.sh /artifacts/%s.raw /artifacts/%s.vhd",
|
|
||||||
artifact.Name,
|
|
||||||
artifact.Name,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
VolumeMounts: volumeMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
buildGCECloudImageContainer := corev1.Container{
|
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
|
||||||
SecurityContext: &corev1.SecurityContext{Privileged: ptr(true)},
|
|
||||||
Name: "build-gce-cloud-image",
|
|
||||||
Image: r.ToolImage,
|
|
||||||
Command: []string{"/bin/bash", "-cxe"},
|
|
||||||
Args: []string{
|
|
||||||
fmt.Sprintf(
|
|
||||||
"/gce.sh /artifacts/%s.raw /artifacts/%s.gce.raw",
|
|
||||||
artifact.Name,
|
|
||||||
artifact.Name,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
VolumeMounts: volumeMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
podSpec := corev1.PodSpec{
|
|
||||||
AutomountServiceAccountToken: ptr(false),
|
|
||||||
RestartPolicy: corev1.RestartPolicyNever,
|
|
||||||
Volumes: []corev1.Volume{
|
|
||||||
{
|
|
||||||
Name: "artifacts",
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
|
|
||||||
ClaimName: pvcName,
|
|
||||||
ReadOnly: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "rootfs",
|
|
||||||
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "config",
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
|
||||||
LocalObjectReference: corev1.LocalObjectReference{
|
|
||||||
Name: artifact.Name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.CloudConfigRef != nil {
|
|
||||||
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
|
|
||||||
Name: "cloudconfig",
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
Secret: &corev1.SecretVolumeSource{
|
|
||||||
SecretName: artifact.Spec.CloudConfigRef.Name,
|
|
||||||
Optional: ptr(true),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range artifact.Spec.ImagePullSecrets {
|
|
||||||
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
podSpec.InitContainers = []corev1.Container{unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName)}
|
|
||||||
|
|
||||||
for i, bundle := range artifact.Spec.Bundles {
|
|
||||||
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer(fmt.Sprint(i), r.ToolImage, bundle))
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.OSRelease != "" {
|
|
||||||
podSpec.InitContainers = append(podSpec.InitContainers, osReleaseContainer(r.ToolImage))
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.ISO || artifact.Spec.Netboot {
|
|
||||||
podSpec.Containers = append(podSpec.Containers, buildIsoContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.Netboot {
|
|
||||||
podSpec.Containers = append(podSpec.Containers, extractNetboot)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.CloudImage {
|
|
||||||
podSpec.Containers = append(podSpec.Containers, buildCloudImageContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.AzureImage {
|
|
||||||
podSpec.Containers = append(podSpec.Containers, buildAzureCloudImageContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifact.Spec.GCEImage {
|
|
||||||
podSpec.Containers = append(podSpec.Containers, buildGCECloudImageContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
podSpec.Containers = append(podSpec.Containers, createImageContainer(r.ToolImage, artifact))
|
|
||||||
|
|
||||||
return &corev1.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
GenerateName: artifact.Name + "-",
|
|
||||||
Namespace: artifact.Namespace,
|
|
||||||
},
|
|
||||||
Spec: podSpec,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ptr[T any](val T) *T {
|
|
||||||
return &val
|
|
||||||
}
|
|
||||||
@@ -19,287 +19,159 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
"time"
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"sigs.k8s.io/cluster-api/util/patch"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
FinalizerName = "build.kairos.io/osbuilder-finalizer"
|
|
||||||
artifactLabel = "build.kairos.io/artifact"
|
|
||||||
artifactExporterIndexAnnotation = "build.kairos.io/export-index"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// OSArtifactReconciler reconciles a OSArtifact object
|
// OSArtifactReconciler reconciles a OSArtifact object
|
||||||
type OSArtifactReconciler struct {
|
type OSArtifactReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
ServingImage, ToolImage, CopierImage string
|
Scheme *runtime.Scheme
|
||||||
|
clientSet *kubernetes.Clientset
|
||||||
|
ServingImage, BuildImage, ToolImage string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) InjectClient(c client.Client) error {
|
func genOwner(artifact buildv1alpha1.OSArtifact) []metav1.OwnerReference {
|
||||||
r.Client = c
|
return []metav1.OwnerReference{
|
||||||
|
*metav1.NewControllerRef(&artifact.ObjectMeta, schema.GroupVersionKind{
|
||||||
return nil
|
Group: buildv1alpha1.GroupVersion.Group,
|
||||||
|
Version: buildv1alpha1.GroupVersion.Version,
|
||||||
|
Kind: "OSArtifact",
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//+kubebuilder:rbac:groups=build.kairos.io,resources=osartifacts,verbs=get;list;watch;create;update;patch;delete
|
//+kubebuilder:rbac:groups=build.c3os-x.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.c3os-x.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/finalizers,verbs=update
|
||||||
//+kubebuilder:rbac:groups="",resources=pods,verbs=get;list;watch;create;delete
|
|
||||||
//+kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=get;list;create;delete;watch
|
|
||||||
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;
|
|
||||||
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;create;
|
|
||||||
//+kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;delete
|
|
||||||
|
|
||||||
|
// 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 OSArtifact 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.1/pkg/reconcile
|
||||||
func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
|
|
||||||
var artifact osbuilder.OSArtifact
|
var osbuild buildv1alpha1.OSArtifact
|
||||||
if err := r.Get(ctx, req.NamespacedName, &artifact); err != nil {
|
if err := r.Get(ctx, req.NamespacedName, &osbuild); err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
if apierrors.IsNotFound(err) {
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if artifact.DeletionTimestamp != nil {
|
logger.Info(fmt.Sprintf("Reconciling %v", osbuild))
|
||||||
controllerutil.RemoveFinalizer(&artifact, FinalizerName)
|
|
||||||
return ctrl.Result{}, r.Update(ctx, &artifact)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !controllerutil.ContainsFinalizer(&artifact, FinalizerName) {
|
|
||||||
controllerutil.AddFinalizer(&artifact, FinalizerName)
|
|
||||||
if err := r.Update(ctx, &artifact); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info(fmt.Sprintf("Reconciling %s/%s", artifact.Namespace, artifact.Name))
|
|
||||||
|
|
||||||
switch artifact.Status.Phase {
|
|
||||||
case osbuilder.Exporting:
|
|
||||||
return r.checkExport(ctx, &artifact)
|
|
||||||
case osbuilder.Ready, osbuilder.Error:
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
default:
|
|
||||||
return r.checkBuild(ctx, &artifact)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
|
|
||||||
// generate configmap required for building a custom image
|
// generate configmap required for building a custom image
|
||||||
cm := r.genConfigMap(artifact)
|
desiredConfigMap := r.genConfigMap(osbuild)
|
||||||
if cm.Labels == nil {
|
logger.Info(fmt.Sprintf("Checking configmap %v", osbuild))
|
||||||
cm.Labels = map[string]string{}
|
|
||||||
}
|
cfgMap, err := r.clientSet.CoreV1().ConfigMaps(req.Namespace).Get(ctx, desiredConfigMap.Name, v1.GetOptions{})
|
||||||
cm.Labels[artifactLabel] = artifact.Name
|
if cfgMap == nil || apierrors.IsNotFound(err) {
|
||||||
if err := controllerutil.SetOwnerReference(artifact, cm, r.Scheme()); err != nil {
|
logger.Info(fmt.Sprintf("Creating service %v", desiredConfigMap))
|
||||||
|
|
||||||
|
cfgMap, err = r.clientSet.CoreV1().ConfigMaps(req.Namespace).Create(ctx, desiredConfigMap, v1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err, "Failed while creating svc")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
if err := r.Create(ctx, cm); err != nil && !apierrors.IsAlreadyExists(err) {
|
if err != nil {
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pvc := r.newArtifactPVC(artifact)
|
desiredService := genService(osbuild)
|
||||||
if pvc.Labels == nil {
|
logger.Info(fmt.Sprintf("Checking service %v", osbuild))
|
||||||
pvc.Labels = map[string]string{}
|
|
||||||
}
|
|
||||||
pvc.Labels[artifactLabel] = artifact.Name
|
|
||||||
if err := controllerutil.SetOwnerReference(artifact, pvc, r.Scheme()); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
if err := r.Create(ctx, pvc); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pod := r.newBuilderPod(pvc.Name, artifact)
|
svc, err := r.clientSet.CoreV1().Services(req.Namespace).Get(ctx, desiredService.Name, v1.GetOptions{})
|
||||||
if pod.Labels == nil {
|
if svc == nil || apierrors.IsNotFound(err) {
|
||||||
pod.Labels = map[string]string{}
|
logger.Info(fmt.Sprintf("Creating service %v", desiredService))
|
||||||
}
|
|
||||||
pod.Labels[artifactLabel] = artifact.Name
|
svc, err = r.clientSet.CoreV1().Services(req.Namespace).Create(ctx, desiredService, v1.CreateOptions{})
|
||||||
if err := controllerutil.SetOwnerReference(artifact, pod, r.Scheme()); err != nil {
|
if err != nil {
|
||||||
|
logger.Error(err, "Failed while creating svc")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
if err := r.Create(ctx, pod); err != nil {
|
if err != nil {
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
|
logger.Info(fmt.Sprintf("Checking deployment %v", osbuild))
|
||||||
|
|
||||||
artifact.Status.Phase = osbuilder.Building
|
desiredDeployment := r.genDeployment(osbuild)
|
||||||
if err := r.Status().Update(ctx, artifact); err != nil {
|
deployment, err := r.clientSet.AppsV1().Deployments(req.Namespace).Get(ctx, desiredDeployment.Name, v1.GetOptions{})
|
||||||
return ctrl.Result{Requeue: true}, err
|
if deployment == nil || apierrors.IsNotFound(err) {
|
||||||
}
|
logger.Info(fmt.Sprintf("Creating Deployment %v", deployment))
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
deployment, err = r.clientSet.AppsV1().Deployments(req.Namespace).Create(ctx, desiredDeployment, v1.CreateOptions{})
|
||||||
}
|
if err != nil {
|
||||||
|
logger.Error(err, "Failed while creating deployment")
|
||||||
func (r *OSArtifactReconciler) checkBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
|
|
||||||
var pods corev1.PodList
|
|
||||||
if err := r.List(ctx, &pods, &client.ListOptions{
|
|
||||||
LabelSelector: labels.SelectorFromSet(labels.Set{
|
|
||||||
artifactLabel: artifact.Name,
|
|
||||||
}),
|
|
||||||
}); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pod := range pods.Items {
|
|
||||||
switch pod.Status.Phase {
|
|
||||||
case corev1.PodSucceeded:
|
|
||||||
artifact.Status.Phase = osbuilder.Exporting
|
|
||||||
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, artifact)
|
|
||||||
case corev1.PodFailed:
|
|
||||||
artifact.Status.Phase = osbuilder.Error
|
|
||||||
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, artifact)
|
|
||||||
case corev1.PodPending, corev1.PodRunning:
|
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ctrl.Result{Requeue: true}, nil
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
return r.startBuild(ctx, artifact)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) checkExport(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
|
|
||||||
var jobs batchv1.JobList
|
|
||||||
if err := r.List(ctx, &jobs, &client.ListOptions{
|
|
||||||
LabelSelector: labels.SelectorFromSet(labels.Set{
|
|
||||||
artifactLabel: artifact.Name,
|
|
||||||
}),
|
|
||||||
}); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
return ctrl.Result{Requeue: true}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexedJobs := make(map[string]*batchv1.Job, len(artifact.Spec.Exporters))
|
logger.Info(fmt.Sprintf("Updating state %v", osbuild))
|
||||||
for _, job := range jobs.Items {
|
|
||||||
if job.GetAnnotations() != nil {
|
copy := osbuild.DeepCopy()
|
||||||
if idx, ok := job.GetAnnotations()[artifactExporterIndexAnnotation]; ok {
|
|
||||||
indexedJobs[idx] = &job
|
helper, err := patch.NewHelper(&osbuild, r.Client)
|
||||||
}
|
if err != nil {
|
||||||
}
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
|
if deployment.Status.ReadyReplicas == deployment.Status.Replicas {
|
||||||
|
copy.Status.Phase = "Ready"
|
||||||
|
} else if copy.Status.Phase != "Building" {
|
||||||
|
copy.Status.Phase = "Building"
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := helper.Patch(ctx, copy); err != nil {
|
||||||
|
return ctrl.Result{}, errors.Wrapf(err, "couldn't patch osbuild %q", copy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pvcs corev1.PersistentVolumeClaimList
|
// for _, c := range append(pod.Status.ContainerStatuses, pod.Status.InitContainerStatuses...) {
|
||||||
var pvc *corev1.PersistentVolumeClaim
|
// if c.State.Terminated != nil && c.State.Terminated.ExitCode != 0 {
|
||||||
if err := r.List(ctx, &pvcs, &client.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{artifactLabel: artifact.Name})}); err != nil {
|
// packageBuildCopy.Status.State = "Failed"
|
||||||
return ctrl.Result{Requeue: true}, err
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
for _, item := range pvcs.Items {
|
|
||||||
pvc = &item
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if pvc == nil {
|
|
||||||
log.FromContext(ctx).Error(nil, "failed to locate pvc for artifact, this should not happen")
|
|
||||||
return ctrl.Result{}, fmt.Errorf("failed to locate artifact pvc")
|
|
||||||
}
|
|
||||||
|
|
||||||
var succeeded int
|
|
||||||
for i := range artifact.Spec.Exporters {
|
|
||||||
idx := fmt.Sprintf("%d", i)
|
|
||||||
|
|
||||||
job := indexedJobs[idx]
|
|
||||||
if job == nil {
|
|
||||||
job = &batchv1.Job{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: fmt.Sprintf("%s-export-%s", artifact.Name, idx),
|
|
||||||
Namespace: artifact.Namespace,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
artifactExporterIndexAnnotation: idx,
|
|
||||||
},
|
|
||||||
Labels: map[string]string{
|
|
||||||
artifactLabel: artifact.Name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: artifact.Spec.Exporters[i],
|
|
||||||
}
|
|
||||||
|
|
||||||
job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, corev1.Volume{
|
|
||||||
Name: "artifacts",
|
|
||||||
VolumeSource: corev1.VolumeSource{
|
|
||||||
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
|
|
||||||
ClaimName: pvc.Name,
|
|
||||||
ReadOnly: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := controllerutil.SetOwnerReference(artifact, job, r.Scheme()); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.Create(ctx, job); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if job.Spec.Completions == nil || *job.Spec.Completions == 1 {
|
|
||||||
if job.Status.Succeeded > 0 {
|
|
||||||
succeeded++
|
|
||||||
}
|
|
||||||
} else if *job.Spec.BackoffLimit <= job.Status.Failed {
|
|
||||||
artifact.Status.Phase = osbuilder.Error
|
|
||||||
if err := r.Status().Update(ctx, artifact); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded == len(artifact.Spec.Exporters) {
|
|
||||||
artifact.Status.Phase = osbuilder.Ready
|
|
||||||
if err := r.Status().Update(ctx, artifact); err != nil {
|
|
||||||
return ctrl.Result{Requeue: true}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *OSArtifactReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *OSArtifactReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
|
|
||||||
|
clientset, err := kubernetes.NewForConfig(mgr.GetConfig())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.clientSet = clientset
|
||||||
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
For(&osbuilder.OSArtifact{}).
|
For(&buildv1alpha1.OSArtifact{}).
|
||||||
Owns(&osbuilder.OSArtifact{}).
|
|
||||||
Watches(
|
|
||||||
&source.Kind{Type: &corev1.Pod{}},
|
|
||||||
handler.EnqueueRequestsFromMapFunc(r.findOwningArtifact),
|
|
||||||
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
|
|
||||||
).
|
|
||||||
Watches(
|
|
||||||
&source.Kind{Type: &batchv1.Job{}},
|
|
||||||
handler.EnqueueRequestsFromMapFunc(r.findOwningArtifact),
|
|
||||||
builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}),
|
|
||||||
).
|
|
||||||
Complete(r)
|
Complete(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OSArtifactReconciler) findOwningArtifact(obj client.Object) []reconcile.Request {
|
|
||||||
if obj.GetLabels() == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if artifactName, ok := obj.GetLabels()[artifactLabel]; ok {
|
|
||||||
return []reconcile.Request{
|
|
||||||
{
|
|
||||||
NamespacedName: types.NamespacedName{
|
|
||||||
Name: artifactName,
|
|
||||||
Namespace: obj.GetNamespace(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
39
controllers/service.go
Normal file
39
controllers/service.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
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 {
|
||||||
|
objMeta := metav1.ObjectMeta{
|
||||||
|
Name: artifact.Name,
|
||||||
|
Namespace: artifact.Namespace,
|
||||||
|
OwnerReferences: genOwner(artifact),
|
||||||
|
}
|
||||||
|
return &v1.Service{
|
||||||
|
ObjectMeta: objMeta,
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Ports: []v1.ServicePort{{Name: "http", Port: int32(80), TargetPort: intstr.FromInt(80)}},
|
||||||
|
Selector: genDeploymentLabel(artifact.Name),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
"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
|
//+kubebuilder:scaffold:imports
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
28
go.mod
28
go.mod
@@ -1,11 +1,11 @@
|
|||||||
module github.com/kairos-io/osbuilder
|
module github.com/c3os-io/osbuilder-operator
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/onsi/ginkgo v1.16.5
|
github.com/onsi/ginkgo v1.16.5
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5
|
github.com/onsi/ginkgo/v2 v2.1.3
|
||||||
github.com/onsi/gomega v1.27.7
|
github.com/onsi/gomega v1.18.1
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rancher-sandbox/ele-testhelpers v0.0.0-20220614101555-2eddf3b113e2
|
github.com/rancher-sandbox/ele-testhelpers v0.0.0-20220614101555-2eddf3b113e2
|
||||||
k8s.io/api v0.24.0
|
k8s.io/api v0.24.0
|
||||||
@@ -33,27 +33,24 @@ require (
|
|||||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||||
github.com/go-logr/logr v1.2.4 // indirect
|
github.com/go-logr/logr v1.2.0 // indirect
|
||||||
github.com/go-logr/zapr v1.2.0 // indirect
|
github.com/go-logr/zapr v1.2.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||||
github.com/go-openapi/swag v0.19.14 // indirect
|
github.com/go-openapi/swag v0.19.14 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
|
||||||
github.com/gobuffalo/flect v0.2.4 // indirect
|
github.com/gobuffalo/flect v0.2.4 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/gnostic v0.5.7-v3refs // indirect
|
github.com/google/gnostic v0.5.7-v3refs // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.6 // indirect
|
github.com/mailru/easyjson v0.7.6 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
github.com/moby/spdystream v0.2.0 // indirect
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
@@ -67,20 +64,19 @@ require (
|
|||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.21.0 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
|
||||||
golang.org/x/term v0.8.0 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||||
golang.org/x/tools v0.9.1 // indirect
|
|
||||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.24.0 // indirect
|
k8s.io/apiextensions-apiserver v0.24.0 // indirect
|
||||||
k8s.io/component-base v0.24.0 // indirect
|
k8s.io/component-base v0.24.0 // indirect
|
||||||
k8s.io/klog/v2 v2.60.1 // indirect
|
k8s.io/klog/v2 v2.60.1 // indirect
|
||||||
|
|||||||
31
go.sum
31
go.sum
@@ -82,7 +82,6 @@ github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.m
|
|||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
@@ -137,7 +136,6 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
|
|||||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
|
||||||
@@ -179,8 +177,6 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
|
|||||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||||
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
|
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
|
||||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
|
||||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
|
||||||
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
|
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
|
||||||
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
@@ -194,8 +190,6 @@ github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5F
|
|||||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
|
||||||
github.com/gobuffalo/flect v0.2.4 h1:BSYA8+T60cdyq+vynaSUjqSVI9mDEg9ZfQUXKmfjo4I=
|
github.com/gobuffalo/flect v0.2.4 h1:BSYA8+T60cdyq+vynaSUjqSVI9mDEg9ZfQUXKmfjo4I=
|
||||||
github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8=
|
github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@@ -239,8 +233,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
|||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@@ -263,8 +255,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
@@ -383,7 +373,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
|||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -415,18 +404,12 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042
|
|||||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
|
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
|
||||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
|
||||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
|
||||||
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
@@ -666,8 +649,6 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@@ -765,13 +746,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -782,8 +759,6 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -852,8 +827,6 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||||
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
|
|
||||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -991,8 +964,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -1023,8 +994,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
21
main.go
21
main.go
@@ -31,8 +31,8 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
|
||||||
buildv1alpha2 "github.com/kairos-io/osbuilder/api/v1alpha2"
|
buildv1alpha1 "github.com/c3os-io/osbuilder-operator/api/v1alpha1"
|
||||||
"github.com/kairos-io/osbuilder/controllers"
|
"github.com/c3os-io/osbuilder-operator/controllers"
|
||||||
//+kubebuilder:scaffold:imports
|
//+kubebuilder:scaffold:imports
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
|
||||||
utilruntime.Must(buildv1alpha2.AddToScheme(scheme))
|
utilruntime.Must(buildv1alpha1.AddToScheme(scheme))
|
||||||
//+kubebuilder:scaffold:scheme
|
//+kubebuilder:scaffold:scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,12 +52,11 @@ func main() {
|
|||||||
var metricsAddr string
|
var metricsAddr string
|
||||||
var enableLeaderElection bool
|
var enableLeaderElection bool
|
||||||
var probeAddr string
|
var probeAddr string
|
||||||
var serveImage, toolImage, copierImage string
|
var buildImage, serveImage, toolImage string
|
||||||
|
|
||||||
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
|
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.")
|
||||||
// It needs luet inside
|
flag.StringVar(&serveImage, "serve-image", "nginx", "Serve image.")
|
||||||
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.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||||
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||||
@@ -77,7 +76,7 @@ func main() {
|
|||||||
Port: 9443,
|
Port: 9443,
|
||||||
HealthProbeBindAddress: probeAddr,
|
HealthProbeBindAddress: probeAddr,
|
||||||
LeaderElection: enableLeaderElection,
|
LeaderElection: enableLeaderElection,
|
||||||
LeaderElectionID: "98ca89ca.kairos.io",
|
LeaderElectionID: "98ca89ca.c3os-x.io",
|
||||||
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
||||||
// when the Manager ends. This requires the binary to immediately end when the
|
// when the Manager ends. This requires the binary to immediately end when the
|
||||||
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
||||||
@@ -96,9 +95,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = (&controllers.OSArtifactReconciler{
|
if err = (&controllers.OSArtifactReconciler{
|
||||||
|
Client: mgr.GetClient(),
|
||||||
ServingImage: serveImage,
|
ServingImage: serveImage,
|
||||||
ToolImage: toolImage,
|
ToolImage: toolImage,
|
||||||
CopierImage: copierImage,
|
BuildImage: buildImage,
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
}).SetupWithManager(mgr); err != nil {
|
}).SetupWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
|
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": [
|
|
||||||
"config:base"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
KUBE_VERSION=${KUBE_VERSION:-v1.22.7}
|
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
|
if ! kind get clusters | grep "$CLUSTER_NAME"; then
|
||||||
cat << EOF > kind.config
|
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 EXTERNAL_IP=$(kubectl get nodes -o jsonpath='{.items[].status.addresses[?(@.type == "InternalIP")].address}')
|
||||||
export BRIDGE_IP="172.18.0.1"
|
export BRIDGE_IP="172.18.0.1"
|
||||||
kubectl get nodes -o wide
|
kubectl get nodes -o wide
|
||||||
cd $ROOT_DIR/tests && $GINKGO -r -v ./e2e
|
cd $ROOT_DIR/tests && ginkgo -r -v ./e2e
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package e2e_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/selection"
|
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
"k8s.io/client-go/dynamic"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("ISO build test", func() {
|
|
||||||
k8s := dynamic.NewForConfigOrDie(ctrl.GetConfigOrDie())
|
|
||||||
scheme := runtime.NewScheme()
|
|
||||||
_ = osbuilder.AddToScheme(scheme)
|
|
||||||
|
|
||||||
var artifactName string
|
|
||||||
artifacts := k8s.Resource(schema.GroupVersionResource{Group: osbuilder.GroupVersion.Group, Version: osbuilder.GroupVersion.Version, Resource: "osartifacts"}).Namespace("default")
|
|
||||||
pods := k8s.Resource(schema.GroupVersionResource{Group: corev1.GroupName, Version: corev1.SchemeGroupVersion.Version, Resource: "pods"}).Namespace("default")
|
|
||||||
pvcs := k8s.Resource(schema.GroupVersionResource{Group: corev1.GroupName, Version: corev1.SchemeGroupVersion.Version, Resource: "persistentvolumeclaims"}).Namespace("default")
|
|
||||||
jobs := k8s.Resource(schema.GroupVersionResource{Group: batchv1.GroupName, Version: batchv1.SchemeGroupVersion.Version, Resource: "jobs"}).Namespace("default")
|
|
||||||
|
|
||||||
artifact := &osbuilder.OSArtifact{
|
|
||||||
TypeMeta: metav1.TypeMeta{
|
|
||||||
Kind: "OSArtifact",
|
|
||||||
APIVersion: osbuilder.GroupVersion.String(),
|
|
||||||
},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
GenerateName: "simple-",
|
|
||||||
},
|
|
||||||
Spec: osbuilder.OSArtifactSpec{
|
|
||||||
ImageName: "quay.io/kairos/core-opensuse:latest",
|
|
||||||
ISO: true,
|
|
||||||
DiskSize: "",
|
|
||||||
Exporters: []batchv1.JobSpec{
|
|
||||||
{
|
|
||||||
Template: corev1.PodTemplateSpec{
|
|
||||||
Spec: corev1.PodSpec{
|
|
||||||
RestartPolicy: corev1.RestartPolicyNever,
|
|
||||||
Containers: []corev1.Container{
|
|
||||||
{
|
|
||||||
Name: "test",
|
|
||||||
Image: "debian:latest",
|
|
||||||
Command: []string{"bash"},
|
|
||||||
Args: []string{"-xec", "[ -f /artifacts/*.iso ]"},
|
|
||||||
VolumeMounts: []corev1.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "artifacts",
|
|
||||||
ReadOnly: true,
|
|
||||||
MountPath: "/artifacts",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
uArtifact := unstructured.Unstructured{}
|
|
||||||
uArtifact.Object, _ = runtime.DefaultUnstructuredConverter.ToUnstructured(artifact)
|
|
||||||
resp, err := artifacts.Create(context.TODO(), &uArtifact, metav1.CreateOptions{})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
artifactName = resp.GetName()
|
|
||||||
|
|
||||||
Context("simple", func() {
|
|
||||||
artifactLabelSelectorReq, _ := labels.NewRequirement("build.kairos.io/artifact", selection.Equals, []string{artifactName})
|
|
||||||
artifactLabelSelector := labels.NewSelector().Add(*artifactLabelSelectorReq)
|
|
||||||
|
|
||||||
It("starts the build", func() {
|
|
||||||
Eventually(func(g Gomega) {
|
|
||||||
w, err := pods.Watch(context.TODO(), metav1.ListOptions{LabelSelector: artifactLabelSelector.String()})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
var stopped bool
|
|
||||||
for !stopped {
|
|
||||||
event, ok := <-w.ResultChan()
|
|
||||||
|
|
||||||
stopped = event.Type != watch.Deleted && event.Type != watch.Error || !ok
|
|
||||||
}
|
|
||||||
}).WithTimeout(time.Hour).Should(Succeed())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("exports the artifacts", func() {
|
|
||||||
Eventually(func(g Gomega) {
|
|
||||||
w, err := jobs.Watch(context.TODO(), metav1.ListOptions{LabelSelector: artifactLabelSelector.String()})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
var stopped bool
|
|
||||||
for !stopped {
|
|
||||||
event, ok := <-w.ResultChan()
|
|
||||||
|
|
||||||
stopped = event.Type != watch.Deleted && event.Type != watch.Error || !ok
|
|
||||||
}
|
|
||||||
}).WithTimeout(time.Hour).Should(Succeed())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("artifact successfully builds", func() {
|
|
||||||
Eventually(func(g Gomega) {
|
|
||||||
w, err := artifacts.Watch(context.TODO(), metav1.ListOptions{})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
var artifact osbuilder.OSArtifact
|
|
||||||
var stopped bool
|
|
||||||
for !stopped {
|
|
||||||
event, ok := <-w.ResultChan()
|
|
||||||
stopped = !ok
|
|
||||||
|
|
||||||
if event.Type == watch.Modified && event.Object.(*unstructured.Unstructured).GetName() == artifactName {
|
|
||||||
err := scheme.Convert(event.Object, &artifact, nil)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
stopped = artifact.Status.Phase == osbuilder.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}).WithTimeout(time.Hour).Should(Succeed())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("cleans up resources on deleted", func() {
|
|
||||||
err := artifacts.Delete(context.TODO(), artifactName, metav1.DeleteOptions{})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
Eventually(func(g Gomega) int {
|
|
||||||
res, err := artifacts.List(context.TODO(), metav1.ListOptions{})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
return len(res.Items)
|
|
||||||
}).WithTimeout(time.Minute).Should(Equal(0))
|
|
||||||
Eventually(func(g Gomega) int {
|
|
||||||
res, err := pods.List(context.TODO(), metav1.ListOptions{LabelSelector: artifactLabelSelector.String()})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
return len(res.Items)
|
|
||||||
}).WithTimeout(time.Minute).Should(Equal(0))
|
|
||||||
Eventually(func(g Gomega) int {
|
|
||||||
res, err := pvcs.List(context.TODO(), metav1.ListOptions{LabelSelector: artifactLabelSelector.String()})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
return len(res.Items)
|
|
||||||
}).WithTimeout(time.Minute).Should(Equal(0))
|
|
||||||
Eventually(func(g Gomega) int {
|
|
||||||
res, err := jobs.List(context.TODO(), metav1.ListOptions{LabelSelector: artifactLabelSelector.String()})
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
return len(res.Items)
|
|
||||||
}).WithTimeout(time.Minute).Should(Equal(0))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,13 +1,39 @@
|
|||||||
package e2e_test
|
package e2e_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"time"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
kubectl "github.com/rancher-sandbox/ele-testhelpers/kubectl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestE2e(t *testing.T) {
|
var _ = Describe("ISO build test", func() {
|
||||||
RegisterFailHandler(Fail)
|
//k := kubectl.New()
|
||||||
RunSpecs(t, "kairos-operator e2e test Suite")
|
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
13
tests/e2e/e2e_test.go
Normal 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")
|
||||||
|
}
|
||||||
53
tests/fixtures/simple.yaml
vendored
53
tests/fixtures/simple.yaml
vendored
@@ -1,52 +1,7 @@
|
|||||||
apiVersion: build.kairos.io/v1alpha1
|
apiVersion: build.c3os-x.io/v1alpha1
|
||||||
kind: OSArtifact
|
kind: OSArtifact
|
||||||
metadata:
|
metadata:
|
||||||
name: hello-kairos
|
name: hello-c3os
|
||||||
spec:
|
spec:
|
||||||
imageName: "quay.io/kairos/core-opensuse:latest"
|
imageName: "quay.io/c3os/c3os:opensuse-latest"
|
||||||
iso: true
|
iso: true
|
||||||
bundles:
|
|
||||||
- quay.io/kairos/packages:goreleaser-utils-1.13.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
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
# https://quay.io/repository/kairos/packages?tab=tags&tag=latest
|
|
||||||
ARG LEAP_VERSION=15.4
|
|
||||||
ARG LUET_VERSION=0.33.0
|
|
||||||
FROM quay.io/luet/base:$LUET_VERSION AS luet
|
|
||||||
|
|
||||||
FROM opensuse/leap:$LEAP_VERSION as luet-install
|
|
||||||
COPY --from=luet /usr/bin/luet /usr/bin/luet
|
|
||||||
ENV LUET_NOLOCK=true
|
|
||||||
ENV TMPDIR=/tmp
|
|
||||||
COPY luet.yaml /etc/luet/luet.yaml
|
|
||||||
RUN luet install -y system/elemental-cli
|
|
||||||
RUN luet install -y livecd/grub2 --system-target /grub2
|
|
||||||
RUN luet install -y livecd/grub2-efi-image --system-target /efi
|
|
||||||
|
|
||||||
# remove luet tmp files. Side effect of setting the system-target is that it treats it as a root fs
|
|
||||||
RUN rm -Rf /grub2/var
|
|
||||||
RUN rm -Rf /efi/var
|
|
||||||
|
|
||||||
## amd64 Live CD artifacts
|
|
||||||
FROM quay.io/kairos/packages:grub2-livecd-0.0.6 AS grub2
|
|
||||||
FROM quay.io/kairos/packages:grub2-efi-image-livecd-0.0.6 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.2 AS grub-efi
|
|
||||||
FROM quay.io/kairos/packages-arm64:grub-config-static-0.3 AS grub-config
|
|
||||||
FROM quay.io/kairos/packages-arm64:grub-artifacts-static-0.2 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=luet-install /usr/bin/elemental /usr/bin/elemental
|
|
||||||
COPY --from=luet /usr/bin/luet /usr/bin/luet
|
|
||||||
|
|
||||||
# ISO files
|
|
||||||
COPY --from=luet-install /grub2 /grub2
|
|
||||||
COPY --from=luet-install /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
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
# ARM helpers
|
|
||||||
COPY ./build-arm-image.sh /build-arm-image.sh
|
|
||||||
COPY ./arm /arm
|
|
||||||
COPY ./prepare_arm_images.sh /prepare_arm_images.sh
|
|
||||||
|
|
||||||
# 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" ]
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/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}"
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/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"
|
|
||||||
@@ -1,484 +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}
|
|
||||||
disable_lvm=${DISABLE_LVM:-false}
|
|
||||||
directory=${DIRECTORY:-}
|
|
||||||
output_image="${OUTPUT_IMAGE:-arm.img}"
|
|
||||||
# Img creation options. Size is in MB for all of the vars below
|
|
||||||
size="${SIZE:-7608}"
|
|
||||||
state_size="${STATE_SIZE:-4992}"
|
|
||||||
oem_size="${OEM_SIZE:-64}"
|
|
||||||
recovery_size="${RECOVERY_SIZE:-2192}"
|
|
||||||
default_active_size="${DEFAULT_ACTIVE_SIZE:-2400}"
|
|
||||||
menu_entry="${DEFAULT_MENU_ENTRY:-Kairos}"
|
|
||||||
|
|
||||||
## 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 "${LOOP}" || 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"
|
|
||||||
echo " --disable-lvm: (optional- no arguments) LVM for the recovery and oem partitions will be disabled"
|
|
||||||
echo " --use-lvm: (deprecated and ignored. Kept for backwards compatibility)"
|
|
||||||
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
|
|
||||||
;;
|
|
||||||
--disable-lvm)
|
|
||||||
disable_lvm=true
|
|
||||||
;;
|
|
||||||
--use-lvm)
|
|
||||||
disable_lvm=false
|
|
||||||
;;
|
|
||||||
-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
|
|
||||||
|
|
||||||
# We copy the grubmenu.cfg to a temporary location to be copied later in the state partition
|
|
||||||
# https://github.com/kairos-io/kairos/blob/62c67e3e61d49435c362014522e5c6696335376f/overlay/files/system/oem/08_grub.yaml#L105
|
|
||||||
# This is a hack and we need a better way: https://github.com/kairos-io/kairos/issues/1427
|
|
||||||
tmpgrubconfig=$(mktemp /tmp/grubmeny.cfg.XXXXXX)
|
|
||||||
cp -rfv $TARGET/etc/kairos/branding/grubmenu.cfg "${tmpgrubconfig}"
|
|
||||||
|
|
||||||
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/fonts
|
|
||||||
cp -rfv /arm/grub/artifacts/* $RECOVERY/grub2
|
|
||||||
mv $RECOVERY/grub2/*pf2 $RECOVERY/grub2/fonts
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
partprobe
|
|
||||||
|
|
||||||
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}
|
|
||||||
if [ "$disable_lvm" == 'true' ]; then
|
|
||||||
sgdisk -n 3:0:+${recovery_size}M -c 3:recovery -t 3:8300 ${output_image}
|
|
||||||
else
|
|
||||||
sgdisk -n 3:0:+$(( ${recovery_size} + ${oem_size} ))M -c 3:lvm -t 3:8e00 ${output_image}
|
|
||||||
fi
|
|
||||||
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
|
|
||||||
oem_lv=/dev/mapper/KairosVG-oem
|
|
||||||
recovery_lv=/dev/mapper/KairosVG-recovery
|
|
||||||
|
|
||||||
# Create partitions (RECOVERY, STATE, COS_PERSISTENT)
|
|
||||||
mkfs.vfat -F 32 ${efi}
|
|
||||||
fatlabel ${efi} COS_GRUB
|
|
||||||
|
|
||||||
if [ "$disable_lvm" == 'true' ]; then
|
|
||||||
mkfs.ext4 -F -L ${RECOVERY_LABEL} $recovery
|
|
||||||
else
|
|
||||||
pvcreate $recovery
|
|
||||||
vgcreate KairosVG $recovery
|
|
||||||
lvcreate -Z n -n oem -L ${oem_size} KairosVG
|
|
||||||
lvcreate -Z n -n recovery -l 100%FREE KairosVG
|
|
||||||
vgchange -ay
|
|
||||||
vgmknodes
|
|
||||||
mkfs.ext4 -F -L ${OEM_LABEL} $oem_lv
|
|
||||||
mkfs.ext4 -F -L ${RECOVERY_LABEL} $recovery_lv
|
|
||||||
fi
|
|
||||||
mkfs.ext4 -F -L ${STATE_LABEL} $state
|
|
||||||
mkfs.ext4 -F -L ${PERSISTENT_LABEL} $persistent
|
|
||||||
|
|
||||||
mkdir $WORKDIR/state
|
|
||||||
mkdir $WORKDIR/recovery
|
|
||||||
mkdir $WORKDIR/efi
|
|
||||||
|
|
||||||
if [ "$disable_lvm" == 'true' ]; then
|
|
||||||
mount $recovery $WORKDIR/recovery
|
|
||||||
else
|
|
||||||
mount $recovery_lv $WORKDIR/recovery
|
|
||||||
fi
|
|
||||||
mount $state $WORKDIR/state
|
|
||||||
mount $efi $WORKDIR/efi
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$disable_lvm" == "false" ]; then
|
|
||||||
mkdir $WORKDIR/oem
|
|
||||||
mount $oem_lv $WORKDIR/oem
|
|
||||||
|
|
||||||
cp -rfv /defaults.yaml $WORKDIR/oem/01_defaults.yaml
|
|
||||||
|
|
||||||
# Set a OEM config file if specified
|
|
||||||
if [ -n "$config" ]; then
|
|
||||||
echo ">> Copying $config OEM config file"
|
|
||||||
get_url $config $WORKDIR/oem/99_custom.yaml
|
|
||||||
fi
|
|
||||||
|
|
||||||
umount $WORKDIR/oem
|
|
||||||
else
|
|
||||||
echo "LVM disabled: Not adding default config with default user/pass and custom config file"
|
|
||||||
echo "Enable LVM to copy those files into /oem"
|
|
||||||
fi
|
|
||||||
|
|
||||||
grub2-editenv $WORKDIR/state/grub_oem_env set "default_menu_entry=$menu_entry"
|
|
||||||
|
|
||||||
# We copy the file we saved earier to the STATE partition
|
|
||||||
cp -rfv "${tmpgrubconfig}" $WORKDIR/state/grubmenu
|
|
||||||
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
if [ "$disable_lvm" == 'false' ]; then
|
|
||||||
vgchange -an
|
|
||||||
fi
|
|
||||||
sync
|
|
||||||
|
|
||||||
# Flash uboot and vendor-specific bits
|
|
||||||
echo ">> Performing $model specific bits.."
|
|
||||||
/arm/boards/$model.sh ${DRIVE}
|
|
||||||
|
|
||||||
sync
|
|
||||||
sleep 5
|
|
||||||
sync
|
|
||||||
|
|
||||||
kpartx -dv $DRIVE || true
|
|
||||||
|
|
||||||
umount $DRIVE || true
|
|
||||||
|
|
||||||
echo ">> Done writing $output_image"
|
|
||||||
|
|
||||||
echo ">> Creating SHA256 sum"
|
|
||||||
|
|
||||||
sha256sum $output_image > $output_image.sha256
|
|
||||||
|
|
||||||
cleanup
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
iso:
|
|
||||||
uefi:
|
|
||||||
- dir:/efi
|
|
||||||
image:
|
|
||||||
- dir:/efi
|
|
||||||
- dir:/grub2
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#cloud-config
|
|
||||||
name: "Default user"
|
|
||||||
stages:
|
|
||||||
initramfs:
|
|
||||||
- name: "Set default user/pass"
|
|
||||||
users:
|
|
||||||
kairos:
|
|
||||||
passwd: "kairos"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
elemental --config-dir /config $@
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
general:
|
|
||||||
debug: false
|
|
||||||
spinner_charset: 9
|
|
||||||
logging:
|
|
||||||
enable_emoji: false
|
|
||||||
repositories:
|
|
||||||
- name: "kairos"
|
|
||||||
description: "kairos repository"
|
|
||||||
type: "docker"
|
|
||||||
arch: amd64
|
|
||||||
cached: true
|
|
||||||
priority: 2
|
|
||||||
urls:
|
|
||||||
- "quay.io/kairos/packages"
|
|
||||||
reference: 20230512113938-repository.yaml
|
|
||||||
- name: "kairos-arm64"
|
|
||||||
description: "kairos repository arm64"
|
|
||||||
type: "docker"
|
|
||||||
arch: arm64
|
|
||||||
cached: true
|
|
||||||
priority: 2
|
|
||||||
urls:
|
|
||||||
- "quay.io/kairos/packages-arm64"
|
|
||||||
reference: 20230512115044-repository.yaml
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This script prepares Kairos state, recovery, oem and pesistent partitions as img files.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Temp dir used during build
|
|
||||||
WORKDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
|
|
||||||
TARGET=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
|
|
||||||
STATEDIR=$(mktemp -d --tmpdir arm-builder.XXXXXXXXXX)
|
|
||||||
|
|
||||||
: "${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}"
|
|
||||||
|
|
||||||
size="${SIZE:-7544}"
|
|
||||||
state_size="${STATE_SIZE:-4992}"
|
|
||||||
recovery_size="${RECOVERY_SIZE:-2192}"
|
|
||||||
default_active_size="${DEFAULT_ACTIVE_SIZE:-2400}"
|
|
||||||
menu_entry="${DEFAULT_MENU_ENTRY:-Kairos}"
|
|
||||||
|
|
||||||
container_image="${container_image:-quay.io/kairos/kairos-opensuse-leap-arm-rpi:v1.5.1-k3sv1.25.6-k3s1}"
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdir -p $WORKDIR/tmpefi
|
|
||||||
|
|
||||||
# Create the EFI partition FAT16 and include the EFI image and a basic grub.cfg
|
|
||||||
truncate -s $((20*1024*1024)) bootloader/efi.img
|
|
||||||
cp -rfv /arm/grub/efi/* $WORKDIR/tmpefi
|
|
||||||
mkfs.fat -F16 -n COS_GRUB bootloader/efi.img
|
|
||||||
mcopy -s -i bootloader/efi.img $WORKDIR/tmpefi/EFI ::EFI
|
|
||||||
|
|
||||||
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}
|
|
||||||
|
|
||||||
|
|
||||||
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"
|
|
||||||
luet util unpack $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
|
|
||||||
|
|
||||||
# We copy the grubmenu.cfg to a temporary location to be copied later in the state partition
|
|
||||||
# https://github.com/kairos-io/kairos/blob/62c67e3e61d49435c362014522e5c6696335376f/overlay/files/system/oem/08_grub.yaml#L105
|
|
||||||
# This is a hack and we need a better way: https://github.com/kairos-io/kairos/issues/1427
|
|
||||||
tmpgrubconfig=$(mktemp /tmp/grubmeny.cfg.XXXXXX)
|
|
||||||
cp -rfv $TARGET/etc/kairos/branding/grubmenu.cfg "${tmpgrubconfig}"
|
|
||||||
|
|
||||||
umount $TARGET
|
|
||||||
sync
|
|
||||||
|
|
||||||
losetup -d $LOOP
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
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/fonts
|
|
||||||
cp -rfv /arm/grub/artifacts/* $RECOVERY/grub2
|
|
||||||
mv $RECOVERY/grub2/*pf2 $RECOVERY/grub2/fonts
|
|
||||||
|
|
||||||
dd if=/dev/zero of=recovery_partition.img bs=1M count=$recovery_size
|
|
||||||
dd if=/dev/zero of=state_partition.img bs=1M count=$state_size
|
|
||||||
|
|
||||||
mkfs.ext4 -F -L ${RECOVERY_LABEL} recovery_partition.img
|
|
||||||
LOOP=$(losetup --show -f recovery_partition.img)
|
|
||||||
mkdir -p $WORKDIR/recovery
|
|
||||||
mount $LOOP $WORKDIR/recovery
|
|
||||||
cp -arf $RECOVERY/* $WORKDIR/recovery
|
|
||||||
umount $WORKDIR/recovery
|
|
||||||
losetup -d $LOOP
|
|
||||||
|
|
||||||
mkfs.ext4 -F -L ${STATE_LABEL} state_partition.img
|
|
||||||
LOOP=$(losetup --show -f state_partition.img)
|
|
||||||
mkdir -p $WORKDIR/state
|
|
||||||
mount $LOOP $WORKDIR/state
|
|
||||||
cp -arf $STATEDIR/* $WORKDIR/state
|
|
||||||
grub2-editenv $WORKDIR/state/grub_oem_env set "default_menu_entry=$menu_entry"
|
|
||||||
|
|
||||||
# We copy the file we saved earier to the STATE partition
|
|
||||||
cp -rfv "${tmpgrubconfig}" $WORKDIR/state/grubmenu
|
|
||||||
|
|
||||||
umount $WORKDIR/state
|
|
||||||
losetup -d $LOOP
|
|
||||||
|
|
||||||
cp -rfv state_partition.img bootloader/
|
|
||||||
cp -rfv recovery_partition.img bootloader/
|
|
||||||
|
|
||||||
## Optional, prepare COS_OEM and COS_PERSISTENT
|
|
||||||
|
|
||||||
# Create the grubenv forcing first boot to be on recovery system
|
|
||||||
mkdir -p $WORKDIR/oem
|
|
||||||
cp -rfv /defaults.yaml $WORKDIR/oem/01_defaults.yaml
|
|
||||||
|
|
||||||
# Create a 64MB filesystem for OEM volume
|
|
||||||
truncate -s $((64*1024*1024)) bootloader/oem.img
|
|
||||||
mkfs.ext2 -L "${OEM_LABEL}" -d $WORKDIR/oem bootloader/oem.img
|
|
||||||
|
|
||||||
# Create a 2GB filesystem for COS_PERSISTENT volume
|
|
||||||
truncate -s $((2048*1024*1024)) bootloader/persistent.img
|
|
||||||
mkfs.ext2 -L "${PERSISTENT_LABEL}" bootloader/persistent.img
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#!/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:=}"
|
|
||||||
: "${RECOVERY_SIZE:=2048}"
|
|
||||||
|
|
||||||
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)
|
|
||||||
# shellcheck disable=SC2004
|
|
||||||
truncate -s $(($RECOVERY_SIZE*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:+${RECOVERY_SIZE}M -c 4:root -t 4:8300 $OUT
|
|
||||||
Reference in New Issue
Block a user