@@ -23,7 +23,14 @@ func preInitJobName(node *seiv1alpha1.SeiNode) string {
2323
2424func generatePreInitJob (node * seiv1alpha1.SeiNode , platform PlatformConfig ) * batchv1.Job {
2525 labels := preInitLabelsForNode (node )
26- snap := snapshotSourceFor (node )
26+
27+ var podSpec corev1.PodSpec
28+ if isGenesisCeremonyNode (node ) {
29+ podSpec = buildGenesisPreInitPodSpec (node , platform )
30+ } else {
31+ snap := snapshotSourceFor (node )
32+ podSpec = buildPreInitPodSpec (node , snap , platform )
33+ }
2734
2835 return & batchv1.Job {
2936 ObjectMeta : metav1.ObjectMeta {
@@ -41,7 +48,7 @@ func generatePreInitJob(node *seiv1alpha1.SeiNode, platform PlatformConfig) *bat
4148 "karpenter.sh/do-not-disrupt" : "true" ,
4249 },
4350 },
44- Spec : buildPreInitPodSpec ( node , snap , platform ) ,
51+ Spec : podSpec ,
4552 },
4653 },
4754 }
@@ -72,8 +79,15 @@ func generatePreInitService(node *seiv1alpha1.SeiNode) *corev1.Service {
7279
7380// preInitSidecarURL returns the in-cluster DNS URL for the pre-init Job's sidecar.
7481func preInitSidecarURL (node * seiv1alpha1.SeiNode ) string {
82+ return PreInitSidecarURL (node .Name , node .Namespace , sidecarPort (node ))
83+ }
84+
85+ // PreInitSidecarURL builds the in-cluster DNS URL for a pre-init Job's sidecar
86+ // given the node name, namespace, and port. Exported for use by the group controller.
87+ func PreInitSidecarURL (nodeName , namespace string , port int32 ) string {
88+ jobName := fmt .Sprintf ("%s-pre-init" , nodeName )
7589 return fmt .Sprintf ("http://%s.%s.%s.svc.cluster.local:%d" ,
76- preInitPodHostname , preInitJobName ( node ), node . Namespace , sidecarPort ( node ) )
90+ preInitPodHostname , jobName , namespace , port )
7791}
7892
7993// preInitWaitCommand returns a shell command that waits for the sidecar
@@ -99,6 +113,78 @@ func preInitWaitCommand(port int32, haltHeight int64) (command []string, args []
99113 return []string {"/bin/bash" , "-c" }, []string {script }
100114}
101115
116+ // buildGenesisPreInitPodSpec constructs a PodSpec for the genesis ceremony PreInit Job.
117+ // Unlike the snapshot PreInit, the main container runs "sleep infinity" as a keepalive
118+ // (the sidecar does the real work), and an init container copies the seid binary from
119+ // the node image to the PVC so sidecar tasks can invoke it.
120+ func buildGenesisPreInitPodSpec (node * seiv1alpha1.SeiNode , platform PlatformConfig ) corev1.PodSpec {
121+ serviceName := preInitJobName (node )
122+
123+ dataVolume := corev1.Volume {
124+ Name : "data" ,
125+ VolumeSource : corev1.VolumeSource {
126+ PersistentVolumeClaim : & corev1.PersistentVolumeClaimVolumeSource {
127+ ClaimName : nodeDataPVCClaimName (node ),
128+ },
129+ },
130+ }
131+
132+ port := sidecarPort (node )
133+ sidecarContainer := corev1.Container {
134+ Name : "sei-sidecar" ,
135+ Image : sidecarImage (node ),
136+ Command : []string {"seictl" , "serve" },
137+ RestartPolicy : ptr .To (corev1 .ContainerRestartPolicyAlways ),
138+ Env : []corev1.EnvVar {
139+ {Name : "SEI_CHAIN_ID" , Value : node .Spec .ChainID },
140+ {Name : "SEI_SIDECAR_PORT" , Value : fmt .Sprintf ("%d" , port )},
141+ {Name : "SEI_HOME" , Value : dataDir },
142+ },
143+ Ports : []corev1.ContainerPort {
144+ {Name : "sidecar" , ContainerPort : port , Protocol : corev1 .ProtocolTCP },
145+ },
146+ VolumeMounts : []corev1.VolumeMount {
147+ {Name : "data" , MountPath : dataDir },
148+ },
149+ }
150+ if node .Spec .Sidecar != nil && node .Spec .Sidecar .Resources != nil {
151+ sidecarContainer .Resources = * node .Spec .Sidecar .Resources
152+ }
153+
154+ copySeid := corev1.Container {
155+ Name : "copy-seid" ,
156+ Image : node .Spec .Image ,
157+ Command : []string {"sh" , "-c" , fmt .Sprintf ("mkdir -p %s/bin && cp $(which seid) %s/bin/seid" , dataDir , dataDir )},
158+ VolumeMounts : []corev1.VolumeMount {
159+ {Name : "data" , MountPath : dataDir },
160+ },
161+ }
162+
163+ keepalive := corev1.Container {
164+ Name : "keepalive" ,
165+ Image : node .Spec .Image ,
166+ Command : []string {"sleep" , "infinity" },
167+ VolumeMounts : []corev1.VolumeMount {
168+ {Name : "data" , MountPath : dataDir },
169+ },
170+ }
171+
172+ return corev1.PodSpec {
173+ Hostname : preInitPodHostname ,
174+ Subdomain : serviceName ,
175+ ServiceAccountName : platform .ServiceAccount ,
176+ ShareProcessNamespace : ptr .To (true ),
177+ RestartPolicy : corev1 .RestartPolicyNever ,
178+ TerminationGracePeriodSeconds : ptr .To (int64 (5 )),
179+ Tolerations : []corev1.Toleration {
180+ {Key : platform .TolerationKey , Value : platform .TolerationVal , Effect : corev1 .TaintEffectNoSchedule },
181+ },
182+ Volumes : []corev1.Volume {dataVolume },
183+ InitContainers : []corev1.Container {copySeid , sidecarContainer },
184+ Containers : []corev1.Container {keepalive },
185+ }
186+ }
187+
102188func buildPreInitPodSpec (node * seiv1alpha1.SeiNode , snap * seiv1alpha1.SnapshotSource , platform PlatformConfig ) corev1.PodSpec {
103189 serviceName := preInitJobName (node )
104190
0 commit comments