diff --git a/client/src/components/apps/form.vue b/client/src/components/apps/form.vue index 69a3bf1af..c6c5787af 100644 --- a/client/src/components/apps/form.vue +++ b/client/src/components/apps/form.vue @@ -1409,6 +1409,8 @@ export default defineComponent({ provider: '', repository: {} as GitRepo, }, + buildstrategy: 'plain', + deploymentstrategy: 'git', }, appname: '', resourceVersion: '', @@ -1754,6 +1756,8 @@ export default defineComponent({ this.loadBranches(); this.buildpack = this.pipelineData.buildpack; + this.buildstrategy = this.pipelineData.buildstrategy; + this.deploymentstrategy = this.pipelineData.deploymentstrategy; if (this.app == 'new') { this.ingress.hosts[0].host = this.pipelineData.domain; diff --git a/client/src/components/pipelines/form.vue b/client/src/components/pipelines/form.vue index 4b53256dd..184fce898 100644 --- a/client/src/components/pipelines/form.vue +++ b/client/src/components/pipelines/form.vue @@ -51,105 +51,241 @@ > - - - - mdi-githubGithub - Gitea - mdi-gitlabGitlab - - Gogs - mdi-bitbucketBitbucket - - - + + Deployment + + + + + mdi-githubGithub + Gitea + mdi-gitlabGitlab + + Gogs + mdi-bitbucketBitbucket + + + - - - - - - - - {{repository_status.statusTxt}} - - Connect - - + + + + + - - - Webhook created + + + + + + + + + + + + + +

+ Runpacks +

+
Your code is build and running on official images. The code will be built for every pod in a init container. This is the fastes way, to run your code, but becomes more inefficient with every replica.
- Deploy keys added + + +

+ Nixpacks +

+
+ Nixpacks is a open source project to build docker images with nix. It is a good way to build images without a Dockerfile, if you want to have a reproducable build process. +
-
-
- - - - - + +

+ Buildpacks +

+
+ Buildpacks are a set of scripts and binaries used to transform application source code into a deployable image, automating the process of compiling, building, and configuring the app for deployment. +
+
+ + +

+ Dockerfile +

+
Builds the image based on the Dockerfile in your git root directory. This allows for the highest level of customization.
+
+ + +

+ External CI/CD +

+
You are building your image on a external CI/CD and deploy it by changing the image tag thrue the API
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Webhook created + + Deploy keys added + + + + + + + + {{repository_status.statusTxt}} + + Connect + + +
+
+ + + Phases @@ -271,6 +407,13 @@ export default defineComponent({ gitops: false, dockerimage: '', deploymentstrategy: "git", + buildstrategy: "plain", + dockerfilepath: '/', + registry: { + host: 'https://', + username: '', + password: '', + }, newPipeline: true, resourceVersion: undefined, repotab: 'github', //selected tab @@ -349,8 +492,8 @@ export default defineComponent({ (v: any) => v !== 'new' || 'Name cannot be "new"', ], domainRules: [ - (v: any) => v.length <= 253 || 'Name must be less than 253 characters', - (v: any) => /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/.test(v) || 'Not a domain', + //(v: any) => v.length <= 253 || 'Name must be less than 253 characters', + (v: any) => /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$|^localhost$|^$/.test(v) || 'Not a domain', ], repositoryRules: [ (v: any) => !!v || 'Repository is required', @@ -367,6 +510,7 @@ export default defineComponent({ mounted() { this.getContextList(); this.listRepositories(); + this.loadDefaultregistry(); this.listBuildpacks(); this.loadRepository(); this.loadPipeline(); @@ -465,6 +609,23 @@ export default defineComponent({ }); }, + loadDefaultregistry() { + if (this.pipeline === 'new') { + axios.get(`/api/config/registry`) + .then(response => { + if (response.data.host && response.data.account.username && response.data.account.password) { + this.registry ={ + host: 'https://'+response.data.host, + username: response.data.account.username, + password: response.data.account.password, + } + } + }).catch(error => { + console.log(error); + }); + } + }, + connectRepository(repo: string) { axios.post(`/api/repo/${repo}/connect`, { gitrepo: this.gitrepo @@ -535,6 +696,8 @@ export default defineComponent({ this.phases = p.phases; this.reviewapps = p.reviewapps; this.git = p.git; + this.registry = p.registry || this.registry; + this.buildstrategy = p.buildstrategy || this.buildstrategy; this.dockerimage = p.dockerimage; this.deploymentstrategy = p.deploymentstrategy; this.buildpack = p.buildpack; @@ -572,8 +735,10 @@ export default defineComponent({ phases: this.phases, reviewapps: this.reviewapps, git: this.git, + registry: this.registry, dockerimage: '', - deploymentstrategy: "git", // DEPRECATED + deploymentstrategy: this.deploymentstrategy, + buildstrategy: this.buildstrategy, buildpack: this.buildpack, }) .then(response => { @@ -594,8 +759,10 @@ export default defineComponent({ phases: this.phases, reviewapps: this.reviewapps, git: this.git, + registry: this.registry, dockerimage: '', - deploymentstrategy: "git", // DEPRECATED + deploymentstrategy: this.deploymentstrategy, + buildstrategy: this.buildstrategy, buildpack: this.buildpack, }) .then(response => { diff --git a/client/src/layouts/default/NavDrawer.vue b/client/src/layouts/default/NavDrawer.vue index 2e97e832d..183af53a0 100644 --- a/client/src/layouts/default/NavDrawer.vue +++ b/client/src/layouts/default/NavDrawer.vue @@ -92,6 +92,8 @@ --> diff --git a/server/src/kubero.ts b/server/src/kubero.ts index 7ebe74e3e..2a3980490 100644 --- a/server/src/kubero.ts +++ b/server/src/kubero.ts @@ -1263,10 +1263,15 @@ export class Kubero { } else { debug.log('no git repo found to run scan'); } + } else if (app?.spec?.deploymentstrategy === 'git' && app?.spec?.buildstrategy != 'plain') { + if (contextName) { + this.kubectl.setCurrentContext(contextName); + this.kubectl.createScanImageJob(namespace, appName, app.spec.image.repository, app.spec.image.tag, true); + } } else { if (contextName) { this.kubectl.setCurrentContext(contextName); - this.kubectl.createScanImageJob(namespace, appName, app.spec.image.repository, app.spec.image.tag); + this.kubectl.createScanImageJob(namespace, appName, app.spec.image.repository, app.spec.image.tag, false); } } diff --git a/server/src/modules/kubectl.ts b/server/src/modules/kubectl.ts index 13d85db16..8b9c18f0b 100644 --- a/server/src/modules/kubectl.ts +++ b/server/src/modules/kubectl.ts @@ -746,9 +746,9 @@ export class Kubectl { } } - public async createScanImageJob(namespace: string, app: string, image: string, tag: string): Promise { + public async createScanImageJob(namespace: string, app: string, image: string, tag: string, withCredentials: boolean): Promise { await this.deleteScanJob(namespace, app+'-kuberoapp-vuln'); - const job = { + let job = { apiVersion: 'batch/v1', kind: 'Job', metadata: { @@ -788,34 +788,39 @@ export class Kubectl { "--exit-code", "0" ], - env: [ - { - name: 'TRIVY_USERNAME', - valueFrom: { - secretKeyRef: { - name: 'registry-credentials', - key: 'username', - optional: true - } - } - }, - { - name: 'TRIVY_PASSWORD', - valueFrom: { - secretKeyRef: { - name: 'registry-credentials', - key: 'password', - optional: true - } - } - } - ], + env: [] as { name: string; valueFrom: { secretKeyRef: { name: string; key: string; optional: true; }; }; }[], } ] } } } }; + + if (withCredentials) { + job.spec.template.spec.containers[0].env = [ + { + name: 'TRIVY_USERNAME', + valueFrom: { + secretKeyRef: { + name: 'registry-credentials', + key: 'username', + optional: true + } + } + }, + { + name: 'TRIVY_PASSWORD', + valueFrom: { + secretKeyRef: { + name: 'registry-credentials', + key: 'password', + optional: true + } + } + } + ] + } + try { return await this.batchV1Api.createNamespacedJob(namespace, job); } catch (error) { diff --git a/server/src/modules/pipeline.ts b/server/src/modules/pipeline.ts index 9fc260c09..634e80c39 100644 --- a/server/src/modules/pipeline.ts +++ b/server/src/modules/pipeline.ts @@ -1,4 +1,4 @@ -import { IBuildpack , IPipeline, IPipelinePhase, IKubectlPipeline, IKubectlMetadata, IgitLink, IGithubRepository} from '../types'; +import { IBuildpack , IPipeline, IPipelinePhase, IKubectlPipeline, IKubectlMetadata, IgitLink, IGithubRepository, IRegistry} from '../types'; export class Pipeline implements IPipeline { public name: string; @@ -8,7 +8,9 @@ export class Pipeline implements IPipeline { public phases: IPipelinePhase[]; public buildpack: IBuildpack; public deploymentstrategy: 'git' | 'docker'; + public buildstrategy : 'plain' | 'dockerfile' | 'nixpacks' | 'buildpacks'; public git: IgitLink; + public registry: IRegistry; constructor( pl: IPipeline, @@ -19,8 +21,10 @@ export class Pipeline implements IPipeline { this.phases = pl.phases; this.buildpack = pl.buildpack; this.dockerimage = pl.dockerimage; - this.git = pl.git; this.deploymentstrategy = pl.deploymentstrategy; + this.buildstrategy = pl.buildstrategy; + this.git = pl.git; + this.registry = pl.registry; } } diff --git a/server/src/modules/settings.ts b/server/src/modules/settings.ts index b0212c6b1..19a904d25 100644 --- a/server/src/modules/settings.ts +++ b/server/src/modules/settings.ts @@ -175,6 +175,13 @@ export class Settings { }); } + public async getDefaultRegistry(): Promise { + const namespace = process.env.KUBERO_NAMESPACE || "kubero" + let kuberoes = await this.kubectl.getKuberoConfig(namespace) + + return kuberoes.spec.registry + } + public async getDomains(): Promise { let allIngress = await this.kubectl.getAllIngress() let domains: string[] = [] diff --git a/server/src/routes/config.ts b/server/src/routes/config.ts index 07de52342..15a7a4cb5 100644 --- a/server/src/routes/config.ts +++ b/server/src/routes/config.ts @@ -60,6 +60,12 @@ Router.get('/config/buildpacks', authMiddleware, async function (req: Request, r res.send(await req.app.locals.kubero.getBuildpacks()); }); +Router.get('/config/registry', authMiddleware, async function (req: Request, res: Response) { + // #swagger.tags = ['UI'] + // #swagger.summary = 'Get the default registry list' + res.send(await req.app.locals.settings.getDefaultRegistry()); +}); + Router.get('/cli/config/k8s/context', bearerMiddleware, async function (req: Request, res: Response) { // #swagger.tags = ['Config'] diff --git a/server/src/routes/pipelines.ts b/server/src/routes/pipelines.ts index 5385d7099..8e0c10e5b 100644 --- a/server/src/routes/pipelines.ts +++ b/server/src/routes/pipelines.ts @@ -61,9 +61,11 @@ Router.post('/cli/pipelines',bearerMiddleware, async function (req: Request, res phases: req.body.phases, buildpack: selectedBuildpack, reviewapps: req.body.reviewapps, - git: git, dockerimage: req.body.dockerimage, + git: git, + registry: req.body.registry, deploymentstrategy: req.body.deploymentstrategy, + buildstrategy: req.body.buildstrategy, }; const user = auth.getUser(req); req.app.locals.kubero.newPipeline(pipeline, user); @@ -80,10 +82,12 @@ Router.post('/pipelines',authMiddleware, async function (req: Request, res: Resp domain: req.body.domain, phases: req.body.phases, buildpack: req.body.buildpack, + dockerimage: req.body.dockerimage, reviewapps: req.body.reviewapps, git: req.body.git, - dockerimage: req.body.dockerimage, + registry: req.body.registry, deploymentstrategy: req.body.deploymentstrategy, + buildstrategy: req.body.buildstrategy, }; req.app.locals.kubero.newPipeline(pipeline, user); res.send("new"); @@ -101,9 +105,11 @@ Router.put('/pipelines/:pipeline',authMiddleware, async function (req: Request, phases: req.body.phases, buildpack: req.body.buildpack, reviewapps: req.body.reviewapps, - git: req.body.git, dockerimage: req.body.dockerimage, + git: req.body.git, + registry: req.body.registry, deploymentstrategy: req.body.deploymentstrategy, + buildstrategy: req.body.buildstrategy, }; req.app.locals.kubero.updatePipeline(pipeline, req.body.resourceVersion, user); res.send("new"); diff --git a/server/src/types.ts b/server/src/types.ts index 52a467682..f7c2cf4ed 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -199,11 +199,19 @@ export interface IPipeline { phases: IPipelinePhase[]; buildpack: IBuildpack git: IgitLink; + registry: IRegistry; dockerimage: string; deploymentstrategy: 'git' | 'docker', + buildstrategy: 'plain' | 'dockerfile' | 'nixpacks' | 'buildpacks', resourceVersion?: string; // required to update resource, not part of spec } +export interface IRegistry { + host: string; + username: string; + password: string; +} + export interface IgitLink { keys: { priv?: string,