Compare commits

...

87 Commits

Author SHA1 Message Date
Mauro Morales
6e7bcc882b works 2024-02-09 17:44:57 +01:00
Itxaka
7c417e773f Merge pull request #131 from ci-forks/create-pull-request/patch 2024-02-08 09:35:35 +01:00
mudler
ba9290acb7 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-02-07 20:07:19 +00:00
Itxaka
627d7e87ed Merge pull request #130 from ci-forks/create-pull-request/patch 2024-02-07 16:10:17 +01:00
Itxaka
f00b095ec1 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-02-07 15:10:04 +00:00
Itxaka
10b1baff0d Merge pull request #129 from kairos-io/fix_arm64_build 2024-02-07 11:20:28 +01:00
Itxaka
5c13bd2bdc Fix arm64 build for os tools
Signed-off-by: Itxaka <itxaka@kairos.io>
2024-02-07 11:10:17 +01:00
Itxaka
c86be82d66 Merge pull request #128 from kairos-io/move_tools_fedora 2024-02-07 10:03:21 +01:00
Itxaka
104eb89548 Merge branch 'master' into move_tools_fedora 2024-02-06 11:16:38 +01:00
Itxaka
815a9e2898 Move tool image to fedora
Signed-off-by: Itxaka <itxaka@kairos.io>
2024-02-06 10:31:09 +01:00
Mauro Morales
52475cf069 Merge pull request #126 from ci-forks/create-pull-request/patch
⬆️ Update repositories
2024-02-05 22:08:40 +01:00
mudler
f30e9a6a6a ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-02-05 20:15:37 +00:00
renovate[bot]
7005550b32 Update quay.io/kairos/enki Docker tag to v0.0.16 2024-02-05 16:21:35 +00:00
Itxaka
18959ee26a Merge pull request #121 from ci-forks/create-pull-request/patch
⬆️ Update repositories
2024-02-02 22:34:40 +01:00
Itxaka
cbc6ca3fc0 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-02-02 20:49:19 +00:00
Itxaka
44fb9dc165 Merge pull request #124 from kairos-io/Itxaka-patch-1 2024-02-02 21:48:05 +01:00
Itxaka
902c311c17 Update Dockerfile
Signed-off-by: Itxaka <itxakaserrano@gmail.com>
2024-02-02 21:11:57 +01:00
renovate[bot]
f8a2ff5531 Update quay.io/kairos/enki Docker tag to v0.0.13 2024-02-01 01:23:20 +00:00
Itxaka
ca2d1fc9cc Merge pull request #119 from ci-forks/create-pull-request/patch 2024-01-30 17:49:38 +01:00
renovate[bot]
c2748aecad Update quay.io/kairos/enki Docker tag to v0.0.12 2024-01-30 16:49:15 +00:00
Itxaka
b834974606 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-01-30 16:48:37 +00:00
Itxaka
30f8b9cb1c Merge pull request #112 from ci-forks/create-pull-request/patch 2024-01-30 15:32:08 +01:00
Itxaka
2b601c1420 Merge pull request #118 from kairos-io/nodepair_enable 2024-01-30 15:29:52 +01:00
Itxaka
e5cded4980 Rename modepair.enable to install-mode
Signed-off-by: Itxaka <itxaka@kairos.io>
2024-01-30 14:39:07 +01:00
renovate[bot]
a482917a27 Update quay.io/kairos/enki Docker tag to v0.0.11 2024-01-30 00:40:16 +00:00
mudler
48c41866ed ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-01-26 20:07:08 +00:00
renovate[bot]
89f39c7ada Update quay.io/kairos/enki Docker tag to v0.0.10 2024-01-25 22:06:52 +00:00
renovate[bot]
5158b5b7f3 Update quay.io/kairos/enki Docker tag to v0.0.8 2024-01-24 22:20:35 +00:00
Itxaka
d73c9528b1 Merge pull request #110 from ci-forks/create-pull-request/patch 2024-01-12 16:07:50 +01:00
Itxaka
b54cac66b7 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-01-12 15:07:30 +00:00
Itxaka
754ac31929 Bump enki version
Signed-off-by: Itxaka <itxakaserrano@gmail.com>
2024-01-12 15:43:13 +01:00
Itxaka
87c309421d Merge pull request #108 from ci-forks/create-pull-request/patch 2024-01-12 15:42:08 +01:00
Itxaka
939857b201 Merge pull request #109 from kairos-io/renovate/github.com-onsi-ginkgo-v2-2.x 2024-01-12 15:41:42 +01:00
renovate[bot]
b82332d9bf fix(deps): update module github.com/onsi/ginkgo/v2 to v2.14.0 2024-01-11 22:51:44 +00:00
mudler
f0cec49b08 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-01-11 20:07:22 +00:00
Itxaka
f32d1c4baa Merge pull request #106 from ci-forks/create-pull-request/patch 2024-01-11 10:14:40 +01:00
Itxaka
1a34dc98f2 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2024-01-11 09:11:32 +00:00
Itxaka
b7af88b618 Do not hardcode enki version when building tools image
Signed-off-by: Itxaka <itxakaserrano@gmail.com>
2024-01-11 10:00:16 +01:00
Itxaka
275bbf8871 Merge pull request #107 from kairos-io/efi_secureboot_enki 2024-01-11 09:39:15 +01:00
Itxaka
866dc42c48 Drop usage of system/grub2-efi package as a source
Now rootfs needs to provide their artifacts from packages so the dir is
no longer used, so the config needs to change

The package is still there as alpine will need it as a last resort but
it wont support secureboot

Signed-off-by: Itxaka <itxaka@kairos.io>
2023-12-30 12:53:33 +01:00
Itxaka
e4482ddc08 Merge pull request #78 from kairos-io/renovate/github.com-onsi-ginkgo-v2-2.x 2023-12-03 13:38:41 +01:00
renovate[bot]
a946063eac fix(deps): update module github.com/onsi/ginkgo/v2 to v2.13.2 2023-12-03 12:38:33 +00:00
Itxaka
73afbbf332 Merge pull request #97 from kairos-io/renovate/actions-checkout-4.x 2023-12-03 13:38:24 +01:00
Itxaka
17ef38753d Merge pull request #94 from kairos-io/renovate/quay.io-luet-base-0.x 2023-12-03 13:38:09 +01:00
Itxaka
bcda489c96 Merge pull request #101 from kairos-io/renovate/github.com-onsi-gomega-1.x 2023-12-03 13:37:59 +01:00
Itxaka
e731abc99b Merge pull request #102 from kairos-io/renovate/docker-build-push-action-5.x 2023-12-03 13:37:47 +01:00
Itxaka
1354314fd4 Merge pull request #103 from kairos-io/renovate/docker-login-action-3.x 2023-12-03 13:37:37 +01:00
Itxaka
98bb28c046 Merge pull request #92 from ci-forks/create-pull-request/patch 2023-12-03 13:37:14 +01:00
mudler
9f456b0119 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2023-12-02 20:06:59 +00:00
Dimitris Karakasilis
1dc94d57c8 Bump repositories to consume latest grub config for livecd (#105)
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-11-22 13:33:50 +02:00
renovate[bot]
08db23aca8 chore(deps): update quay.io/luet/base docker tag to v0.35.0 2023-11-22 07:34:00 +00:00
Dimitris Karakasilis
89b014b2b2 Bump enki to 0.0.3
to make use of: https://github.com/kairos-io/enki/pull/16

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-11-22 09:32:36 +02:00
renovate[bot]
9a6003118e fix(deps): update module github.com/onsi/gomega to v1.30.0 2023-11-08 18:31:24 +00:00
renovate[bot]
f67f1939b9 chore(deps): update docker/login-action action to v3 2023-10-05 22:38:45 +00:00
renovate[bot]
d744abf9ab chore(deps): update docker/build-push-action action to v5 2023-10-05 22:38:41 +00:00
renovate[bot]
320dd7a070 chore(deps): update actions/checkout action to v4 2023-10-05 06:51:13 +00:00
Dimitris Karakasilis
66e9e7a940 Merge branch 'migrate-enki' 2023-10-05 09:49:33 +03:00
Dimitris Karakasilis
b9f6893e28 Use an existing image
(we never built a v0.0.1 image)

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-10-05 09:48:37 +03:00
Dimitris Karakasilis
e933ba05d5 Specify tools-image enki version in the pipeline
to be easier to bump. It also has a default value in the Dockerfile.

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-10-05 09:48:37 +03:00
Dimitris Karakasilis
6e0146ef4d Remove enki building pipeline, use pre-built enki image
Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-10-05 09:48:36 +03:00
Dimitris Karakasilis
be735dccad Migrate enki to a separate repository
Moved here:
https://github.com/kairos-io/enki

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-10-05 09:48:00 +03:00
renovate[bot]
196c84dee0 chore(deps): update earthly/actions-setup action to v1.0.8 2023-10-04 22:57:23 +00:00
renovate[bot]
862d937209 fix(deps): update module github.com/kairos-io/kairos-sdk to v0.0.14 2023-10-04 16:57:07 +00:00
Mauro Morales
8fc4c182ba Configure automerge for patch updates
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-10-04 16:36:40 +02:00
Ettore Di Giacinto
497ecf90df Merge pull request #98 from kairos-io/raw_disks_mbr
example: add script to generate bios mbr raw disks
2023-09-20 16:27:01 +02:00
mudler
e3f4b6150c example: add script to generate bios mbr raw disks
Signed-off-by: mudler <mudler@kairos.io>
2023-09-20 15:13:26 +02:00
Ettore Di Giacinto
b2efc802b1 Merge pull request #63 from kairos-io/renovate/github.com-onsi-gomega-1.x
Update module github.com/onsi/gomega to v1.27.10
2023-09-05 14:55:21 +02:00
renovate[bot]
1b6266d385 Update module github.com/onsi/gomega to v1.27.10 2023-08-31 12:32:17 +00:00
Dimitris Karakasilis
e55bd03800 1546 byoi (#88)
* Add fields to the CRDs

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP Create test

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Refactor code to split in testable functions

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Do something actually useful in tests

- Create a random namespace
- Create an artifact
- Check that CreateConfigmap doesn't error

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Refactor before each so that we can change the artifact object per test

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Run kaniko to build the Dockerfile

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Build the image from Dockerfile with kaniko

Currently can build an image. For example apply these:

```
kind: Secret
apiVersion: v1
metadata:
  name: mydockerfile
stringData:
  Dockerfile: |
    FROM ubuntu
    RUN touch myfile

---
kind: OSArtifact
apiVersion: build.kairos.io/v1alpha2
metadata:
  name: hello-kairos
spec:
  imageName: "quay.io/kairos/core-opensuse-leap:latest"
  baseImageDockerfile:
    name: "mydockerfile"
    key: "Dockerfile"
  iso: true
```

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Clarify that convert-to-kairos is not yet implemented

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Remove implemented TODO

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* WIP

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Bump linting action

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Fix linting errors

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Bump it again

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Unexport function and run controller tests in CI

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Unexport the other one too

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Extract case to a function

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Split controller tests in a separate job

so that they run on a fresh cluster and they run in parallel

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Remove non-implemented functionality

Will happen as part of this: https://github.com/kairos-io/kairos/issues/1721

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* go mod tidy

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

* Try to use a random (free) port in tests

because sometimes we collide

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>

---------

Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
2023-08-31 15:30:55 +03:00
Itxaka
09058c0d69 Merge pull request #91 from Itxaka/bundle_ipxe_template 2023-08-18 10:01:24 +02:00
Itxaka
a3204411ab Merge branch 'master' into bundle_ipxe_template 2023-08-17 18:23:56 +02:00
Itxaka
888465f981 Bundle the ipxe template in the osbuilder
Signed-off-by: Itxaka <itxaka@kairos.io>
2023-08-17 18:23:13 +02:00
Itxaka
c7373a5fa6 Merge pull request #90 from Itxaka/bump_deps_toolimage 2023-08-16 16:39:22 +02:00
Itxaka
de5488867c Bump repos
Brings the newest grub packages to support secureboot

Signed-off-by: Itxaka <itxaka@kairos.io>
2023-08-16 16:16:40 +02:00
Itxaka
f2831462f3 Bump repos to get newer livecd/grub packages
New versions restore secureboot from cd and bundle the default grub.cfg
for livecd for both bios and efi

Signed-off-by: Itxaka <itxaka@kairos.io>
2023-08-16 14:37:03 +02:00
Itxaka
80c53e0d7f Merge pull request #85 from Itxaka/rpi3_rpi4
Support rpi3 and rpi 4 boards
2023-08-09 16:59:50 +02:00
Itxaka
0019c9cbb6 Merge branch 'master' into rpi3_rpi4 2023-08-08 15:20:12 +02:00
Itxaka
714323816b Merge pull request #82 from ci-forks/create-pull-request/patch 2023-08-08 15:20:01 +02:00
Itxaka
92193abe84 Dont use local flag for pull-image
not supported and done automatically

Signed-off-by: Itxaka <itxaka@kairos.io>
2023-08-08 15:06:32 +02:00
Itxaka
c813e546d0 Support rpi3 and rpi 4 boards
Due to rpi3 not supporting GPT disks, we need to separate the building
into rpi3 and 4 so rpi4 gets GPT disks and can auto-expand the last
partition properly (and add extra partitions and so on)

This also includes some cleanup for the luet cache dirs, includes the
kairos-agent which was missing from the image for pulling images, and
cleans up the lvm vgs if they were left

Signed-off-by: Itxaka <itxaka@kairos.io>
2023-08-08 14:56:39 +02:00
mudler
ed8c62dae5 ⬆️ Update repositories
Signed-off-by: GitHub <noreply@github.com>
2023-08-07 20:09:12 +00:00
Mauro Morales
a549b5e9d9 Merge pull request #84 from kairos-io/pass-targetarch-instead-of-buildarch
Pass targetarch instead of buildarch for copying luet config
2023-08-07 16:03:04 +02:00
Mauro Morales
3a34887f19 Pass targetarch instead of buildarch for copying luet config
Signed-off-by: Mauro Morales <mauro.morales@spectrocloud.com>
2023-08-07 15:58:17 +02:00
Itxaka
518e8f2800 Merge pull request #83 from Itxaka/other_missing_dir 2023-07-31 22:19:37 +02:00
Itxaka
8559cd70c0 Add second missing dir for arm grub efi
Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
2023-07-31 22:19:11 +02:00
Itxaka
19927d0ca9 Merge pull request #81 from Itxaka/missing_dir 2023-07-31 19:24:16 +02:00
Itxaka
2996f21dfa Fix missing dir for amr artifacts
It was using the default one which provides grub artifacts for the
current arch, not specific arm64 ones for the arm images

Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
2023-07-31 16:30:15 +02:00
51 changed files with 692 additions and 3624 deletions

View File

@@ -7,7 +7,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install earthly
uses: Luet-lab/luet-install-action@v1
with:

View File

@@ -1,24 +0,0 @@
---
name: 'run enki unit tests'
on:
pull_request:
concurrency:
group: enki-${{ github.ref || github.head_ref }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: earthly/actions-setup@v1.0.7
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build
run: cd tools-image/enki && earthly -P +test

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Prepare
id: prep
@@ -50,14 +50,14 @@ jobs:
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: .

View File

@@ -15,7 +15,7 @@ env:
FORCE_COLOR: 1
jobs:
call-workflow:
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.6
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.8
with:
yamldirs: ".github/workflows/ config/ tools-image/"
is-go: true

View File

@@ -14,11 +14,19 @@ concurrency:
cancel-in-progress: true
jobs:
docker:
e2e-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Test
run: |
make kind-e2e-tests
controller-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Test
run: |
make controller-tests

View File

@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Prepare
id: prep
@@ -49,14 +49,14 @@ jobs:
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: ./tools-image

View File

@@ -263,6 +263,9 @@ kind-setup:
kind-setup-image: docker-build
kind load docker-image --name $(CLUSTER_NAME) ${IMG}
kind-teardown:
kind delete cluster --name ${CLUSTER_NAME} || true
.PHONY: test_deps
test_deps:
go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
@@ -275,8 +278,10 @@ unit-tests: test_deps
e2e-tests:
GINKGO=$(GINKGO) KUBE_VERSION=${KUBE_VERSION} $(ROOT_DIR)/script/test.sh
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
controller-tests: ginkgo kind-setup install undeploy-dev deploy-dev
USE_EXISTING_CLUSTER=true go run github.com/onsi/ginkgo/v2/ginkgo -v run controllers/.
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
kubesplit: manifests kustomize
rm -rf helm-chart

View File

@@ -24,8 +24,17 @@ import (
// OSArtifactSpec defines the desired state of OSArtifact
type OSArtifactSpec struct {
// There are 3 ways to specify a Kairos image:
// Points to a prepared kairos image (e.g. a released one)
ImageName string `json:"imageName,omitempty"`
// Points to a vanilla (non-Kairos) image. osbuilder will try to convert this to a Kairos image
BaseImageName string `json:"baseImageName,omitempty"`
// Points to a Secret that contains a Dockerfile. osbuilder will build the image using that Dockerfile and will try to create a Kairos image from it.
BaseImageDockerfile *SecretKeySelector `json:"baseImageDockerfile,omitempty"`
ISO bool `json:"iso,omitempty"`
//Disk-only stuff

View File

@@ -89,6 +89,11 @@ func (in *OSArtifactList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OSArtifactSpec) DeepCopyInto(out *OSArtifactSpec) {
*out = *in
if in.BaseImageDockerfile != nil {
in, out := &in.BaseImageDockerfile, &out.BaseImageDockerfile
*out = new(SecretKeySelector)
**out = **in
}
if in.CloudConfigRef != nil {
in, out := &in.CloudConfigRef, &out.CloudConfigRef
*out = new(SecretKeySelector)

View File

@@ -41,6 +41,22 @@ spec:
properties:
azureImage:
type: boolean
baseImageDockerfile:
description: Points to a Secret that contains a Dockerfile. osbuilder
will build the image using that Dockerfile and will try to create
a Kairos image from it.
properties:
key:
type: string
name:
type: string
required:
- name
type: object
baseImageName:
description: Points to a vanilla (non-Kairos) image. osbuilder will
try to convert this to a Kairos image
type: string
bundles:
items:
type: string
@@ -7834,6 +7850,7 @@ spec:
grubConfig:
type: string
imageName:
description: Points to a prepared kairos image (e.g. a released one)
type: string
imagePullSecrets:
items:

View File

@@ -18,6 +18,7 @@ package controllers
import (
"fmt"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -292,6 +293,17 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
},
}
if artifact.Spec.BaseImageDockerfile != nil {
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: "dockerfile",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: artifact.Spec.BaseImageDockerfile.Name,
},
},
})
}
if artifact.Spec.CloudConfigRef != nil {
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: "cloudconfig",
@@ -304,11 +316,40 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
})
}
for i := range artifact.Spec.ImagePullSecrets {
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets[i])
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets...)
podSpec.InitContainers = []corev1.Container{}
// Base image can be:
// - built from a dockerfile and converted to a kairos one
// - built by converting an existing image to a kairos one
// - a prebuilt kairos image
if artifact.Spec.BaseImageDockerfile != nil {
podSpec.InitContainers = append(podSpec.InitContainers, baseImageBuildContainers()...)
} else if artifact.Spec.BaseImageName != "" { // Existing base image - non kairos
podSpec.InitContainers = append(podSpec.InitContainers,
unpackContainer("baseimage-non-kairos", r.ToolImage, artifact.Spec.BaseImageName))
} else { // Existing Kairos base image
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName))
}
podSpec.InitContainers = []corev1.Container{unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName)}
// If base image was a non kairos one, either one we built with kaniko or prebuilt,
// convert it to a Kairos one, in a best effort manner.
if artifact.Spec.BaseImageDockerfile != nil || artifact.Spec.BaseImageName != "" {
podSpec.InitContainers = append(podSpec.InitContainers,
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "convert-to-kairos",
Image: "busybox",
Command: []string{"/bin/echo"},
Args: []string{"TODO"},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
})
}
for i, bundle := range artifact.Spec.Bundles {
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer(fmt.Sprint(i), r.ToolImage, bundle))
@@ -352,3 +393,59 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
func ptr[T any](val T) *T {
return &val
}
func baseImageBuildContainers() []corev1.Container {
return []corev1.Container{
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "kaniko-build",
Image: "gcr.io/kaniko-project/executor:latest",
Args: []string{
"--dockerfile", "dockerfile/Dockerfile",
"--context", "dir://workspace",
"--destination", "whatever", // We don't push, but it needs this
"--tar-path", "/rootfs/image.tar",
"--no-push",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
{
Name: "dockerfile",
MountPath: "/workspace/dockerfile",
},
},
},
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "image-extractor",
Image: "quay.io/luet/base",
Args: []string{
"util", "unpack", "--local", "file:////rootfs/image.tar", "/rootfs",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
},
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "cleanup",
Image: "busybox",
Command: []string{"/bin/rm"},
Args: []string{
"/rootfs/image.tar",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
},
}
}

View File

@@ -19,6 +19,7 @@ package controllers
import (
"context"
"fmt"
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
@@ -99,41 +100,69 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
}
func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
// generate configmap required for building a custom image
// CreateConfigMap generates a configmap required for building a custom image
func (r *OSArtifactReconciler) CreateConfigMap(ctx context.Context, artifact *osbuilder.OSArtifact) error {
cm := r.genConfigMap(artifact)
if cm.Labels == nil {
cm.Labels = map[string]string{}
}
cm.Labels[artifactLabel] = artifact.Name
if err := controllerutil.SetOwnerReference(artifact, cm, r.Scheme()); err != nil {
return ctrl.Result{Requeue: true}, err
return err
}
if err := r.Create(ctx, cm); err != nil && !apierrors.IsAlreadyExists(err) {
return ctrl.Result{Requeue: true}, err
return err
}
return nil
}
func (r *OSArtifactReconciler) createPVC(ctx context.Context, artifact *osbuilder.OSArtifact) (*corev1.PersistentVolumeClaim, error) {
pvc := r.newArtifactPVC(artifact)
if pvc.Labels == nil {
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
return pvc, err
}
if err := r.Create(ctx, pvc); err != nil {
return ctrl.Result{Requeue: true}, err
return pvc, err
}
return pvc, nil
}
func (r *OSArtifactReconciler) createBuilderPod(ctx context.Context, artifact *osbuilder.OSArtifact, pvc *corev1.PersistentVolumeClaim) (*corev1.Pod, error) {
pod := r.newBuilderPod(pvc.Name, artifact)
if pod.Labels == nil {
pod.Labels = map[string]string{}
}
pod.Labels[artifactLabel] = artifact.Name
if err := controllerutil.SetOwnerReference(artifact, pod, r.Scheme()); err != nil {
return pod, err
}
if err := r.Create(ctx, pod); err != nil {
return pod, err
}
return pod, nil
}
func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
err := r.CreateConfigMap(ctx, artifact)
if err != nil {
return ctrl.Result{Requeue: true}, err
}
if err := r.Create(ctx, pod); err != nil {
pvc, err := r.createPVC(ctx, artifact)
if err != nil {
return ctrl.Result{Requeue: true}, err
}
_, err = r.createBuilderPod(ctx, artifact, pvc)
if err != nil {
return ctrl.Result{Requeue: true}, err
}

View File

@@ -0,0 +1,173 @@
package controllers
import (
"context"
"fmt"
"time"
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/phayes/freeport"
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/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
)
var _ = Describe("OSArtifactReconciler", func() {
var r *OSArtifactReconciler
var artifact *osbuilder.OSArtifact
var namespace string
var restConfig *rest.Config
var clientset *kubernetes.Clientset
var err error
BeforeEach(func() {
restConfig = ctrl.GetConfigOrDie()
clientset, err = kubernetes.NewForConfig(restConfig)
Expect(err).ToNot(HaveOccurred())
namespace = createRandomNamespace(clientset)
artifact = &osbuilder.OSArtifact{
TypeMeta: metav1.TypeMeta{
Kind: "OSArtifact",
APIVersion: osbuilder.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: randStringRunes(10),
},
}
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(osbuilder.AddToScheme(scheme))
metricsPort, err := freeport.GetFreePort()
Expect(err).ToNot(HaveOccurred())
fmt.Printf("metricsPort = %+v\n", metricsPort)
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: fmt.Sprintf("127.0.0.1:%d", metricsPort),
})
Expect(err).ToNot(HaveOccurred())
r = &OSArtifactReconciler{
ToolImage: "quay.io/kairos/osbuilder-tools:latest",
}
err = (r).SetupWithManager(mgr)
Expect(err).ToNot(HaveOccurred())
})
JustBeforeEach(func() {
k8s := dynamic.NewForConfigOrDie(restConfig)
artifacts := k8s.Resource(
schema.GroupVersionResource{
Group: osbuilder.GroupVersion.Group,
Version: osbuilder.GroupVersion.Version,
Resource: "osartifacts"}).Namespace(namespace)
uArtifact := unstructured.Unstructured{}
uArtifact.Object, _ = runtime.DefaultUnstructuredConverter.ToUnstructured(artifact)
resp, err := artifacts.Create(context.TODO(), &uArtifact, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
// Update the local object with the one fetched from k8s
err = runtime.DefaultUnstructuredConverter.FromUnstructured(resp.Object, artifact)
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
deleteNamepace(clientset, namespace)
})
Describe("CreateConfigMap", func() {
It("creates a ConfigMap with no error", func() {
ctx := context.Background()
err := r.CreateConfigMap(ctx, artifact)
Expect(err).ToNot(HaveOccurred())
c, err := clientset.CoreV1().ConfigMaps(namespace).Get(context.TODO(), artifact.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(c).ToNot(BeNil())
})
})
Describe("CreateBuilderPod", func() {
When("BaseImageDockerfile is set", func() {
BeforeEach(func() {
secretName := artifact.Name + "-dockerfile"
_, err := clientset.CoreV1().Secrets(namespace).Create(context.TODO(),
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
},
StringData: map[string]string{
"Dockerfile": "FROM ubuntu",
},
Type: "Opaque",
}, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
artifact.Spec.BaseImageDockerfile = &osbuilder.SecretKeySelector{
Name: secretName,
Key: "Dockerfile",
}
// Whatever, just to let it work
artifact.Spec.ImageName = "quay.io/kairos-ci/" + artifact.Name + ":latest"
})
It("creates an Init Container to build the image", func() {
pvc, err := r.createPVC(context.TODO(), artifact)
Expect(err).ToNot(HaveOccurred())
pod, err := r.createBuilderPod(context.TODO(), artifact, pvc)
Expect(err).ToNot(HaveOccurred())
By("checking if an init container was created")
initContainerNames := []string{}
for _, c := range pod.Spec.InitContainers {
initContainerNames = append(initContainerNames, c.Name)
}
Expect(initContainerNames).To(ContainElement("kaniko-build"))
By("checking if init containers complete successfully")
Eventually(func() bool {
p, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
var allReady = false
if len(p.Status.InitContainerStatuses) > 0 {
allReady = true
}
for _, c := range p.Status.InitContainerStatuses {
allReady = allReady && c.Ready
}
return allReady
}, 2*time.Minute, 5*time.Second).Should(BeTrue())
// req := clientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &v1.PodLogOptions{})
// podLogs, err := req.Stream(context.TODO())
// Expect(err).ToNot(HaveOccurred())
// defer podLogs.Close()
// buf := new(bytes.Buffer)
// _, err = io.Copy(buf, podLogs)
// Expect(err).ToNot(HaveOccurred())
// str := buf.String()
// fmt.Printf("str = %+v\n", str)
})
})
})
})

View File

@@ -17,20 +17,24 @@ limitations under the License.
package controllers
import (
"context"
"math/rand"
"path/filepath"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
buildv1alpha2 "github.com/kairos-io/osbuilder/api/v1alpha2"
//+kubebuilder:scaffold:imports
)
@@ -43,10 +47,7 @@ var testEnv *envtest.Environment
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{printer.NewlineReporter{}})
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {
@@ -64,7 +65,7 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = buildv1alpha1.AddToScheme(scheme.Scheme)
err = buildv1alpha2.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
//+kubebuilder:scaffold:scheme
@@ -73,10 +74,36 @@ var _ = BeforeSuite(func() {
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
}, 60)
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
func randStringRunes(n int) string {
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyz")
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
func createRandomNamespace(clientset *kubernetes.Clientset) string {
name := randStringRunes(10)
_, err := clientset.CoreV1().Namespaces().Create(context.Background(), &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
return name
}
func deleteNamepace(clientset *kubernetes.Clientset, name string) {
err := clientset.CoreV1().Namespaces().Delete(context.Background(), name, metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
}

31
go.mod
View File

@@ -3,15 +3,12 @@ module github.com/kairos-io/osbuilder
go 1.18
require (
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.9.5
github.com/onsi/gomega v1.27.7
github.com/pkg/errors v0.9.1
github.com/rancher-sandbox/ele-testhelpers v0.0.0-20220614101555-2eddf3b113e2
github.com/onsi/ginkgo/v2 v2.14.0
github.com/onsi/gomega v1.30.0
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
k8s.io/api v0.24.0
k8s.io/apimachinery v0.24.0
k8s.io/client-go v0.24.0
sigs.k8s.io/cluster-api v1.1.4
sigs.k8s.io/controller-runtime v0.12.1
)
@@ -26,25 +23,23 @@ require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful v2.9.5+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/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
github.com/go-openapi/jsonpointer 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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobuffalo/flect v0.2.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // 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.6.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
@@ -53,11 +48,10 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.6 // 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/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
@@ -66,19 +60,18 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/tools v0.16.1 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.24.0 // indirect

119
go.sum
View File

@@ -60,10 +60,6 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@@ -77,14 +73,11 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e h1:GCzyKMDDjSGnlpl3clrdAK7I1AaVoaiKDOYkUzChZzg=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
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-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/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/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
@@ -95,8 +88,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -116,8 +107,6 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/coredns/caddy v1.1.0 h1:ezvsPrT/tA/7pYDBZxu0cT0VmWk75AfIaf6GSYCNMf0=
github.com/coredns/corefile-migration v1.0.14 h1:Tz3WZhoj2NdP8drrQH86NgnCng+VrPjNeg2Oe1ALKag=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
@@ -134,10 +123,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
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/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/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=
@@ -153,7 +140,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@@ -177,10 +163,11 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
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/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/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -193,11 +180,8 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
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-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/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -237,7 +221,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
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/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=
@@ -245,7 +228,6 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
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.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.10.1 h1:MQBGSZGnDwh7T/un+mzGKOMz3x+4E/GDPprWjDL+1Jg=
github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
@@ -261,10 +243,11 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/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/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/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -284,9 +267,9 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
@@ -323,7 +306,6 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
@@ -372,7 +354,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
@@ -381,9 +362,6 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
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/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/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=
@@ -403,35 +381,37 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
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/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/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw=
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.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.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
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/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
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/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -468,8 +448,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rancher-sandbox/ele-testhelpers v0.0.0-20220614101555-2eddf3b113e2 h1:amWBHqvIh/rmaDTuHfoGVAjmnQoZHq+jGuLAmHQhpyM=
github.com/rancher-sandbox/ele-testhelpers v0.0.0-20220614101555-2eddf3b113e2/go.mod h1:rZj2a+V44LvtFVH/vsFXtHYIWMP1Q9aSrl6RGLbk49A=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -477,7 +455,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -493,7 +470,6 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
@@ -501,7 +477,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -579,6 +554,12 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -615,6 +596,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -658,16 +640,20 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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/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/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -741,7 +727,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -763,15 +748,27 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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/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/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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/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/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -780,10 +777,15 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
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/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
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-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -842,7 +844,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -854,10 +855,17 @@ 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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
@@ -949,7 +957,6 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -989,7 +996,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
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/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=
@@ -1021,7 +1027,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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/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=
@@ -1040,11 +1045,9 @@ k8s.io/apiextensions-apiserver v0.24.0 h1:JfgFqbA8gKJ/uDT++feAqk9jBIwNnL9YGdQvaI
k8s.io/apiextensions-apiserver v0.24.0/go.mod h1:iuVe4aEpe6827lvO6yWQVxiPSpPoSKVjkq+MIdg84cM=
k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ=
k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apiserver v0.24.0 h1:GR7kGsjOMfilRvlG3Stxv/3uz/ryvJ/aZXc5pqdsNV0=
k8s.io/apiserver v0.24.0/go.mod h1:WFx2yiOMawnogNToVvUYT9nn1jaIkMKj41ZYCVycsBA=
k8s.io/client-go v0.24.0 h1:lbE4aB1gTHvYFSwm6eD3OF14NhFDKCejlnsGYlSJe5U=
k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw=
k8s.io/cluster-bootstrap v0.23.0 h1:8pZuuAWPoygewSNB4IddX3HBwXcQkPDXL/ca7GtGf4o=
k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w=
k8s.io/component-base v0.24.0 h1:h5jieHZQoHrY/lHG+HyrSbJeyfuitheBvqvKwKHVC0g=
k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA=
@@ -1063,8 +1066,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw=
sigs.k8s.io/cluster-api v1.1.4 h1:mD44GELeiMfQKxyBmsxdYn/FmNAIkFWr2auM++qxx1A=
sigs.k8s.io/cluster-api v1.1.4/go.mod h1:luiK6hLylbm4Kc7dkRw6KPAvNum9sAqpz5DfkdCaSW8=
sigs.k8s.io/controller-runtime v0.12.1 h1:4BJY01xe9zKQti8oRjj/NeHKRXthf1YkYJAgLONFFoI=
sigs.k8s.io/controller-runtime v0.12.1/go.mod h1:BKhxlA4l7FPK4AQcsuL4X6vZeWnKDXez/vp1Y8dxTU0=
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=

View File

@@ -8,5 +8,11 @@
"before 7am every weekday",
"every weekend"
],
"timezone": "Europe/Brussels"
"timezone": "Europe/Brussels",
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true
}
]
}

View File

@@ -31,7 +31,7 @@ spec:
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
$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 install-mode
echo Loading initrd...
$initrd ($root)/boot/rootfs.xz
}

View File

@@ -1,45 +1,42 @@
# https://quay.io/repository/kairos/packages?tab=tags&tag=latest
ARG LEAP_VERSION=15.5
ARG LUET_VERSION=0.34.0
FROM quay.io/luet/base:$LUET_VERSION AS luet
ARG LUET_VERSION=0.35.0
ARG ENKI_VERSION=v0.0.16
FROM golang:1.20 as enki
ENV CGO_ENABLED=0
COPY ./enki /src/enki
WORKDIR /src/enki
RUN go mod download
# Set arg/env after go mod download, otherwise we invalidate the cached layers due to the commit changing easily
ARG ENKI_VERSION=0.0.1
ARG ENKI_COMMIT=""
ENV ENKI_VERSION=${ENKI_VERSION}
ENV ENKI_COMMIT=${ENKI_COMMIT}
RUN go build \
-ldflags "-w -s \
-X github.com/kairos-io/enki/internal/version.version=$ENKI_VERSION \
-X github.com/kairos-io/enki/internal/version.gitCommit=$ENKI_COMMIT" \
-o /usr/bin/enki
FROM quay.io/luet/base:$LUET_VERSION AS luet
FROM quay.io/kairos/enki:${ENKI_VERSION} as enki
FROM opensuse/leap:$LEAP_VERSION as default
RUN zypper ref && zypper dup -y
## ISO+ Arm image + Netboot + cloud images Build depedencies
RUN zypper ref && zypper in -y bc qemu-tools jq cdrtools docker git curl gptfdisk kpartx sudo xfsprogs parted util-linux-systemd e2fsprogs curl util-linux udev rsync grub2 dosfstools grub2-x86_64-efi squashfs mtools xorriso lvm2 zstd
COPY --from=luet /usr/bin/luet /usr/bin/luet
ENV LUET_NOLOCK=true
ENV TMPDIR=/tmp
ARG BUILDARCH
ARG TARGETARCH
# copy both arches
COPY luet-arm64.yaml /tmp/luet-arm64.yaml
COPY luet-amd64.yaml /tmp/luet-amd64.yaml
# Set the default luet config to the current build arch
RUN mkdir -p /etc/luet/
RUN cp /tmp/luet-${BUILDARCH}.yaml /etc/luet/luet.yaml
RUN cp /tmp/luet-${TARGETARCH}.yaml /etc/luet/luet.yaml
## Live CD artifacts
RUN luet install -y livecd/grub2 --system-target /grub2
RUN luet install -y livecd/grub2-efi-image --system-target /efi
## RPI64
RUN luet install -y firmware/u-boot-rpi64 firmware/raspberrypi-firmware firmware/raspberrypi-firmware-config firmware/raspberrypi-firmware-dt --system-target /rpi/
RUN luet install -y firmware/raspberrypi-firmware firmware/raspberrypi-firmware-config firmware/raspberrypi-firmware-dt --system-target /rpi/
COPY luet-arm64-old.yaml /tmp/luet-arm64.yaml
COPY luet-amd64-old.yaml /tmp/luet-amd64.yaml
RUN cp /tmp/luet-${TARGETARCH}.yaml /etc/luet/luet.yaml
RUN luet install -y firmware/u-boot-rpi64 --system-target /rpi/
COPY luet-arm64.yaml /tmp/luet-arm64.yaml
COPY luet-amd64.yaml /tmp/luet-amd64.yaml
## PineBook64 Pro
RUN luet install -y arm-vendor-blob/u-boot-rockchip --system-target /pinebookpro/u-boot
@@ -57,19 +54,37 @@ RUN luet install -y static/grub-artifacts --system-target /raw/grubartifacts
# get them from the x86 repo and we want it to do it from the arm64 repo, even on x86
# so we use the arm64 luet config and use that to install those on x86
# This is being used by the prepare_arm_images.sh and build-arch-image.sh scripts
RUN luet install --config /tmp/luet-arm64.yaml -y static/grub-efi --system-target /arm/raw/grub
RUN luet install --config /tmp/luet-arm64.yaml -y static/grub-efi --system-target /arm/raw/grubefi
RUN luet install --config /tmp/luet-arm64.yaml -y static/grub-config --system-target /arm/raw/grubconfig
RUN luet install --config /tmp/luet-arm64.yaml -y static/grub-artifacts --system-target /arm/raw/grubartifacts
# kairos-agent so we can use the pull-image
RUN luet install -y system/kairos-agent
# remove luet tmp files. Side effect of setting the system-target is that it treats it as a root fs
# so temporal files are stored in each dir
RUN rm -Rf /grub2/var/tmp
RUN rm -Rf /grub2/var/cache
RUN rm -Rf /efi/var/tmp
RUN rm -Rf /efi/var/cache
RUN rm -Rf /rpi/var/tmp
RUN rm -Rf /rpi/var/cache
RUN rm -Rf /pinebookpro/u-boot/var/tmp
RUN rm -Rf /pinebookpro/u-boot/var/cache
RUN rm -Rf /firmware/odroid-c2/var/tmp
RUN rm -Rf /firmware/odroid-c2/var/cache
RUN rm -Rf /raw/grub/var/tmp
RUN rm -Rf /raw/grub/var/cache
RUN rm -Rf /raw/grubconfig/var/tmp
RUN rm -Rf /raw/grubconfig/var/cache
RUN rm -Rf /raw/grubartifacts/var/tmp
RUN rm -Rf /raw/grubartifacts/var/cache
RUN rm -Rf /arm/raw/grubefi/var/tmp
RUN rm -Rf /arm/raw/grubefi/var/cache
RUN rm -Rf /arm/raw/grubconfig/var/tmp
RUN rm -Rf /arm/raw/grubconfig/var/cache
RUN rm -Rf /arm/raw/grubartifacts/var/tmp
RUN rm -Rf /arm/raw/grubartifacts/var/cache
RUN mkdir /config
@@ -78,6 +93,7 @@ COPY ./config.yaml /config/manifest.yaml
COPY ./entrypoint.sh /entrypoint.sh
COPY ./add-cloud-init.sh /add-cloud-init.sh
COPY ./os-release.tmpl /os-release.tmpl
COPY ./ipxe.tmpl /ipxe.tmpl
COPY ./update-os-release.sh /update-os-release.sh
# ARM helpers
@@ -93,6 +109,6 @@ COPY ./netboot.sh /netboot.sh
COPY defaults.yaml /defaults.yaml
COPY --from=enki /usr/bin/enki /usr/bin/enki
COPY --from=enki /enki /usr/bin/enki
ENTRYPOINT [ "/entrypoint.sh" ]

22
tools-image/arm/boards/rpi4.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/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}"
# Copy all rpi files
cp -rfv /rpi/* $TEMPDIR
umount "${TEMPDIR}"

27
tools-image/bios-raw-image.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Generates raw bootable images with qemu
set -ex
CLOUD_INIT=${1:-cloud_init.yaml}
QEMU=${QEMU:-qemu-system-x86_64}
ISO=${2:-iso.iso}
mkdir -p build
pushd build
touch meta-data
cp -rfv $CLOUD_INIT user-data
mkisofs -output ci.iso -volid cidata -joliet -rock user-data meta-data
truncate -s "+$((20000*1024*1024))" disk.raw
${QEMU} -m 8096 -smp cores=2 \
-nographic -cpu host \
-serial mon:stdio \
-rtc base=utc,clock=rt \
-chardev socket,path=qga.sock,server,nowait,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
-drive if=virtio,media=disk,file=disk.raw \
-drive format=raw,media=cdrom,readonly=on,file=$ISO \
-drive format=raw,media=cdrom,readonly=on,file=ci.iso \
-boot d \
-enable-kvm

View File

@@ -73,6 +73,8 @@ cleanup() {
fi
losetup -D "${LOOP}" || true;
dmsetup remove KairosVG-oem || true;
dmsetup remove KairosVG-recovery || true;
}
ensure_dir_structure() {
@@ -215,7 +217,12 @@ while [ "$#" -gt 0 ]; do
shift 1
done
if [ "$model" == "rpi64" ]; then
if [ "$model" == "rpi64" ];then
echo "rpi64 model not supported anymore, please select either rpi3 or rpi4"
exit 1
fi
if [ "$model" == "rpi3" ] || [ "$model" == "rpi4" ]; then
container_image=${CONTAINER_IMAGE:-quay.io/costoolkit/examples:rpi-latest}
else
# Odroid C2 image contains kernel-default-extra, might have broader support
@@ -284,7 +291,7 @@ 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
kairos-agent pull-image $container_image $TARGET
else
echo ">>> Copying files from $directory"
rsync -axq --exclude='host' --exclude='mnt' --exclude='proc' --exclude='sys' --exclude='dev' --exclude='tmp' ${directory}/ $TARGET
@@ -336,7 +343,7 @@ if [ -z "$EFI" ]; then
exit 1
fi
cp -rfv /efi/* $EFI
cp -rfv /arm/raw/grubefi/* $EFI
if [ -n "$EFI" ] && [ -n "$efi_dir" ]; then
echo "Copy $efi_dir to EFI directory"
cp -rfv $efi_dir/* $EFI
@@ -346,23 +353,31 @@ partprobe
echo ">> Writing image and partition table"
dd if=/dev/zero of="${output_image}" bs=1024000 count="${size}" || exit 1
if [ "$model" == "rpi64" ]; then
# Image partitions
# only rpi4 supports gpt
if [ "$model" == "rpi3" ]; then
sgdisk -n 1:8192:+96M -c 1:EFI -t 1:0c00 ${output_image}
sgdisk -n 2:0:+${state_size}M -c 2:state -t 2:8300 ${output_image}
sgdisk -n 3:0:+$(( recovery_size + oem_size ))M -c 3:lvm -t 3:8e00 ${output_image}
sgdisk -n 4:0:+64M -c 4:persistent -t 4:8300 ${output_image}
sgdisk -m 1:2:3:4 ${output_image}
sfdisk --part-type ${output_image} 1 c
elif [ "$model" == "rpi4" ]; then
echo "label: gpt" | sfdisk "${output_image}"
sgdisk -n 1:8192:+96M -c 1:EFI -t 1:0c00 ${output_image}
sgdisk -n 2:0:+${state_size}M -c 2:state -t 2:8300 ${output_image}
sgdisk -n 3:0:+${recovery_size}M -c 3:recovery -t 3:8300 ${output_image}
sgdisk -n 4:0:+${oem_size}M -c 4:oem -t 4:8300 ${output_image}
sgdisk -n 5:0:+64M -c 5:persistent -t 5:8300 ${output_image}
sgdisk -g ${output_image}
sgdisk -m 1:2:3:4:5 ${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
sgdisk -n 2:0:+${state_size}M -c 2:state -t 2:8300 ${output_image}
sgdisk -n 3:0:+$(( recovery_size + oem_size ))M -c 3:lvm -t 3:8e00 ${output_image}
sgdisk -n 4:0:+64M -c 4:persistent -t 4:8300 ${output_image}
sgdisk -m 1:2:3:4 ${output_image}
fi
# Prepare the image and copy over the files
@@ -385,64 +400,68 @@ export device="/dev/mapper/${device}"
partprobe
kpartx -va $DRIVE
if [ "$model" == 'rpi4' ]; then
kpartx -vag $DRIVE
else
kpartx -va $DRIVE
fi
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
if [ "$model" == 'rpi4' ]; then
oem=${device}p4
persistent=${device}p5
else
persistent=${device}p4
oem_lv=/dev/mapper/KairosVG-oem
recovery_lv=/dev/mapper/KairosVG-recovery
fi
# 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
if [ "$model" == 'rpi4' ]; then
mkfs.ext4 -F -L ${RECOVERY_LABEL} $recovery
mkfs.ext4 -F -L ${OEM_LABEL} $oem
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
mkdir $WORKDIR/state
mkdir $WORKDIR/recovery
mkdir $WORKDIR/efi
mkdir $WORKDIR/oem
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
if [ "$model" == 'rpi4' ]; then
mount $recovery $WORKDIR/recovery
mount $oem $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"
mount $recovery_lv $WORKDIR/recovery
mount $oem_lv $WORKDIR/oem
fi
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
grub2-editenv $WORKDIR/state/grub_oem_env set "default_menu_entry=$menu_entry"
@@ -450,7 +469,6 @@ 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
@@ -459,10 +477,13 @@ cp -arf $STATEDIR/* $WORKDIR/state
umount $WORKDIR/recovery
umount $WORKDIR/state
umount $WORKDIR/efi
umount $WORKDIR/oem
if [ "$disable_lvm" == 'false' ]; then
vgchange -an
if [ "$model" != 'rpi4' ]; then
vgchange -an
fi
sync
# Flash uboot and vendor-specific bits
@@ -473,7 +494,11 @@ sync
sleep 5
sync
kpartx -dv $DRIVE || true
if [ "$model" == 'rpi4' ]; then
kpartx -dvg $DRIVE
else
kpartx -dv $DRIVE || true
fi
umount $DRIVE || true

View File

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

View File

@@ -1,19 +0,0 @@
VERSION 0.7
# renovate: datasource=docker depName=golang
ARG --global GO_VERSION=1.20-alpine3.18
test:
FROM golang:$GO_VERSION
RUN apk add rsync gcc musl-dev docker jq
WORKDIR /build
COPY . .
RUN go mod download
ARG TEST_PATHS=./...
ARG LABEL_FILTER=
ENV CGO_ENABLED=1
# Some test require the docker sock exposed
WITH DOCKER
RUN go run github.com/onsi/ginkgo/v2/ginkgo run --label-filter "$LABEL_FILTER" -v --fail-fast --race --covermode=atomic --coverprofile=coverage.out --coverpkg=github.com/kairos-io/enki/... -p -r $TEST_PATHS
END
SAVE ARTIFACT coverage.out AS LOCAL coverage.out

View File

@@ -1,122 +0,0 @@
package cmd
import (
"fmt"
"os/exec"
"github.com/kairos-io/enki/pkg/action"
"github.com/kairos-io/enki/pkg/config"
"github.com/kairos-io/enki/pkg/utils"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/mount-utils"
)
// NewBuildISOCmd returns a new instance of the build-iso subcommand and appends it to
// the root command.
func NewBuildISOCmd() *cobra.Command {
c := &cobra.Command{
Use: "build-iso SOURCE",
Short: "Build bootable installation media ISOs",
Long: "Build bootable installation media ISOs\n\n" +
"SOURCE - should be provided as uri in following format <sourceType>:<sourceName>\n" +
" * <sourceType> - might be [\"dir\", \"file\", \"oci\", \"docker\"], as default is \"docker\"\n" +
" * <sourceName> - is path to file or directory, image name with tag version",
Args: cobra.MaximumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
return CheckRoot()
},
RunE: func(cmd *cobra.Command, args []string) error {
path, err := exec.LookPath("mount")
if err != nil {
return err
}
mounter := mount.New(path)
cfg, err := config.ReadConfigBuild(viper.GetString("config-dir"), cmd.Flags(), mounter)
if err != nil {
cfg.Logger.Errorf("Error reading config: %s\n", err)
}
flags := cmd.Flags()
// Set this after parsing of the flags, so it fails on parsing and prints usage properly
cmd.SilenceUsage = true
cmd.SilenceErrors = true // Do not propagate errors down the line, we control them
spec, err := config.ReadBuildISO(cfg, flags)
if err != nil {
cfg.Logger.Errorf("invalid install command setup %v", err)
return err
}
if len(args) == 1 {
imgSource, err := v1.NewSrcFromURI(args[0])
if err != nil {
cfg.Logger.Errorf("not a valid rootfs source image argument: %s", args[0])
return err
}
spec.RootFS = []*v1.ImageSource{imgSource}
} else if len(spec.RootFS) == 0 {
errmsg := "rootfs source image for building ISO was not provided"
cfg.Logger.Errorf(errmsg)
return fmt.Errorf(errmsg)
}
// Repos and overlays can't be unmarshaled directly as they require
// to be merged on top and flags do not match any config value key
oRootfs, _ := flags.GetString("overlay-rootfs")
oUEFI, _ := flags.GetString("overlay-uefi")
oISO, _ := flags.GetString("overlay-iso")
if oRootfs != "" {
if ok, err := utils.Exists(cfg.Fs, oRootfs); ok {
spec.RootFS = append(spec.RootFS, v1.NewDirSrc(oRootfs))
} else {
cfg.Logger.Errorf("Invalid value for overlay-rootfs")
return fmt.Errorf("Invalid path '%s': %v", oRootfs, err)
}
}
if oUEFI != "" {
if ok, err := utils.Exists(cfg.Fs, oUEFI); ok {
spec.UEFI = append(spec.UEFI, v1.NewDirSrc(oUEFI))
} else {
cfg.Logger.Errorf("Invalid value for overlay-uefi")
return fmt.Errorf("Invalid path '%s': %v", oUEFI, err)
}
}
if oISO != "" {
if ok, err := utils.Exists(cfg.Fs, oISO); ok {
spec.Image = append(spec.Image, v1.NewDirSrc(oISO))
} else {
cfg.Logger.Errorf("Invalid value for overlay-iso")
return fmt.Errorf("Invalid path '%s': %v", oISO, err)
}
}
buildISO := action.NewBuildISOAction(cfg, spec)
err = buildISO.ISORun()
if err != nil {
cfg.Logger.Errorf(err.Error())
return err
}
return nil
},
}
c.Flags().StringP("name", "n", "", "Basename of the generated ISO file")
c.Flags().StringP("output", "o", "", "Output directory (defaults to current directory)")
c.Flags().Bool("date", false, "Adds a date suffix into the generated ISO file")
c.Flags().String("overlay-rootfs", "", "Path of the overlayed rootfs data")
c.Flags().String("overlay-uefi", "", "Path of the overlayed uefi data")
c.Flags().String("overlay-iso", "", "Path of the overlayed iso data")
c.Flags().String("label", "", "Label of the ISO volume")
archType := newEnumFlag([]string{"x86_64", "arm64"}, "x86_64")
c.Flags().Bool("squash-no-compression", true, "Disable squashfs compression.")
c.Flags().VarP(archType, "arch", "a", "Arch to build the image for")
return c
}
func init() {
rootCmd.AddCommand(NewBuildISOCmd())
}

View File

@@ -1,70 +0,0 @@
/*
Copyright © 2022 SUSE LLC
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 cmd
import (
"bytes"
"fmt"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/spf13/viper"
)
var _ = Describe("BuildISO", Label("iso", "cmd"), func() {
var buf *bytes.Buffer
BeforeEach(func() {
buf = new(bytes.Buffer)
rootCmd.SetOut(buf)
rootCmd.SetErr(buf)
})
AfterEach(func() {
viper.Reset()
})
It("Errors out if no rootfs sources are defined", Label("flags"), func() {
_, _, err := executeCommandC(rootCmd, "build-iso")
fmt.Println(buf)
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("rootfs source image for building ISO was not provided"))
})
It("Errors out if rootfs is a non valid argument", Label("flags"), func() {
_, _, err := executeCommandC(rootCmd, "build-iso", "/no/image/reference")
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("invalid image reference"))
})
It("Errors out if overlay roofs path does not exist", Label("flags"), func() {
_, _, err := executeCommandC(
rootCmd, "build-iso", "system/cos", "--overlay-rootfs", "/nonexistingpath",
)
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("Invalid path"))
})
It("Errors out if overlay uefi path does not exist", Label("flags"), func() {
_, _, err := executeCommandC(
rootCmd, "build-iso", "someimage:latest", "--overlay-uefi", "/nonexistingpath",
)
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("Invalid path"))
})
It("Errors out if overlay iso path does not exist", Label("flags"), func() {
_, _, err := executeCommandC(
rootCmd, "build-iso", "some/image:latest", "--overlay-iso", "/nonexistingpath",
)
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("Invalid path"))
})
})

View File

@@ -1,29 +0,0 @@
/*
Copyright © 2021 SUSE LLC
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 cmd
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestWhitebox(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "CLI whitebox test suite")
}

View File

@@ -1,53 +0,0 @@
/*
Copyright © 2021 SUSE LLC
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 cmd
import (
"io/ioutil"
"os"
"github.com/spf13/cobra"
)
func executeCommandC(cmd *cobra.Command, args ...string) (c *cobra.Command, output string, err error) {
// Set args to command
cmd.SetArgs(args)
// store old stdout
oldStdout := os.Stdout
r, w, _ := os.Pipe()
// Change stdout to our pipe
os.Stdout = w
// run the command
c, err = cmd.ExecuteC()
if err != nil {
// Remember to restore stdout!
os.Stdout = oldStdout
return nil, "", err
}
err = w.Close()
if err != nil {
// Remember to restore stdout!
os.Stdout = oldStdout
return nil, "", err
}
// Read output from our pipe
out, _ := ioutil.ReadAll(r)
// restore stdout
os.Stdout = oldStdout
return c, string(out), nil
}

View File

@@ -1,90 +0,0 @@
package cmd
import (
"errors"
"fmt"
"os"
"strings"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func NewRootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "enki",
Short: "enki",
}
cmd.PersistentFlags().Bool("debug", false, "Enable debug output")
cmd.PersistentFlags().String("config-dir", "/etc/elemental", "Set config dir (default is /etc/elemental)")
cmd.PersistentFlags().String("logfile", "", "Set logfile")
cmd.PersistentFlags().Bool("quiet", false, "Do not output to stdout")
_ = viper.BindPFlag("debug", cmd.PersistentFlags().Lookup("debug"))
_ = viper.BindPFlag("config-dir", cmd.PersistentFlags().Lookup("config-dir"))
_ = viper.BindPFlag("logfile", cmd.PersistentFlags().Lookup("logfile"))
_ = viper.BindPFlag("quiet", cmd.PersistentFlags().Lookup("quiet"))
if viper.GetBool("debug") {
logrus.SetLevel(logrus.DebugLevel)
}
return cmd
}
// rootCmd represents the base command when called without any subcommands
var rootCmd = NewRootCmd()
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
// CheckRoot is a helper to return on PreRunE, so we can add it to commands that require root
func CheckRoot() error {
if os.Geteuid() != 0 {
return errors.New("this command requires root privileges")
}
return nil
}
type enum struct {
Allowed []string
Value string
}
func (a enum) String() string {
return a.Value
}
func (a *enum) Set(p string) error {
isIncluded := func(opts []string, val string) bool {
for _, opt := range opts {
if val == opt {
return true
}
}
return false
}
if !isIncluded(a.Allowed, p) {
return fmt.Errorf("%s is not included in %s", p, strings.Join(a.Allowed, ","))
}
a.Value = p
return nil
}
func (a *enum) Type() string {
return "string"
}
// newEnum give a list of allowed flag parameters, where the second argument is the default
func newEnumFlag(allowed []string, d string) *enum {
return &enum{
Allowed: allowed,
Value: d,
}
}

View File

@@ -1,154 +0,0 @@
module github.com/kairos-io/enki
go 1.20
require (
github.com/kairos-io/kairos-agent/v2 v2.1.11-0.20230713071318-9a16b94e2af6
github.com/kairos-io/kairos-sdk v0.0.9-0.20230719194412-fe26d1de9166
github.com/mitchellh/mapstructure v1.5.0
github.com/onsi/ginkgo/v2 v2.9.7
github.com/onsi/gomega v1.27.8
github.com/sanity-io/litter v1.5.5
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.16.0
github.com/twpayne/go-vfs v1.7.2
k8s.io/mount-utils v0.27.3
)
require (
atomicgo.dev/cursor v0.1.3 // indirect
atomicgo.dev/keyboard v0.2.9 // indirect
atomicgo.dev/schedule v0.0.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.10.0-rc.8 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230117203413-a47887b8f098 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect
github.com/cavaliergopher/grab v2.0.0+incompatible // indirect
github.com/cavaliergopher/grab/v3 v3.0.1 // indirect
github.com/cloudflare/circl v1.3.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/containerd/containerd v1.7.1 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/denisbrodbeck/machineid v1.0.1 // indirect
github.com/diskfs/go-diskfs v1.3.0 // indirect
github.com/distribution/distribution v2.8.2+incompatible // indirect
github.com/docker/cli v23.0.5+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v23.0.6+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-git/go-git/v5 v5.4.2 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-containerregistry v0.15.2 // indirect
github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gookit/color v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/itchyny/gojq v0.12.12 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/jaypipes/ghw v0.10.0 // indirect
github.com/jaypipes/pcidb v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/lithammer/fuzzysearch v1.1.8 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/moby v23.0.4+incompatible // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/mudler/entities v0.0.0-20220905203055-68348bae0f49 // indirect
github.com/mudler/yip v1.3.1-0.20230704124832-e5812d0f5890 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
github.com/packethost/packngo v0.29.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/xattr v0.4.9 // indirect
github.com/pterm/pterm v0.12.63 // indirect
github.com/qeesung/image2ascii v1.0.1 // indirect
github.com/rancher-sandbox/linuxkit v1.0.1-0.20230517173613-432a87ba3e09 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/samber/lo v1.37.0 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/sergi/go-diff v1.3.1 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/spectrocloud-labs/herd v0.4.2 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tredoe/osutil/v2 v2.0.0-rc.16 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
github.com/vmware/vmw-guestinfo v0.0.0-20220317130741-510905f0efa3 // indirect
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
github.com/willdonnelly/passwd v0.0.0-20141013001024-7935dab3074c // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/zcalusic/sysinfo v0.9.5 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/grpc v1.55.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect
pault.ag/go/modprobe v0.1.2 // indirect
pault.ag/go/topsort v0.1.1 // indirect
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +0,0 @@
package version
import (
"runtime"
)
var (
version = "v0.0.1"
// gitCommit is the git sha1
gitCommit = ""
)
// BuildInfo describes the compile time information.
type BuildInfo struct {
// Version is the current semver.
Version string `json:"version,omitempty"`
// GitCommit is the git sha1.
GitCommit string `json:"git_commit,omitempty"`
// GoVersion is the version of the Go compiler used.
GoVersion string `json:"go_version,omitempty"`
}
func GetVersion() string {
return version
}
// Get returns build info
func Get() BuildInfo {
v := BuildInfo{
Version: GetVersion(),
GitCommit: gitCommit,
GoVersion: runtime.Version(),
}
return v
}

View File

@@ -1,7 +0,0 @@
package main
import "github.com/kairos-io/enki/cmd"
func main() {
cmd.Execute()
}

View File

@@ -1,28 +0,0 @@
/*
Copyright © 2022 SUSE LLC
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 action_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestActionSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Actions test suite")
}

View File

@@ -1,360 +0,0 @@
package action
import (
"fmt"
"path/filepath"
"strings"
"time"
"github.com/kairos-io/enki/pkg/constants"
"github.com/kairos-io/enki/pkg/utils"
"github.com/kairos-io/kairos-agent/v2/pkg/elemental"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
sdk "github.com/kairos-io/kairos-sdk/utils"
)
type BuildISOAction struct {
cfg *v1.BuildConfig
spec *v1.LiveISO
e *elemental.Elemental
}
type BuildISOActionOption func(a *BuildISOAction)
func NewBuildISOAction(cfg *v1.BuildConfig, spec *v1.LiveISO, opts ...BuildISOActionOption) *BuildISOAction {
b := &BuildISOAction{
cfg: cfg,
e: elemental.NewElemental(&cfg.Config),
spec: spec,
}
for _, opt := range opts {
opt(b)
}
return b
}
// ISORun will install the system from a given configuration
func (b *BuildISOAction) ISORun() (err error) {
cleanup := sdk.NewCleanStack()
defer func() { err = cleanup.Cleanup(err) }()
isoTmpDir, err := utils.TempDir(b.cfg.Fs, "", "enki-iso")
if err != nil {
return err
}
cleanup.Push(func() error { return b.cfg.Fs.RemoveAll(isoTmpDir) })
rootDir := filepath.Join(isoTmpDir, "rootfs")
err = utils.MkdirAll(b.cfg.Fs, rootDir, constants.DirPerm)
if err != nil {
return err
}
uefiDir := filepath.Join(isoTmpDir, "uefi")
err = utils.MkdirAll(b.cfg.Fs, uefiDir, constants.DirPerm)
if err != nil {
return err
}
isoDir := filepath.Join(isoTmpDir, "iso")
err = utils.MkdirAll(b.cfg.Fs, isoDir, constants.DirPerm)
if err != nil {
return err
}
if b.cfg.OutDir != "" {
err = utils.MkdirAll(b.cfg.Fs, b.cfg.OutDir, constants.DirPerm)
if err != nil {
b.cfg.Logger.Errorf("Failed creating output folder: %s", b.cfg.OutDir)
return err
}
}
b.cfg.Logger.Infof("Preparing squashfs root...")
err = b.applySources(rootDir, b.spec.RootFS...)
if err != nil {
b.cfg.Logger.Errorf("Failed installing OS packages: %v", err)
return err
}
err = utils.CreateDirStructure(b.cfg.Fs, rootDir)
if err != nil {
b.cfg.Logger.Errorf("Failed creating root directory structure: %v", err)
return err
}
b.cfg.Logger.Infof("Preparing EFI image...")
err = b.applySources(uefiDir, b.spec.UEFI...)
if err != nil {
b.cfg.Logger.Errorf("Failed installing EFI packages: %v", err)
return err
}
b.cfg.Logger.Infof("Preparing ISO image root tree...")
err = b.applySources(isoDir, b.spec.Image...)
if err != nil {
b.cfg.Logger.Errorf("Failed installing ISO image packages: %v", err)
return err
}
err = b.prepareISORoot(isoDir, rootDir, uefiDir)
if err != nil {
b.cfg.Logger.Errorf("Failed preparing ISO's root tree: %v", err)
return err
}
b.cfg.Logger.Infof("Creating ISO image...")
err = b.burnISO(isoDir)
if err != nil {
b.cfg.Logger.Errorf("Failed preparing ISO's root tree: %v", err)
return err
}
return err
}
func (b BuildISOAction) prepareISORoot(isoDir string, rootDir string, uefiDir string) error {
kernel, initrd, err := b.e.FindKernelInitrd(rootDir)
if err != nil {
b.cfg.Logger.Error("Could not find kernel and/or initrd")
return err
}
err = utils.MkdirAll(b.cfg.Fs, filepath.Join(isoDir, "boot"), constants.DirPerm)
if err != nil {
return err
}
//TODO document boot/kernel and boot/initrd expectation in bootloader config
b.cfg.Logger.Debugf("Copying Kernel file %s to iso root tree", kernel)
err = utils.CopyFile(b.cfg.Fs, kernel, filepath.Join(isoDir, constants.IsoKernelPath))
if err != nil {
return err
}
b.cfg.Logger.Debugf("Copying initrd file %s to iso root tree", initrd)
err = utils.CopyFile(b.cfg.Fs, initrd, filepath.Join(isoDir, constants.IsoInitrdPath))
if err != nil {
return err
}
b.cfg.Logger.Info("Creating squashfs...")
err = utils.CreateSquashFS(b.cfg.Runner, b.cfg.Logger, rootDir, filepath.Join(isoDir, constants.IsoRootFile), constants.GetDefaultSquashfsOptions())
if err != nil {
return err
}
b.cfg.Logger.Info("Creating EFI image...")
err = b.createEFI(uefiDir, filepath.Join(isoDir, constants.IsoEFIPath))
if err != nil {
return err
}
return nil
}
func (b BuildISOAction) createEFI(root string, img string) error {
efiSize, err := utils.DirSize(b.cfg.Fs, root)
if err != nil {
return err
}
// align efiSize to the next 4MB slot
align := int64(4 * 1024 * 1024)
efiSizeMB := (efiSize/align*align + align) / (1024 * 1024)
err = b.e.CreateFileSystemImage(&v1.Image{
File: img,
Size: uint(efiSizeMB),
FS: constants.EfiFs,
Label: constants.EfiLabel,
})
if err != nil {
return err
}
files, err := b.cfg.Fs.ReadDir(root)
if err != nil {
return err
}
for _, f := range files {
_, err = b.cfg.Runner.Run("mcopy", "-s", "-i", img, filepath.Join(root, f.Name()), "::")
if err != nil {
return err
}
}
return nil
}
func (b BuildISOAction) burnISO(root string) error {
cmd := "xorriso"
var outputFile string
var isoFileName string
if b.cfg.Date {
currTime := time.Now()
isoFileName = fmt.Sprintf("%s.%s.iso", b.cfg.Name, currTime.Format("20060102"))
} else {
isoFileName = fmt.Sprintf("%s.iso", b.cfg.Name)
}
outputFile = isoFileName
if b.cfg.OutDir != "" {
outputFile = filepath.Join(b.cfg.OutDir, outputFile)
}
if exists, _ := utils.Exists(b.cfg.Fs, outputFile); exists {
b.cfg.Logger.Warnf("Overwriting already existing %s", outputFile)
err := b.cfg.Fs.Remove(outputFile)
if err != nil {
return err
}
}
args := []string{
"-volid", b.spec.Label, "-joliet", "on", "-padding", "0",
"-outdev", outputFile, "-map", root, "/", "-chmod", "0755", "--",
}
args = append(args, constants.GetXorrisoBooloaderArgs(root)...)
out, err := b.cfg.Runner.Run(cmd, args...)
b.cfg.Logger.Debugf("Xorriso: %s", string(out))
if err != nil {
return err
}
checksum, err := utils.CalcFileChecksum(b.cfg.Fs, outputFile)
if err != nil {
return fmt.Errorf("checksum computation failed: %w", err)
}
err = b.cfg.Fs.WriteFile(fmt.Sprintf("%s.sha256", outputFile), []byte(fmt.Sprintf("%s %s\n", checksum, isoFileName)), 0644)
if err != nil {
return fmt.Errorf("cannot write checksum file: %w", err)
}
return nil
}
func (b BuildISOAction) applySources(target string, sources ...*v1.ImageSource) error {
for _, src := range sources {
_, err := b.e.DumpSource(target, src)
if err != nil {
return err
}
}
return nil
}
func (g *BuildISOAction) PrepareEFI(rootDir, uefiDir string) error {
err := utils.MkdirAll(g.cfg.Fs, filepath.Join(uefiDir, constants.EfiBootPath), constants.DirPerm)
if err != nil {
return err
}
switch g.cfg.Arch {
case constants.ArchAmd64, constants.Archx86:
err = utils.CopyFile(
g.cfg.Fs,
filepath.Join(rootDir, constants.GrubEfiImagex86),
filepath.Join(uefiDir, constants.GrubEfiImagex86Dest),
)
case constants.ArchArm64:
err = utils.CopyFile(
g.cfg.Fs,
filepath.Join(rootDir, constants.GrubEfiImageArm64),
filepath.Join(uefiDir, constants.GrubEfiImageArm64Dest),
)
default:
err = fmt.Errorf("Not supported architecture: %v", g.cfg.Arch)
}
if err != nil {
return err
}
return g.cfg.Fs.WriteFile(filepath.Join(uefiDir, constants.EfiBootPath, constants.GrubCfg), []byte(constants.GrubEfiCfg), constants.FilePerm)
}
func (g *BuildISOAction) PrepareISO(rootDir, imageDir string) error {
err := utils.MkdirAll(g.cfg.Fs, filepath.Join(imageDir, constants.GrubPrefixDir), constants.DirPerm)
if err != nil {
return err
}
switch g.cfg.Arch {
case constants.ArchAmd64, constants.Archx86:
// Create eltorito image
eltorito, err := g.BuildEltoritoImg(rootDir)
if err != nil {
return err
}
// Inlude loaders in expected paths
loaderDir := filepath.Join(imageDir, constants.IsoLoaderPath)
err = utils.MkdirAll(g.cfg.Fs, loaderDir, constants.DirPerm)
if err != nil {
return err
}
loaderFiles := []string{eltorito, constants.GrubBootHybridImg}
loaderFiles = append(loaderFiles, strings.Split(constants.SyslinuxFiles, " ")...)
for _, f := range loaderFiles {
err = utils.CopyFile(g.cfg.Fs, filepath.Join(rootDir, f), loaderDir)
if err != nil {
return err
}
}
fontsDir := filepath.Join(loaderDir, "/grub2/fonts")
err = utils.MkdirAll(g.cfg.Fs, fontsDir, constants.DirPerm)
if err != nil {
return err
}
err = utils.CopyFile(g.cfg.Fs, filepath.Join(rootDir, constants.GrubFont), fontsDir)
if err != nil {
return err
}
case constants.ArchArm64:
// TBC
default:
return fmt.Errorf("Not supported architecture: %v", g.cfg.Arch)
}
// Write grub.cfg file
err = g.cfg.Fs.WriteFile(
filepath.Join(imageDir, constants.GrubPrefixDir, constants.GrubCfg),
[]byte(fmt.Sprintf(constants.GrubCfgTemplate, g.spec.GrubEntry, g.spec.Label)),
constants.FilePerm,
)
if err != nil {
return err
}
// Include EFI contents in iso root too
return g.PrepareEFI(rootDir, imageDir)
}
func (g *BuildISOAction) BuildEltoritoImg(rootDir string) (string, error) {
var args []string
args = append(args, "-O", constants.GrubBiosTarget)
args = append(args, "-o", constants.GrubBiosImg)
args = append(args, "-p", constants.GrubPrefixDir)
args = append(args, "-d", constants.GrubI386BinDir)
args = append(args, strings.Split(constants.GrubModules, " ")...)
chRoot := utils.NewChroot(rootDir, &g.cfg.Config)
out, err := chRoot.Run("grub2-mkimage", args...)
if err != nil {
g.cfg.Logger.Errorf("grub2-mkimage failed: %s", string(out))
g.cfg.Logger.Errorf("Error: %v", err)
return "", err
}
concatFiles := func() error {
return utils.ConcatFiles(
g.cfg.Fs, []string{constants.GrubBiosCDBoot, constants.GrubBiosImg},
constants.GrubEltoritoImg,
)
}
err = chRoot.RunCallback(concatFiles)
if err != nil {
return "", err
}
return constants.GrubEltoritoImg, nil
}

View File

@@ -1,195 +0,0 @@
/*
Copyright © 2022 SUSE LLC
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 action_test
import (
"bytes"
"errors"
"fmt"
"github.com/kairos-io/enki/pkg/action"
"github.com/kairos-io/enki/pkg/config"
"github.com/kairos-io/enki/pkg/constants"
"github.com/kairos-io/enki/pkg/utils"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/sirupsen/logrus"
"github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst"
"path/filepath"
)
var _ = Describe("Runtime Actions", func() {
var cfg *v1.BuildConfig
var runner *v1mock.FakeRunner
var fs vfs.FS
var logger v1.Logger
var mounter *v1mock.ErrorMounter
var syscall *v1mock.FakeSyscall
var client *v1mock.FakeHTTPClient
var cloudInit *v1mock.FakeCloudInitRunner
var cleanup func()
var memLog *bytes.Buffer
var imageExtractor *v1mock.FakeImageExtractor
BeforeEach(func() {
runner = v1mock.NewFakeRunner()
syscall = &v1mock.FakeSyscall{}
mounter = v1mock.NewErrorMounter()
client = &v1mock.FakeHTTPClient{}
memLog = &bytes.Buffer{}
logger = v1.NewBufferLogger(memLog)
logger.SetLevel(logrus.DebugLevel)
cloudInit = &v1mock.FakeCloudInitRunner{}
fs, cleanup, _ = vfst.NewTestFS(map[string]interface{}{})
imageExtractor = v1mock.NewFakeImageExtractor(logger)
cfg = config.NewBuildConfig(
config.WithFs(fs),
config.WithRunner(runner),
config.WithLogger(logger),
config.WithMounter(mounter),
config.WithSyscall(syscall),
config.WithClient(client),
config.WithCloudInitRunner(cloudInit),
config.WithImageExtractor(imageExtractor),
)
})
AfterEach(func() {
cleanup()
})
Describe("Build ISO", Label("iso"), func() {
var iso *v1.LiveISO
BeforeEach(func() {
iso = config.NewISO()
tmpDir, err := utils.TempDir(fs, "", "test")
Expect(err).ShouldNot(HaveOccurred())
cfg.Date = false
cfg.OutDir = tmpDir
runner.SideEffect = func(cmd string, args ...string) ([]byte, error) {
switch cmd {
case "xorriso":
err := fs.WriteFile(filepath.Join(tmpDir, "elemental.iso"), []byte("profound thoughts"), constants.FilePerm)
return []byte{}, err
default:
return []byte{}, nil
}
}
})
It("Successfully builds an ISO from a Docker image", func() {
rootSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.RootFS = []*v1.ImageSource{rootSrc}
uefiSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.UEFI = []*v1.ImageSource{uefiSrc}
imageSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.Image = []*v1.ImageSource{imageSrc}
// Create kernel and vmlinuz
// Thanks to the testfs stuff in utils.TempDir we know what the temp fs is gonna be as
// its predictable
bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot")
err := utils.MkdirAll(fs, bootDir, constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(filepath.Join(bootDir, "vmlinuz"))
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(filepath.Join(bootDir, "initrd"))
Expect(err).ShouldNot(HaveOccurred())
buildISO := action.NewBuildISOAction(cfg, iso)
err = buildISO.ISORun()
Expect(err).ShouldNot(HaveOccurred())
})
It("Fails if kernel or initrd is not found in rootfs", func() {
rootSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.RootFS = []*v1.ImageSource{rootSrc}
uefiSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.UEFI = []*v1.ImageSource{uefiSrc}
imageSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.Image = []*v1.ImageSource{imageSrc}
By("fails without kernel")
buildISO := action.NewBuildISOAction(cfg, iso)
err := buildISO.ISORun()
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("No file found with prefixes"))
Expect(err.Error()).To(ContainSubstring("uImage Image zImage vmlinuz image"))
bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot")
err = utils.MkdirAll(fs, bootDir, constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(filepath.Join(bootDir, "vmlinuz"))
Expect(err).ShouldNot(HaveOccurred())
By("fails without initrd")
buildISO = action.NewBuildISOAction(cfg, iso)
err = buildISO.ISORun()
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("No file found with prefixes"))
Expect(err.Error()).To(ContainSubstring("initrd initramfs"))
})
It("Fails installing image sources", func() {
rootSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.RootFS = []*v1.ImageSource{rootSrc}
uefiSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.UEFI = []*v1.ImageSource{uefiSrc}
imageSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.Image = []*v1.ImageSource{imageSrc}
imageExtractor.SideEffect = func(imageRef, destination, platformRef string) error {
return fmt.Errorf("uh oh")
}
buildISO := action.NewBuildISOAction(cfg, iso)
err := buildISO.ISORun()
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("uh oh"))
})
It("Fails on ISO filesystem creation", func() {
rootSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.RootFS = []*v1.ImageSource{rootSrc}
uefiSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.UEFI = []*v1.ImageSource{uefiSrc}
imageSrc, _ := v1.NewSrcFromURI("oci:image:version")
iso.Image = []*v1.ImageSource{imageSrc}
bootDir := filepath.Join("/tmp/enki-iso/rootfs", "boot")
err := utils.MkdirAll(fs, bootDir, constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(filepath.Join(bootDir, "vmlinuz"))
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create(filepath.Join(bootDir, "initrd"))
Expect(err).ShouldNot(HaveOccurred())
runner.SideEffect = func(command string, args ...string) ([]byte, error) {
if command == "xorriso" {
return []byte{}, errors.New("Burn ISO error")
}
return []byte{}, nil
}
buildISO := action.NewBuildISOAction(cfg, iso)
err = buildISO.ISORun()
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Burn ISO error"))
})
})
})

View File

@@ -1,303 +0,0 @@
package config
import (
"github.com/kairos-io/enki/internal/version"
"github.com/kairos-io/enki/pkg/constants"
"github.com/kairos-io/enki/pkg/utils"
"github.com/kairos-io/kairos-agent/v2/pkg/cloudinit"
"github.com/kairos-io/kairos-agent/v2/pkg/http"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/mitchellh/mapstructure"
"github.com/sanity-io/litter"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/twpayne/go-vfs"
"io"
"io/fs"
"k8s.io/mount-utils"
"os"
"reflect"
"runtime"
)
var decodeHook = viper.DecodeHook(
mapstructure.ComposeDecodeHookFunc(
UnmarshalerHook(),
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
),
)
func WithFs(fs v1.FS) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Fs = fs
return nil
}
}
func WithLogger(logger v1.Logger) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Logger = logger
return nil
}
}
func WithSyscall(syscall v1.SyscallInterface) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Syscall = syscall
return nil
}
}
func WithMounter(mounter mount.Interface) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Mounter = mounter
return nil
}
}
func WithRunner(runner v1.Runner) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Runner = runner
return nil
}
}
func WithClient(client v1.HTTPClient) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Client = client
return nil
}
}
func WithCloudInitRunner(ci v1.CloudInitRunner) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.CloudInitRunner = ci
return nil
}
}
func WithArch(arch string) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.Arch = arch
return nil
}
}
func WithImageExtractor(extractor v1.ImageExtractor) func(r *v1.Config) error {
return func(r *v1.Config) error {
r.ImageExtractor = extractor
return nil
}
}
type GenericOptions func(a *v1.Config) error
func ReadConfigBuild(configDir string, flags *pflag.FlagSet, mounter mount.Interface) (*v1.BuildConfig, error) {
logger := v1.NewLogger()
if configDir == "" {
configDir = "."
}
cfg := NewBuildConfig(
WithLogger(logger),
WithMounter(mounter),
)
configLogger(cfg.Logger, cfg.Fs)
viper.AddConfigPath(configDir)
viper.SetConfigType("yaml")
viper.SetConfigName("manifest.yaml")
// If a config file is found, read it in.
_ = viper.MergeInConfig()
// Bind buildconfig flags
bindGivenFlags(viper.GetViper(), flags)
// unmarshal all the vars into the config object
err := viper.Unmarshal(cfg, setDecoder, decodeHook)
if err != nil {
cfg.Logger.Warnf("error unmarshalling config: %s", err)
}
err = cfg.Sanitize()
cfg.Logger.Debugf("Full config loaded: %s", litter.Sdump(cfg))
return cfg, err
}
func ReadBuildISO(b *v1.BuildConfig, flags *pflag.FlagSet) (*v1.LiveISO, error) {
iso := NewISO()
vp := viper.Sub("iso")
if vp == nil {
vp = viper.New()
}
// Bind build-iso cmd flags
bindGivenFlags(vp, flags)
err := vp.Unmarshal(iso, setDecoder, decodeHook)
if err != nil {
b.Logger.Warnf("error unmarshalling LiveISO: %s", err)
}
err = iso.Sanitize()
b.Logger.Debugf("Loaded LiveISO: %s", litter.Sdump(iso))
return iso, err
}
func NewISO() *v1.LiveISO {
return &v1.LiveISO{
Label: constants.ISOLabel,
GrubEntry: constants.GrubDefEntry,
UEFI: []*v1.ImageSource{},
Image: []*v1.ImageSource{},
}
}
func NewBuildConfig(opts ...GenericOptions) *v1.BuildConfig {
b := &v1.BuildConfig{
Config: *NewConfig(opts...),
Name: constants.BuildImgName,
}
return b
}
func NewConfig(opts ...GenericOptions) *v1.Config {
log := v1.NewLogger()
arch, err := utils.GolangArchToArch(runtime.GOARCH)
if err != nil {
log.Errorf("invalid arch: %s", err.Error())
return nil
}
c := &v1.Config{
Fs: vfs.OSFS,
Logger: log,
Syscall: &v1.RealSyscall{},
Client: http.NewClient(),
Repos: []v1.Repository{},
Arch: arch,
SquashFsNoCompression: true,
}
for _, o := range opts {
err := o(c)
if err != nil {
log.Errorf("error applying config option: %s", err.Error())
return nil
}
}
// delay runner creation after we have run over the options in case we use WithRunner
if c.Runner == nil {
c.Runner = &v1.RealRunner{Logger: c.Logger}
}
// Now check if the runner has a logger inside, otherwise point our logger into it
// This can happen if we set the WithRunner option as that doesn't set a logger
if c.Runner.GetLogger() == nil {
c.Runner.SetLogger(c.Logger)
}
// Delay the yip runner creation, so we set the proper logger instead of blindly setting it to the logger we create
// at the start of NewRunConfig, as WithLogger can be passed on init, and that would result in 2 different logger
// instances, on the config.Logger and the other on config.CloudInitRunner
if c.CloudInitRunner == nil {
c.CloudInitRunner = cloudinit.NewYipCloudInitRunner(c.Logger, c.Runner, vfs.OSFS)
}
if c.Mounter == nil {
c.Mounter = mount.New(constants.MountBinary)
}
return c
}
func configLogger(log v1.Logger, vfs v1.FS) {
// Set debug level
if viper.GetBool("debug") {
log.SetLevel(v1.DebugLevel())
}
// Set formatter so both file and stdout format are equal
log.SetFormatter(&logrus.TextFormatter{
ForceColors: true,
DisableColors: false,
DisableTimestamp: false,
FullTimestamp: true,
})
// Logfile
logfile := viper.GetString("logfile")
if logfile != "" {
o, err := vfs.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, fs.ModePerm)
if err != nil {
log.Errorf("Could not open %s for logging to file: %s", logfile, err.Error())
}
// else set it to both stdout and the file
mw := io.MultiWriter(os.Stdout, o)
log.SetOutput(mw)
} else { // no logfile
if viper.GetBool("quiet") { // quiet is enabled so discard all logging
log.SetOutput(io.Discard)
} else { // default to stdout
log.SetOutput(os.Stdout)
}
}
log.Infof("Starting enki version %s", version.GetVersion())
if log.GetLevel() == logrus.DebugLevel {
log.Debugf("%+v\n", version.Get())
}
}
// BindGivenFlags binds to viper only passed flags, ignoring any non provided flag
func bindGivenFlags(vp *viper.Viper, flagSet *pflag.FlagSet) {
if flagSet != nil {
flagSet.VisitAll(func(f *pflag.Flag) {
if f.Changed {
_ = vp.BindPFlag(f.Name, f)
}
})
}
}
// setDecoder sets ZeroFields mastructure attribute to true
func setDecoder(config *mapstructure.DecoderConfig) {
// Make sure we zero fields before applying them, this is relevant for slices
// so we do not merge with any already present value and directly apply whatever
// we got form configs.
config.ZeroFields = true
}
type Unmarshaler interface {
CustomUnmarshal(interface{}) (bool, error)
}
func UnmarshalerHook() mapstructure.DecodeHookFunc {
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
// get the destination object address if it is not passed by reference
if to.CanAddr() {
to = to.Addr()
}
// If the destination implements the unmarshaling interface
u, ok := to.Interface().(Unmarshaler)
if !ok {
return from.Interface(), nil
}
// If it is nil and a pointer, create and assign the target value first
if to.IsNil() && to.Type().Kind() == reflect.Ptr {
to.Set(reflect.New(to.Type().Elem()))
u = to.Interface().(Unmarshaler)
}
// Call the custom unmarshaling method
cont, err := u.CustomUnmarshal(from.Interface())
if cont {
// Continue with the decoding stack
return from.Interface(), err
}
// Decoding finalized
return to.Interface(), err
}
}

View File

@@ -1,124 +0,0 @@
package constants
import (
"fmt"
"os"
"path/filepath"
)
const (
GrubDefEntry = "Kairos"
EfiLabel = "COS_GRUB"
ISOLabel = "COS_LIVE"
MountBinary = "/usr/bin/mount"
EfiFs = "vfat"
IsoRootFile = "rootfs.squashfs"
IsoEFIPath = "/boot/uefi.img"
BuildImgName = "elemental"
EfiBootPath = "/EFI/BOOT"
GrubEfiImagex86 = "/usr/share/grub2/x86_64-efi/grub.efi"
GrubEfiImageArm64 = "/usr/share/grub2/arm64-efi/grub.efi"
GrubEfiImagex86Dest = EfiBootPath + "/bootx64.efi"
GrubEfiImageArm64Dest = EfiBootPath + "/bootaa64.efi"
GrubCfg = "grub.cfg"
GrubPrefixDir = "/boot/grub2"
GrubEfiCfg = "search --no-floppy --file --set=root " + IsoKernelPath +
"\nset prefix=($root)" + GrubPrefixDir +
"\nconfigfile $prefix/" + GrubCfg
GrubFont = "/usr/share/grub2/unicode.pf2"
GrubBootHybridImg = "/usr/share/grub2/i386-pc/boot_hybrid.img"
SyslinuxFiles = "/usr/share/syslinux/isolinux.bin " +
"/usr/share/syslinux/menu.c32 " +
"/usr/share/syslinux/chain.c32 " +
"/usr/share/syslinux/mboot.c32"
IsoLoaderPath = "/boot/x86_64/loader"
GrubCfgTemplate = `search --no-floppy --file --set=root /boot/kernel
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 "%s" --class os --unrestricted {
echo Loading kernel...
$linux ($root)/boot/kernel cdroot root=live:CDLABEL=%s rd.live.dir=/ rd.live.squashimg=rootfs.squashfs rd.live.overlay.overlayfs console=tty1 console=ttyS0 rd.cos.disable
echo Loading initrd...
$initrd ($root)/boot/initrd
}
if [ "${grub_platform}" = "efi" ]; then
hiddenentry "Text mode" --hotkey "t" {
set textmode=true
terminal_output console
}
fi`
GrubBiosTarget = "i386-pc"
GrubI386BinDir = "/usr/share/grub2/i386-pc"
GrubBiosImg = GrubI386BinDir + "/core.img"
GrubBiosCDBoot = GrubI386BinDir + "/cdboot.img"
GrubEltoritoImg = GrubI386BinDir + "/eltorito.img"
//TODO this list could be optimized
GrubModules = "ext2 iso9660 linux echo configfile search_label search_fs_file search search_fs_uuid " +
"ls normal gzio png fat gettext font minicmd gfxterm gfxmenu all_video xfs btrfs lvm luks " +
"gcry_rijndael gcry_sha256 gcry_sha512 crypto cryptodisk test true loadenv part_gpt " +
"part_msdos biosdisk vga vbe chain boot"
IsoHybridMBR = "/boot/x86_64/loader/boot_hybrid.img"
IsoBootCatalog = "/boot/x86_64/boot.catalog"
IsoBootFile = "/boot/x86_64/loader/eltorito.img"
// These paths are arbitrary but coupled to grub.cfg
IsoKernelPath = "/boot/kernel"
IsoInitrdPath = "/boot/initrd"
// Default directory and file fileModes
DirPerm = os.ModeDir | os.ModePerm
FilePerm = 0666
NoWriteDirPerm = 0555 | os.ModeDir
TempDirPerm = os.ModePerm | os.ModeSticky | os.ModeDir
ArchAmd64 = "amd64"
Archx86 = "x86_64"
ArchArm64 = "arm64"
)
// GetDefaultSquashfsOptions returns the default options to use when creating a squashfs
func GetDefaultSquashfsOptions() []string {
return []string{"-b", "1024k"}
}
func GetXorrisoBooloaderArgs(root string) []string {
args := []string{
"-boot_image", "grub", fmt.Sprintf("bin_path=%s", IsoBootFile),
"-boot_image", "grub", fmt.Sprintf("grub2_mbr=%s/%s", root, IsoHybridMBR),
"-boot_image", "grub", "grub2_boot_info=on",
"-boot_image", "any", "partition_offset=16",
"-boot_image", "any", fmt.Sprintf("cat_path=%s", IsoBootCatalog),
"-boot_image", "any", "cat_hidden=on",
"-boot_image", "any", "boot_info_table=on",
"-boot_image", "any", "platform_id=0x00",
"-boot_image", "any", "emul_type=no_emulation",
"-boot_image", "any", "load_size=2048",
"-append_partition", "2", "0xef", filepath.Join(root, IsoEFIPath),
"-boot_image", "any", "next",
"-boot_image", "any", "efi_path=--interval:appended_partition_2:all::",
"-boot_image", "any", "platform_id=0xef",
"-boot_image", "any", "emul_type=no_emulation",
}
return args
}

View File

@@ -1,218 +0,0 @@
/*
Copyright © 2022 SUSE LLC
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 utils
import (
"errors"
"fmt"
"os"
"sort"
"strings"
"github.com/kairos-io/enki/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
)
// Chroot represents the struct that will allow us to run commands inside a given chroot
type Chroot struct {
path string
defaultMounts []string
extraMounts map[string]string
activeMounts []string
config *v1.Config
}
func NewChroot(path string, config *v1.Config) *Chroot {
return &Chroot{
path: path,
defaultMounts: []string{"/dev", "/dev/pts", "/proc", "/sys"},
extraMounts: map[string]string{},
activeMounts: []string{},
config: config,
}
}
// ChrootedCallback runs the given callback in a chroot environment
func ChrootedCallback(cfg *v1.Config, path string, bindMounts map[string]string, callback func() error) error {
chroot := NewChroot(path, cfg)
chroot.SetExtraMounts(bindMounts)
return chroot.RunCallback(callback)
}
// Sets additional bind mounts for the chroot enviornment. They are represented
// in a map where the key is the path outside the chroot and the value is the
// path inside the chroot.
func (c *Chroot) SetExtraMounts(extraMounts map[string]string) {
c.extraMounts = extraMounts
}
// Prepare will mount the defaultMounts as bind mounts, to be ready when we run chroot
func (c *Chroot) Prepare() error {
var err error
keys := []string{}
mountOptions := []string{"bind"}
if len(c.activeMounts) > 0 {
return errors.New("There are already active mountpoints for this instance")
}
defer func() {
if err != nil {
c.Close()
}
}()
for _, mnt := range c.defaultMounts {
mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), mnt)
err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm)
if err != nil {
return err
}
err = c.config.Mounter.Mount(mnt, mountPoint, "bind", mountOptions)
if err != nil {
return err
}
c.activeMounts = append(c.activeMounts, mountPoint)
}
for k := range c.extraMounts {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
mountPoint := fmt.Sprintf("%s%s", strings.TrimSuffix(c.path, "/"), c.extraMounts[k])
err = MkdirAll(c.config.Fs, mountPoint, constants.DirPerm)
if err != nil {
return err
}
err = c.config.Mounter.Mount(k, mountPoint, "bind", mountOptions)
if err != nil {
return err
}
c.activeMounts = append(c.activeMounts, mountPoint)
}
return nil
}
// Close will unmount all active mounts created in Prepare on reverse order
func (c *Chroot) Close() error {
failures := []string{}
for len(c.activeMounts) > 0 {
curr := c.activeMounts[len(c.activeMounts)-1]
c.config.Logger.Debugf("Unmounting %s from chroot", curr)
c.activeMounts = c.activeMounts[:len(c.activeMounts)-1]
err := c.config.Mounter.Unmount(curr)
if err != nil {
c.config.Logger.Errorf("Error unmounting %s: %s", curr, err)
failures = append(failures, curr)
}
}
if len(failures) > 0 {
c.activeMounts = failures
return fmt.Errorf("failed closing chroot environment. Unmount failures: %v", failures)
}
return nil
}
// RunCallback runs the given callback in a chroot environment
func (c *Chroot) RunCallback(callback func() error) (err error) {
var currentPath string
var oldRootF *os.File
// Store current path
currentPath, err = os.Getwd()
if err != nil {
c.config.Logger.Error("Failed to get current path")
return err
}
defer func() {
tmpErr := os.Chdir(currentPath)
if err == nil && tmpErr != nil {
err = tmpErr
}
}()
// Store current root
oldRootF, err = c.config.Fs.Open("/")
if err != nil {
c.config.Logger.Errorf("Can't open current root")
return err
}
defer oldRootF.Close()
if len(c.activeMounts) == 0 {
err = c.Prepare()
if err != nil {
c.config.Logger.Errorf("Can't mount default mounts")
return err
}
defer func() {
tmpErr := c.Close()
if err == nil {
err = tmpErr
}
}()
}
// Change to new dir before running chroot!
err = c.config.Syscall.Chdir(c.path)
if err != nil {
c.config.Logger.Errorf("Can't chdir %s: %s", c.path, err)
return err
}
err = c.config.Syscall.Chroot(c.path)
if err != nil {
c.config.Logger.Errorf("Can't chroot %s: %s", c.path, err)
return err
}
// Restore to old root
defer func() {
tmpErr := oldRootF.Chdir()
if tmpErr != nil {
c.config.Logger.Errorf("Can't change to old root dir")
if err == nil {
err = tmpErr
}
} else {
tmpErr = c.config.Syscall.Chroot(".")
if tmpErr != nil {
c.config.Logger.Errorf("Can't chroot back to old root")
if err == nil {
err = tmpErr
}
}
}
}()
return callback()
}
// Run executes a command inside a chroot
func (c *Chroot) Run(command string, args ...string) (out []byte, err error) {
callback := func() error {
out, err = c.config.Runner.Run(command, args...)
return err
}
err = c.RunCallback(callback)
if err != nil {
c.config.Logger.Errorf("Cant run command %s with args %v on chroot: %s", command, args, err)
c.config.Logger.Debugf("Output from command: %s", out)
}
return out, err
}

View File

@@ -1,40 +0,0 @@
package utils
import (
"fmt"
"github.com/kairos-io/enki/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"strings"
)
// CreateSquashFS creates a squash file at destination from a source, with options
// TODO: Check validity of source maybe?
func CreateSquashFS(runner v1.Runner, logger v1.Logger, source string, destination string, options []string) error {
// create args
args := []string{source, destination}
// append options passed to args in order to have the correct order
// protect against options passed together in the same string , i.e. "-x add" instead of "-x", "add"
var optionsExpanded []string
for _, op := range options {
optionsExpanded = append(optionsExpanded, strings.Split(op, " ")...)
}
args = append(args, optionsExpanded...)
out, err := runner.Run("mksquashfs", args...)
if err != nil {
logger.Debugf("Error running squashfs creation, stdout: %s", out)
logger.Errorf("Error while creating squashfs from %s to %s: %s", source, destination, err)
return err
}
return nil
}
func GolangArchToArch(arch string) (string, error) {
switch strings.ToLower(arch) {
case constants.ArchAmd64:
return constants.Archx86, nil
case constants.ArchArm64:
return constants.ArchArm64, nil
default:
return "", fmt.Errorf("invalid arch")
}
}

View File

@@ -1,223 +0,0 @@
package utils
import (
"crypto/sha256"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
"github.com/kairos-io/enki/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
"github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst"
)
// MkdirAll directory and all parents if not existing
func MkdirAll(fs v1.FS, name string, mode os.FileMode) (err error) {
if _, isReadOnly := fs.(*vfs.ReadOnlyFS); isReadOnly {
return permError("mkdir", name)
}
if name, err = fs.RawPath(name); err != nil {
return &os.PathError{Op: "mkdir", Path: name, Err: err}
}
return os.MkdirAll(name, mode)
}
// permError returns an *os.PathError with Err syscall.EPERM.
func permError(op, path string) error {
return &os.PathError{
Op: op,
Path: path,
Err: syscall.EPERM,
}
}
// Copies source file to target file using Fs interface
func CreateDirStructure(fs v1.FS, target string) error {
for _, dir := range []string{"/run", "/dev", "/boot", "/usr/local", "/oem"} {
err := MkdirAll(fs, filepath.Join(target, dir), constants.DirPerm)
if err != nil {
return err
}
}
for _, dir := range []string{"/proc", "/sys"} {
err := MkdirAll(fs, filepath.Join(target, dir), constants.NoWriteDirPerm)
if err != nil {
return err
}
}
err := MkdirAll(fs, filepath.Join(target, "/tmp"), constants.DirPerm)
if err != nil {
return err
}
// Set /tmp permissions regardless the umask setup
err = fs.Chmod(filepath.Join(target, "/tmp"), constants.TempDirPerm)
if err != nil {
return err
}
return nil
}
// TempDir creates a temp file in the virtual fs
// Took from afero.FS code and adapted
func TempDir(fs v1.FS, dir, prefix string) (name string, err error) {
if dir == "" {
dir = os.TempDir()
}
// This skips adding random stuff to the created temp dir so the temp dir created is predictable for testing
if _, isTestFs := fs.(*vfst.TestFS); isTestFs {
err = MkdirAll(fs, filepath.Join(dir, prefix), 0700)
if err != nil {
return "", err
}
name = filepath.Join(dir, prefix)
return
}
nconflict := 0
for i := 0; i < 10000; i++ {
try := filepath.Join(dir, prefix+nextRandom())
err = MkdirAll(fs, try, 0700)
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
randmu.Lock()
rand = reseed()
randmu.Unlock()
}
continue
}
if err == nil {
name = try
}
break
}
return
}
// Random number state.
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
var rand uint32
var randmu sync.Mutex
func reseed() uint32 {
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}
func nextRandom() string {
randmu.Lock()
r := rand
if r == 0 {
r = reseed()
}
r = r*1664525 + 1013904223 // constants from Numerical Recipes
rand = r
randmu.Unlock()
return strconv.Itoa(int(1e9 + r%1e9))[1:]
}
// CopyFile Copies source file to target file using Fs interface. If target
// is directory source is copied into that directory using source name file.
func CopyFile(fs v1.FS, source string, target string) (err error) {
return ConcatFiles(fs, []string{source}, target)
}
// IsDir check if the path is a dir
func IsDir(fs v1.FS, path string) (bool, error) {
fi, err := fs.Stat(path)
if err != nil {
return false, err
}
return fi.IsDir(), nil
}
// ConcatFiles Copies source files to target file using Fs interface.
// Source files are concatenated into target file in the given order.
// If target is a directory source is copied into that directory using
// 1st source name file.
func ConcatFiles(fs v1.FS, sources []string, target string) (err error) {
if len(sources) == 0 {
return fmt.Errorf("Empty sources list")
}
if dir, _ := IsDir(fs, target); dir {
target = filepath.Join(target, filepath.Base(sources[0]))
}
targetFile, err := fs.Create(target)
if err != nil {
return err
}
defer func() {
if err == nil {
err = targetFile.Close()
} else {
_ = fs.Remove(target)
}
}()
var sourceFile *os.File
for _, source := range sources {
sourceFile, err = fs.Open(source)
if err != nil {
break
}
_, err = io.Copy(targetFile, sourceFile)
if err != nil {
break
}
err = sourceFile.Close()
if err != nil {
break
}
}
return err
}
// DirSize returns the accumulated size of all files in folder
func DirSize(fs v1.FS, path string) (int64, error) {
var size int64
err := vfs.Walk(fs, path, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return err
})
return size, err
}
// Check if a file or directory exists.
func Exists(fs v1.FS, path string) (bool, error) {
_, err := fs.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
// CalcFileChecksum opens the given file and returns the sha256 checksum of it.
func CalcFileChecksum(fs v1.FS, fileName string) (string, error) {
f, err := fs.Open(fileName)
if err != nil {
return "", err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}

View File

@@ -1,29 +0,0 @@
/*
Copyright © 2021 SUSE LLC
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 utils_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestWhitebox(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Utils test suite")
}

View File

@@ -1,294 +0,0 @@
/*
Copyright © 2021 SUSE LLC
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 utils_test
import (
"errors"
"fmt"
conf "github.com/kairos-io/enki/pkg/config"
"github.com/kairos-io/enki/pkg/constants"
"github.com/kairos-io/enki/pkg/utils"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/twpayne/go-vfs"
"github.com/twpayne/go-vfs/vfst"
"os"
"strings"
)
var _ = Describe("Utils", Label("utils"), func() {
var config *v1.Config
var runner *v1mock.FakeRunner
var logger v1.Logger
var syscall *v1mock.FakeSyscall
var client *v1mock.FakeHTTPClient
var mounter *v1mock.ErrorMounter
var fs vfs.FS
var cleanup func()
BeforeEach(func() {
runner = v1mock.NewFakeRunner()
syscall = &v1mock.FakeSyscall{}
mounter = v1mock.NewErrorMounter()
client = &v1mock.FakeHTTPClient{}
logger = v1.NewNullLogger()
// Ensure /tmp exists in the VFS
fs, cleanup, _ = vfst.NewTestFS(nil)
fs.Mkdir("/tmp", constants.DirPerm)
fs.Mkdir("/run", constants.DirPerm)
fs.Mkdir("/etc", constants.DirPerm)
config = conf.NewConfig(
conf.WithFs(fs),
conf.WithRunner(runner),
conf.WithLogger(logger),
conf.WithMounter(mounter),
conf.WithSyscall(syscall),
conf.WithClient(client),
)
})
AfterEach(func() { cleanup() })
Describe("Chroot", Label("chroot"), func() {
var chroot *utils.Chroot
BeforeEach(func() {
chroot = utils.NewChroot(
"/whatever",
config,
)
})
Describe("ChrootedCallback method", func() {
It("runs a callback in a chroot", func() {
err := utils.ChrootedCallback(config, "/somepath", map[string]string{}, func() error {
return nil
})
Expect(err).ShouldNot(HaveOccurred())
err = utils.ChrootedCallback(config, "/somepath", map[string]string{}, func() error {
return fmt.Errorf("callback error")
})
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("callback error"))
})
})
Describe("on success", func() {
It("command should be called in the chroot", func() {
_, err := chroot.Run("chroot-command")
Expect(err).To(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
})
It("commands should be called with a customized chroot", func() {
chroot.SetExtraMounts(map[string]string{"/real/path": "/in/chroot/path"})
Expect(chroot.Prepare()).To(BeNil())
defer chroot.Close()
_, err := chroot.Run("chroot-command")
Expect(err).To(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
_, err = chroot.Run("chroot-another-command")
Expect(err).To(BeNil())
})
It("runs a callback in a custom chroot", func() {
called := false
callback := func() error {
called = true
return nil
}
err := chroot.RunCallback(callback)
Expect(err).To(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
Expect(called).To(BeTrue())
})
})
Describe("on failure", func() {
It("should return error if chroot-command fails", func() {
runner.ReturnError = errors.New("run error")
_, err := chroot.Run("chroot-command")
Expect(err).NotTo(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
})
It("should return error if callback fails", func() {
called := false
callback := func() error {
called = true
return errors.New("Callback error")
}
err := chroot.RunCallback(callback)
Expect(err).NotTo(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
Expect(called).To(BeTrue())
})
It("should return error if preparing twice before closing", func() {
Expect(chroot.Prepare()).To(BeNil())
defer chroot.Close()
Expect(chroot.Prepare()).NotTo(BeNil())
Expect(chroot.Close()).To(BeNil())
Expect(chroot.Prepare()).To(BeNil())
})
It("should return error if failed to chroot", func() {
syscall.ErrorOnChroot = true
_, err := chroot.Run("chroot-command")
Expect(err).ToNot(BeNil())
Expect(syscall.WasChrootCalledWith("/whatever")).To(BeTrue())
Expect(err.Error()).To(ContainSubstring("chroot error"))
})
It("should return error if failed to mount on prepare", Label("mount"), func() {
mounter.ErrorOnMount = true
_, err := chroot.Run("chroot-command")
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("mount error"))
})
It("should return error if failed to unmount on close", Label("unmount"), func() {
mounter.ErrorOnUnmount = true
_, err := chroot.Run("chroot-command")
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(ContainSubstring("failed closing chroot"))
})
})
})
Describe("CopyFile", Label("CopyFile"), func() {
It("Copies source file to target file", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create("/some/file")
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Stat("/some/otherfile")
Expect(err).Should(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).ShouldNot(HaveOccurred())
e, err := utils.Exists(fs, "/some/otherfile")
Expect(err).ShouldNot(HaveOccurred())
Expect(e).To(BeTrue())
})
It("Copies source file to target folder", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
err = utils.MkdirAll(fs, "/someotherfolder", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Create("/some/file")
Expect(err).ShouldNot(HaveOccurred())
_, err = fs.Stat("/someotherfolder/file")
Expect(err).Should(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/someotherfolder")).ShouldNot(HaveOccurred())
e, err := utils.Exists(fs, "/someotherfolder/file")
Expect(err).ShouldNot(HaveOccurred())
Expect(e).To(BeTrue())
})
It("Fails to open non existing file", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil())
_, err = fs.Stat("/some/otherfile")
Expect(err).NotTo(BeNil())
})
It("Fails to copy on non writable target", func() {
err := utils.MkdirAll(fs, "/some", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
fs.Create("/some/file")
_, err = fs.Stat("/some/otherfile")
Expect(err).NotTo(BeNil())
fs = vfs.NewReadOnlyFS(fs)
Expect(utils.CopyFile(fs, "/some/file", "/some/otherfile")).NotTo(BeNil())
_, err = fs.Stat("/some/otherfile")
Expect(err).NotTo(BeNil())
})
})
Describe("CreateDirStructure", Label("CreateDirStructure"), func() {
It("Creates essential directories", func() {
dirList := []string{"sys", "proc", "dev", "tmp", "boot", "usr/local", "oem"}
for _, dir := range dirList {
_, err := fs.Stat(fmt.Sprintf("/my/root/%s", dir))
Expect(err).NotTo(BeNil())
}
Expect(utils.CreateDirStructure(fs, "/my/root")).To(BeNil())
for _, dir := range dirList {
fi, err := fs.Stat(fmt.Sprintf("/my/root/%s", dir))
Expect(err).To(BeNil())
if fi.Name() == "tmp" {
Expect(fmt.Sprintf("%04o", fi.Mode().Perm())).To(Equal("0777"))
Expect(fi.Mode() & os.ModeSticky).NotTo(Equal(0))
}
if fi.Name() == "sys" {
Expect(fmt.Sprintf("%04o", fi.Mode().Perm())).To(Equal("0555"))
}
}
})
It("Fails on non writable target", func() {
fs = vfs.NewReadOnlyFS(fs)
Expect(utils.CreateDirStructure(fs, "/my/root")).NotTo(BeNil())
})
})
Describe("DirSize", Label("fs"), func() {
BeforeEach(func() {
err := utils.MkdirAll(fs, "/folder/subfolder", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
f, err := fs.Create("/folder/file")
Expect(err).ShouldNot(HaveOccurred())
err = f.Truncate(1024)
Expect(err).ShouldNot(HaveOccurred())
f, err = fs.Create("/folder/subfolder/file")
Expect(err).ShouldNot(HaveOccurred())
err = f.Truncate(2048)
Expect(err).ShouldNot(HaveOccurred())
})
It("Returns the expected size of a test folder", func() {
size, err := utils.DirSize(fs, "/folder")
Expect(err).ShouldNot(HaveOccurred())
Expect(size).To(Equal(int64(3072)))
})
})
Describe("CalcFileChecksum", Label("checksum"), func() {
It("compute correct sha256 checksum", func() {
testData := strings.Repeat("abcdefghilmnopqrstuvz\n", 20)
testDataSHA256 := "7f182529f6362ae9cfa952ab87342a7180db45d2c57b52b50a68b6130b15a422"
err := fs.Mkdir("/iso", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
err = fs.WriteFile("/iso/test.iso", []byte(testData), 0644)
Expect(err).ShouldNot(HaveOccurred())
checksum, err := utils.CalcFileChecksum(fs, "/iso/test.iso")
Expect(err).ShouldNot(HaveOccurred())
Expect(checksum).To(Equal(testDataSHA256))
})
})
Describe("CreateSquashFS", Label("CreateSquashFS"), func() {
It("runs with no options if none given", func() {
err := utils.CreateSquashFS(runner, logger, "source", "dest", []string{})
Expect(runner.IncludesCmds([][]string{
{"mksquashfs", "source", "dest"},
})).To(BeNil())
Expect(err).ToNot(HaveOccurred())
})
It("runs with options if given", func() {
err := utils.CreateSquashFS(runner, logger, "source", "dest", constants.GetDefaultSquashfsOptions())
cmd := []string{"mksquashfs", "source", "dest"}
cmd = append(cmd, constants.GetDefaultSquashfsOptions()...)
Expect(runner.IncludesCmds([][]string{
cmd,
})).To(BeNil())
Expect(err).ToNot(HaveOccurred())
})
It("returns an error if it fails", func() {
runner.ReturnError = errors.New("error")
err := utils.CreateSquashFS(runner, logger, "source", "dest", []string{})
Expect(runner.IncludesCmds([][]string{
{"mksquashfs", "source", "dest"},
})).To(BeNil())
Expect(err).To(HaveOccurred())
})
})
})

7
tools-image/ipxe.tmpl Normal file
View File

@@ -0,0 +1,7 @@
#!ipxe
set dns 8.8.8.8
ifconf
kernel ${RELEASE_URL}/${VERSION}/${ISO_NAME}-kernel root=live:${RELEASE_URL}/${VERSION}/${ISO_NAME}.squashfs initrd=${ISO_NAME}-initrd rd.neednet=1 ip=dhcp rd.cos.disable netboot install-mode config_url=${config} console=tty1 console=ttyS0 rd.live.overlay.overlayfs ${cmdline}
initrd ${RELEASE_URL}/${VERSION}/${ISO_NAME}-initrd
boot

View File

@@ -0,0 +1,15 @@
general:
debug: false
spinner_charset: 9
logging:
enable_emoji: false
repositories:
- name: "kairos"
description: "kairos repository"
type: "docker"
cached: true
enable: true
priority: 2
urls:
- "quay.io/kairos/packages"
reference: 20240202131847-repository.yaml

View File

@@ -12,4 +12,4 @@ repositories:
priority: 2
urls:
- "quay.io/kairos/packages"
reference: 20230727165842-repository.yaml
reference: 20240207153537-repository.yaml

View File

@@ -0,0 +1,15 @@
general:
debug: false
spinner_charset: 9
logging:
enable_emoji: false
repositories:
- name: "kairos-arm64"
description: "kairos repository arm64"
type: "docker"
cached: true
enable: true
priority: 2
urls:
- "quay.io/kairos/packages-arm64"
reference: 20240202135656-repository.yaml

View File

@@ -12,4 +12,4 @@ repositories:
priority: 2
urls:
- "quay.io/kairos/packages-arm64"
reference: 20230727170327-repository.yaml
reference: 20240207154912-repository.yaml

View File

@@ -19,7 +19,7 @@ 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}
kernel \${url}/\${kernel} initrd=\${initrd} ip=dhcp rd.cos.disable root=live:\${url}/\${rootfs} netboot install-mode config_url=\${config} console=tty1 console=ttyS0 \${cmdline}
initrd \${url}/\${initrd}
boot
EOF

View File

@@ -38,7 +38,7 @@ 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 /efi/* $WORKDIR/tmpefi
cp -rfv /arm/raw/grubefi/* $WORKDIR/tmpefi
mkfs.fat -F16 -n COS_GRUB bootloader/efi.img
mcopy -s -i bootloader/efi.img $WORKDIR/tmpefi/EFI ::EFI