@@ -4,15 +4,86 @@ import { knative } from "~/lib/k8s";
44import { EnvVarsInput } from "../EnvVarsInput" ;
55import { ScalingInput } from "../ScalingInput" ;
66import { ResourcesInput } from "../ResourcesInput" ;
7- import { getUser } from "~/lib/auth" ;
7+ import { getUser , getAccount } from "~/lib/auth" ;
88import type { Service } from "~/lib/knative" ;
99import { toNumber } from "~/lib/knative" ;
10+ import { SourceInput } from "./service/SourceInput" ;
11+ import { k8sCore } from "~/lib/k8s" ;
12+ import { Octokit } from "@octokit/rest" ;
13+ import * as crypto from "crypto" ;
14+ import { config } from "~/lib/config" ;
15+
16+ const ensureGithubPullSecret = async ( namespace : string ) => {
17+ "use server" ;
18+ const secretName = "pull-secret-ghcr" ;
19+ try {
20+ await k8sCore . readNamespacedSecret ( secretName , namespace ) ;
21+ } catch ( e ) {
22+ const user = await getUser ( ) ;
23+ const accout = await getAccount ( ) ;
24+
25+ const username = user . name ;
26+ const token = accout . access_token ;
27+ const email = user . email ;
28+
29+ await k8sCore . createNamespacedSecret ( namespace , {
30+ apiVersion : "v1" ,
31+ kind : "Secret" ,
32+ metadata : {
33+ name : secretName ,
34+ labels : {
35+ "app.kubernetes.io/managed-by" : "deploycat" ,
36+ } ,
37+ } ,
38+ type : "kubernetes.io/dockerconfigjson" ,
39+ data : {
40+ ".dockerconfigjson" : Buffer . from (
41+ JSON . stringify ( {
42+ auths : {
43+ "ghcr.io" : {
44+ username : username ,
45+ password : token ,
46+ email : email ,
47+ auth : Buffer . from ( `${ username } :${ token } ` ) . toString ( "base64" ) ,
48+ } ,
49+ } ,
50+ } )
51+ ) . toString ( "base64" ) ,
52+ } ,
53+ } ) ;
54+ }
55+ } ;
56+
57+ const createGithubWebhook = async ( namespace : string , service ) => {
58+ "use server" ;
59+ const account = await getAccount ( ) ;
60+ const ok = new Octokit ( {
61+ auth : account . access_token ,
62+ } ) ;
63+ ok . repos . createWebhook ( {
64+ owner : service . ghPackageOwner ,
65+ repo : service . ghPackageRepo ,
66+ config : {
67+ url : `${ config ?. publicurl } /api/webhooks/github/apps/${ namespace } /${ service . name } /package` ,
68+ content_type : "json" ,
69+ secret : service . webhookSecret ,
70+ } ,
71+ events : [ "package" ] ,
72+ active : true ,
73+ } ) ;
74+ } ;
1075
1176const createServiceFromForm = async ( form : FormData ) => {
1277 "use server" ;
1378 const service = {
1479 name : form . get ( "name" ) as string ,
80+ source : form . get ( "source" ) as string ,
1581 image : form . get ( "image" ) as string ,
82+ ghPackage : form . get ( "ghPackage" ) as string ,
83+ ghPackageTag : form . get ( "ghPackageTag" ) as string ,
84+ ghPackageName : form . get ( "ghPackageName" ) as string ,
85+ ghPackageOwner : form . get ( "ghPackageOwner" ) as string ,
86+ ghPackageRepo : form . get ( "ghPackageRepo" ) as string ,
1687 port : Number ( form . get ( "port" ) ) as number ,
1788 resources : {
1889 cpuLimit : toNumber ( form . get ( "cpuLimit" ) ) ,
@@ -24,8 +95,24 @@ const createServiceFromForm = async (form: FormData) => {
2495 } ,
2596 envVars : JSON . parse ( form . get ( "env" ) as string ) as { [ key : string ] : string } ,
2697 } as Service ;
98+
2799 const user = await getUser ( ) ;
28- await knative . createService ( service , user . name ) ;
100+ if ( service ?. source === "ghcr" ) {
101+ try {
102+ service . webhookSecret = crypto . randomBytes ( 16 ) . toString ( "hex" ) ;
103+ await ensureGithubPullSecret ( user . name ) ;
104+ await createGithubWebhook ( user . name , service ) ;
105+ } catch ( e ) {
106+ console . error ( e ) ;
107+ }
108+ service . image = `ghcr.io/${ service . ghPackageOwner } /${ service . ghPackageName } :${ service . ghPackageTag } ` ;
109+ service . pullSecret = "pull-secret-ghcr" ;
110+ }
111+ try {
112+ await knative . createService ( service , user . name , service . source ) ;
113+ } catch ( e ) {
114+ console . error ( e ) ;
115+ }
29116} ;
30117
31118const createServiceAction = action ( createServiceFromForm , "createService" ) ;
@@ -54,18 +141,8 @@ export const CreateServiceForm = () => {
54141 class = "input input-bordered w-full"
55142 />
56143 </ label >
57- < label class = "form-control w-full" >
58- < div class = "label" >
59- < span class = "label-text" > Image</ span >
60- </ div >
61- < input
62- type = "text"
63- name = "image"
64- required
65- placeholder = "traefik/whoami"
66- class = "input input-bordered w-full"
67- />
68- </ label >
144+ < SourceInput />
145+
69146 < label class = "form-control w-full" >
70147 < div class = "label" >
71148 < span class = "label-text" > Port</ span >
0 commit comments