mirror of
https://github.com/kairos-io/osbuilder.git
synced 2025-09-08 02:30:30 +00:00
create cluster ISO image
This commit is contained in:
25
.github/workflows/lint.yml
vendored
25
.github/workflows/lint.yml
vendored
@@ -3,19 +3,16 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- '**'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: lint-${{ github.ref || github.head_ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
FORCE_COLOR: 1
|
|
||||||
jobs:
|
jobs:
|
||||||
call-workflow:
|
lint:
|
||||||
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.10
|
name: Lint
|
||||||
with:
|
runs-on: ubuntu-latest
|
||||||
yamldirs: ".github/workflows/ config/"
|
steps:
|
||||||
is-go: true
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- name: golangci-lint
|
||||||
|
uses: golangci/golangci-lint-action@v6
|
||||||
|
|
||||||
|
32
.github/workflows/test.yml
vendored
32
.github/workflows/test.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
name: 'test'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: test-${{ github.ref || github.head_ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
e2e-tests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
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
|
|
@@ -28,6 +28,8 @@ spec:
|
|||||||
image: '{{ .Values.builder.image.repository | default "ghcr.io/pluralsh/osbuilder" }}:{{ .Values.builder.image.tag | default .Chart.AppVersion }}'
|
image: '{{ .Values.builder.image.repository | default "ghcr.io/pluralsh/osbuilder" }}:{{ .Values.builder.image.tag | default .Chart.AppVersion }}'
|
||||||
command: [ '/manager' ]
|
command: [ '/manager' ]
|
||||||
args:
|
args:
|
||||||
|
- --console-url={{ .Values.builder.consoleUrl }}
|
||||||
|
- --console-token={{ .Values.builder.consoleToken }}
|
||||||
- --pvc-storage-size={{ .Values.builder.pvcStorageSize }}
|
- --pvc-storage-size={{ .Values.builder.pvcStorageSize }}
|
||||||
- --health-probe-bind-address=:8081
|
- --health-probe-bind-address=:8081
|
||||||
- --metrics-bind-address=127.0.0.1:8080
|
- --metrics-bind-address=127.0.0.1:8080
|
||||||
|
@@ -16,6 +16,9 @@ builder:
|
|||||||
tag: ~
|
tag: ~
|
||||||
|
|
||||||
replicas: 1
|
replicas: 1
|
||||||
|
consoleUrl: ""
|
||||||
|
consoleToken: ""
|
||||||
|
|
||||||
|
|
||||||
# The PVC storage size for the build process
|
# The PVC storage size for the build process
|
||||||
pvcStorageSize: "30Gi"
|
pvcStorageSize: "30Gi"
|
||||||
|
@@ -21,13 +21,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
||||||
|
consoleclient "github.com/kairos-io/osbuilder/pkg/client"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
console "github.com/pluralsh/console/go/client"
|
||||||
|
|
||||||
batchv1 "k8s.io/api/batch/v1"
|
batchv1 "k8s.io/api/batch/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -40,8 +41,6 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
|
|
||||||
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -60,6 +59,7 @@ var (
|
|||||||
// OSArtifactReconciler reconciles a OSArtifact object
|
// OSArtifactReconciler reconciles a OSArtifact object
|
||||||
type OSArtifactReconciler struct {
|
type OSArtifactReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
|
ConsoleClient consoleclient.Client
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
ServingImage, ToolImage, CopierImage, PVCStorage string
|
ServingImage, ToolImage, CopierImage, PVCStorage string
|
||||||
}
|
}
|
||||||
@@ -404,8 +404,18 @@ func (r *OSArtifactReconciler) checkExport(ctx context.Context, artifact *osbuil
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if job.Spec.Completions != nil {
|
} else if job.Spec.Completions != nil {
|
||||||
if job.Status.Succeeded > 0 {
|
if job.Status.Succeeded > 0 && artifact.Status.Phase == osbuilder.Exporting {
|
||||||
artifact.Status.Phase = osbuilder.Ready
|
artifact.Status.Phase = osbuilder.Ready
|
||||||
|
if err := r.upsertClusterIsoImage(artifact); err != nil {
|
||||||
|
artifact.Status.Phase = osbuilder.Error
|
||||||
|
meta.SetStatusCondition(&artifact.Status.Conditions, metav1.Condition{
|
||||||
|
Type: "Ready",
|
||||||
|
Status: metav1.ConditionFalse,
|
||||||
|
Reason: "Error",
|
||||||
|
Message: consoleclient.GetErrorResponse(err, "CreateClusterIsoImage").Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if err := TryToUpdateStatus(ctx, r.Client, artifact); err != nil {
|
if err := TryToUpdateStatus(ctx, r.Client, artifact); err != nil {
|
||||||
log.FromContext(ctx).Error(err, "failed to update artifact status")
|
log.FromContext(ctx).Error(err, "failed to update artifact status")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
@@ -434,6 +444,27 @@ func (r *OSArtifactReconciler) checkExport(ctx context.Context, artifact *osbuil
|
|||||||
return requeue, nil
|
return requeue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *OSArtifactReconciler) upsertClusterIsoImage(artifact *osbuilder.OSArtifact) error {
|
||||||
|
image := fmt.Sprintf("%s:%s", artifact.Spec.Exporter.Registry.Image.Repository, artifact.Spec.Exporter.Registry.Image.Tag)
|
||||||
|
attr := console.ClusterIsoImageAttributes{
|
||||||
|
Image: image,
|
||||||
|
Registry: artifact.Spec.Exporter.Registry.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponse, err := r.ConsoleClient.GetClusterIsoImage(&image)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
_, err := r.ConsoleClient.CreateClusterIsoImage(attr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := r.ConsoleClient.UpdateClusterIsoImage(getResponse.ID, attr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *OSArtifactReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *OSArtifactReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
|
7
go.mod
7
go.mod
@@ -3,6 +3,9 @@ module github.com/kairos-io/osbuilder
|
|||||||
go 1.23.4
|
go 1.23.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Yamashou/gqlgenc v0.23.2
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/pluralsh/console/go/client v1.28.3
|
||||||
k8s.io/api v0.32.1
|
k8s.io/api v0.32.1
|
||||||
k8s.io/apimachinery v0.32.1
|
k8s.io/apimachinery v0.32.1
|
||||||
k8s.io/client-go v0.32.1
|
k8s.io/client-go v0.32.1
|
||||||
@@ -11,6 +14,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/99designs/gqlgen v0.17.49 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
@@ -39,12 +43,13 @@ require (
|
|||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
|
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
|
||||||
github.com/onsi/gomega v1.36.2 // indirect
|
github.com/onsi/gomega v1.36.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.55.0 // indirect
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/sosodev/duration v1.3.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.16 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
|
14
go.sum
14
go.sum
@@ -1,3 +1,9 @@
|
|||||||
|
github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ=
|
||||||
|
github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0=
|
||||||
|
github.com/Yamashou/gqlgenc v0.23.2 h1:WPxYPrwc6W4Z1eY4qKxoH3nb5PC4jAMWqQA0G8toQMI=
|
||||||
|
github.com/Yamashou/gqlgenc v0.23.2/go.mod h1:oMc4EQBQeDwLIODvgcvpaSp6rO+KMf47FuOhplv5D3A=
|
||||||
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||||
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
@@ -77,6 +83,8 @@ github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
|||||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pluralsh/console/go/client v1.28.3 h1:KyHpOoVHhMRMAZp99k7LqZqX6+FrOwy9sGVXaDSi9FA=
|
||||||
|
github.com/pluralsh/console/go/client v1.28.3/go.mod h1:lpoWASYsM9keNePS3dpFiEisUHEfObIVlSL3tzpKn8k=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
@@ -90,6 +98,10 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
|
|||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
|
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
|
||||||
|
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
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/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -101,6 +113,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
23
main.go
23
main.go
@@ -20,6 +20,8 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
consoleclient "github.com/kairos-io/osbuilder/pkg/client"
|
||||||
|
"github.com/kairos-io/osbuilder/pkg/helpers"
|
||||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||||
|
|
||||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||||
@@ -43,6 +45,8 @@ var (
|
|||||||
setupLog = ctrl.Log.WithName("setup")
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const EnvConsoleToken = "CONSOLE_TOKEN"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
|
||||||
@@ -55,6 +59,10 @@ func main() {
|
|||||||
var enableLeaderElection bool
|
var enableLeaderElection bool
|
||||||
var probeAddr string
|
var probeAddr string
|
||||||
var serveImage, toolImage, copierImage, pvcStorage string
|
var serveImage, toolImage, copierImage, pvcStorage string
|
||||||
|
var consoleUrl, consoleToken string
|
||||||
|
|
||||||
|
flag.StringVar(&consoleUrl, "console-url", "", "The URL of the console api to fetch services from.")
|
||||||
|
flag.StringVar(&consoleToken, "console-token", helpers.GetEnv(EnvConsoleToken, ""), "The deploy token to auth to Console API with.")
|
||||||
|
|
||||||
flag.StringVar(&pvcStorage, "pvc-storage-size", "20Gi", "The PVC storage size for building process")
|
flag.StringVar(&pvcStorage, "pvc-storage-size", "20Gi", "The PVC storage size for building process")
|
||||||
|
|
||||||
@@ -75,6 +83,8 @@ func main() {
|
|||||||
|
|
||||||
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||||
|
|
||||||
|
extConsoleClient := consoleclient.New(consoleUrl, consoleToken)
|
||||||
|
|
||||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||||
Scheme: scheme,
|
Scheme: scheme,
|
||||||
Metrics: metricsserver.Options{BindAddress: metricsAddr},
|
Metrics: metricsserver.Options{BindAddress: metricsAddr},
|
||||||
@@ -99,12 +109,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = (&controllers.OSArtifactReconciler{
|
if err = (&controllers.OSArtifactReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
ServingImage: serveImage,
|
ServingImage: serveImage,
|
||||||
ToolImage: toolImage,
|
ToolImage: toolImage,
|
||||||
CopierImage: copierImage,
|
CopierImage: copierImage,
|
||||||
PVCStorage: pvcStorage,
|
PVCStorage: pvcStorage,
|
||||||
|
ConsoleClient: extConsoleClient,
|
||||||
}).SetupWithManager(mgr); err != nil {
|
}).SetupWithManager(mgr); err != nil {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
|
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
108
pkg/client/console.go
Normal file
108
pkg/client/console.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
rawclient "github.com/Yamashou/gqlgenc/clientv2"
|
||||||
|
internalerror "github.com/kairos-io/osbuilder/pkg/errors"
|
||||||
|
"github.com/kairos-io/osbuilder/pkg/helpers"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
console "github.com/pluralsh/console/go/client"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
ctx context.Context
|
||||||
|
consoleClient console.ConsoleClient
|
||||||
|
url string
|
||||||
|
token string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(url, token string) Client {
|
||||||
|
return &client{
|
||||||
|
consoleClient: console.NewClient(&http.Client{
|
||||||
|
Transport: helpers.NewAuthorizationTokenTransport(token),
|
||||||
|
}, url, nil),
|
||||||
|
ctx: context.Background(),
|
||||||
|
url: url,
|
||||||
|
token: token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
CreateClusterIsoImage(attributes console.ClusterIsoImageAttributes) (*console.ClusterIsoImageFragment, error)
|
||||||
|
UpdateClusterIsoImage(id string, attributes console.ClusterIsoImageAttributes) (*console.ClusterIsoImageFragment, error)
|
||||||
|
GetClusterIsoImage(image *string) (*console.ClusterIsoImageFragment, error)
|
||||||
|
DeleteClusterIsoImage(id string) (*console.ClusterIsoImageFragment, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) CreateClusterIsoImage(attributes console.ClusterIsoImageAttributes) (*console.ClusterIsoImageFragment, error) {
|
||||||
|
response, err := c.consoleClient.CreateClusterIsoImage(c.ctx, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.CreateClusterIsoImage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) DeleteClusterIsoImage(id string) (*console.ClusterIsoImageFragment, error) {
|
||||||
|
response, err := c.consoleClient.DeleteClusterIsoImage(c.ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.DeleteClusterIsoImage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) UpdateClusterIsoImage(id string, attributes console.ClusterIsoImageAttributes) (*console.ClusterIsoImageFragment, error) {
|
||||||
|
response, err := c.consoleClient.UpdateClusterIsoImage(c.ctx, id, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.UpdateClusterIsoImage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) GetClusterIsoImage(image *string) (*console.ClusterIsoImageFragment, error) {
|
||||||
|
response, err := c.consoleClient.GetClusterIsoImage(c.ctx, nil, image)
|
||||||
|
if internalerror.IsNotFound(err) {
|
||||||
|
return nil, apierrors.NewNotFound(schema.GroupResource{}, *image)
|
||||||
|
}
|
||||||
|
if err == nil && (response == nil || response.ClusterIsoImage == nil) {
|
||||||
|
return nil, apierrors.NewNotFound(schema.GroupResource{}, *image)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.ClusterIsoImage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetErrorResponse(err error, methodName string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
errResponse := &rawclient.ErrorResponse{}
|
||||||
|
newErr := json.Unmarshal([]byte(err.Error()), errResponse)
|
||||||
|
if newErr != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
errList := errors.New(methodName)
|
||||||
|
if errResponse.GqlErrors != nil {
|
||||||
|
for _, err := range *errResponse.GqlErrors {
|
||||||
|
errList = errors.Wrap(errList, err.Message)
|
||||||
|
}
|
||||||
|
errList = errors.Wrap(errList, "GraphQL error")
|
||||||
|
}
|
||||||
|
if errResponse.NetworkError != nil {
|
||||||
|
errList = errors.Wrap(errList, errResponse.NetworkError.Message)
|
||||||
|
errList = errors.Wrap(errList, "Network error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return errList
|
||||||
|
}
|
59
pkg/errors/base.go
Normal file
59
pkg/errors/base.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
client "github.com/Yamashou/gqlgenc/clientv2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KnownError string
|
||||||
|
|
||||||
|
func (k KnownError) String() string {
|
||||||
|
return string(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k KnownError) Error() string {
|
||||||
|
return string(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrorNotFound KnownError = "could not find resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wrappedErrorResponse struct {
|
||||||
|
err *client.ErrorResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func (er *wrappedErrorResponse) Has(err KnownError) bool {
|
||||||
|
if er.err.GqlErrors == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range *er.err.GqlErrors {
|
||||||
|
if g.Message == string(err) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAPIError(err *client.ErrorResponse) *wrappedErrorResponse {
|
||||||
|
return &wrappedErrorResponse{
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNotFound(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
errorResponse := new(client.ErrorResponse)
|
||||||
|
ok := errors.As(err, &errorResponse)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAPIError(errorResponse).Has(ErrorNotFound)
|
||||||
|
}
|
14
pkg/helpers/env.go
Normal file
14
pkg/helpers/env.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEnv - Lookup the environment variable provided and set to default value if variable isn't found
|
||||||
|
func GetEnv(key, fallback string) string {
|
||||||
|
if value := os.Getenv(key); len(value) > 0 {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback
|
||||||
|
}
|
33
pkg/helpers/http.go
Normal file
33
pkg/helpers/http.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthorizationTokenTransport struct {
|
||||||
|
token string
|
||||||
|
transport http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in *AuthorizationTokenTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("Authorization", "Token "+in.token)
|
||||||
|
return in.transport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthorizationTokenTransport(token string) http.RoundTripper {
|
||||||
|
return &AuthorizationTokenTransport{token: token, transport: http.DefaultTransport}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthorizationBearerTransport struct {
|
||||||
|
token string
|
||||||
|
transport http.RoundTripper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (in *AuthorizationBearerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+in.token)
|
||||||
|
return in.transport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthorizationBearerTransport(token string) http.RoundTripper {
|
||||||
|
return &AuthorizationBearerTransport{token: token, transport: http.DefaultTransport}
|
||||||
|
}
|
Reference in New Issue
Block a user