@@ -26,6 +26,7 @@ import (
2626
2727 //+kubebuilder:scaffold:imports
2828 csov1alpha1 "github.com/SovereignCloudStack/cluster-stack-operator/api/v1alpha1"
29+ "github.com/SovereignCloudStack/cluster-stack-operator/extension/handlers"
2930 "github.com/SovereignCloudStack/cluster-stack-operator/internal/controller"
3031 "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient"
3132 "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake"
@@ -39,6 +40,10 @@ import (
3940 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
4041 _ "k8s.io/client-go/plugin/pkg/client/auth"
4142 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
43+ "sigs.k8s.io/cluster-api/controllers/remote"
44+ runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog"
45+ runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
46+ "sigs.k8s.io/cluster-api/exp/runtime/server"
4247 dockerv1beta1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1"
4348 "sigs.k8s.io/cluster-api/util/record"
4449 ctrl "sigs.k8s.io/controller-runtime"
@@ -51,9 +56,15 @@ import (
5156var (
5257 scheme = runtime .NewScheme ()
5358 setupLog = ctrl .Log .WithName ("setup" )
59+
60+ // catalog contains all information about RuntimeHooks.
61+ catalog = runtimecatalog .New ()
5462)
5563
5664func init () {
65+ // Adds to the catalog all the RuntimeHooks defined in cluster API.
66+ _ = runtimehooksv1 .AddToCatalog (catalog )
67+
5768 utilruntime .Must (clientgoscheme .AddToScheme (scheme ))
5869 utilruntime .Must (csov1alpha1 .AddToScheme (scheme ))
5970 utilruntime .Must (dockerv1beta1 .AddToScheme (scheme ))
7687 localMode bool
7788 qps float64
7889 burst int
90+ hookPort int
91+ hookCertDir string
7992)
8093
8194func main () {
@@ -93,7 +106,8 @@ func main() {
93106 flag .BoolVar (& localMode , "local" , false , "Enable local mode where no release assets will be downloaded from a remote Git repository. Useful for implementing cluster stacks." )
94107 flag .Float64Var (& qps , "qps" , 50 , "Enable custom query per second for kubernetes API server" )
95108 flag .IntVar (& burst , "burst" , 100 , "Enable custom burst defines how many queries the API server will accept before enforcing the limit established by qps" )
96-
109+ flag .IntVar (& hookPort , "hook-port" , 9442 , "hook server port" )
110+ flag .StringVar (& hookCertDir , "hook-cert-dir" , "/tmp/k8s-hook-server/serving-certs/" , "hook cert dir, only used when hook-port is specified." )
97111 flag .Parse ()
98112
99113 ctrl .SetLogger (utillog .GetDefaultLogger (logLevel ))
@@ -151,7 +165,6 @@ func main() {
151165 }
152166
153167 var wg sync.WaitGroup
154- wg .Add (1 )
155168
156169 if err = (& controller.ClusterStackReconciler {
157170 Client : mgr .GetClient (),
@@ -207,14 +220,88 @@ func main() {
207220 os .Exit (1 )
208221 }
209222
210- setupLog .Info ("starting manager" , "version" , csoversion .Get ().String ())
211- if err := mgr .Start (ctx ); err != nil {
212- setupLog .Error (err , "problem running manager" )
223+ // Create a http server for serving runtime extensions
224+ hookServer , err := server .New (server.Options {
225+ Catalog : catalog ,
226+ Port : hookPort ,
227+ CertDir : hookCertDir ,
228+ })
229+ if err != nil {
230+ setupLog .Error (err , "error creating webhook server" )
231+ os .Exit (1 )
232+ }
233+
234+ // Lifecycle Hooks
235+ // Gets a client to access the Kubernetes cluster where this RuntimeExtension will be deployed to;
236+ // this is a requirement specific of the lifecycle hooks implementation for Cluster APIs E2E tests.
237+ restConfig .UserAgent = remote .DefaultClusterAPIUserAgent ("cluster-stack-operator-extension-manager" )
238+
239+ // Create the ExtensionHandlers for the lifecycle hooks
240+ lifecycleExtensionHandlers := handlers .NewExtensionHandlers (mgr .GetClient (), scheme )
241+
242+ setupLog .Info ("Add extension handlers" )
243+ if err := hookServer .AddExtensionHandler (server.ExtensionHandler {
244+ Hook : runtimehooksv1 .BeforeClusterUpgrade ,
245+ Name : "before-cluster-upgrade" ,
246+ HandlerFunc : lifecycleExtensionHandlers .DoBeforeClusterUpgrade ,
247+ }); err != nil {
248+ setupLog .Error (err , "error adding handler" )
249+ os .Exit (1 )
250+ }
251+
252+ if err := hookServer .AddExtensionHandler (server.ExtensionHandler {
253+ Hook : runtimehooksv1 .AfterClusterUpgrade ,
254+ Name : "after-cluster-upgrade" ,
255+ HandlerFunc : lifecycleExtensionHandlers .DoAfterClusterUpgrade ,
256+ }); err != nil {
257+ setupLog .Error (err , "error adding handler" )
213258 os .Exit (1 )
214259 }
215260
216- wg .Done ()
217- // Wait for all target cluster managers to gracefully shut down.
261+ if err := hookServer .AddExtensionHandler (server.ExtensionHandler {
262+ Hook : runtimehooksv1 .AfterControlPlaneInitialized ,
263+ Name : "after-control-plane-initialized" ,
264+ HandlerFunc : lifecycleExtensionHandlers .DoAfterControlPlaneInitialized ,
265+ }); err != nil {
266+ setupLog .Error (err , "error adding handler" )
267+ os .Exit (1 )
268+ }
269+
270+ errChan := make (chan error , 1 )
271+
272+ wg .Add (1 )
273+
274+ go func () {
275+ setupLog .Info ("starting manager" , "version" , csoversion .Get ().String ())
276+ if err := mgr .Start (ctx ); err != nil {
277+ setupLog .Error (err , "problem running manager" )
278+ errChan <- err
279+ }
280+ wg .Done ()
281+ }()
282+
283+ wg .Add (1 )
284+
285+ go func () {
286+ setupLog .Info ("starting hook server" )
287+ if err := hookServer .Start (ctx ); err != nil {
288+ setupLog .Error (err , "problem running hook server" )
289+ errChan <- err
290+ }
291+ wg .Done ()
292+ }()
293+
294+ go func () {
295+ select {
296+ case err := <- errChan :
297+ setupLog .Error (err , "Received error" )
298+ os .Exit (1 )
299+ case <- ctx .Done ():
300+ setupLog .Info ("shutting down" )
301+ }
302+ }()
303+
304+ // wait for all processes to shut down
218305 wg .Wait ()
219306}
220307
0 commit comments