Browse code

Refactor master start to split responsibilities

Allow health checking and metrics to run for the subcommands
and allow --listen in controllers to differ from the master.

Clayton Coleman authored on 2015/08/16 04:42:13
Showing 5 changed files
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	restful "github.com/emicklei/go-restful"
13 13
 	"github.com/emicklei/go-restful/swagger"
14 14
 	"github.com/golang/glog"
15
+	"github.com/prometheus/client_golang/prometheus"
15 16
 
16 17
 	kapi "k8s.io/kubernetes/pkg/api"
17 18
 	"k8s.io/kubernetes/pkg/api/rest"
... ...
@@ -188,6 +189,27 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller)
188 188
 		handler = apiserver.MaxInFlightLimit(sem, longRunningRE, handler)
189 189
 	}
190 190
 
191
+	c.serve(handler, extra)
192
+
193
+	// Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try)
194
+	cmdutil.WaitForSuccessfulDial(c.TLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100)
195
+}
196
+
197
+func (c *MasterConfig) RunHealth() {
198
+	ws := &restful.WebService{}
199
+	mux := http.NewServeMux()
200
+	hc := kmaster.NewHandlerContainer(mux)
201
+	hc.Add(ws)
202
+
203
+	initHealthCheckRoute(ws, "/healthz")
204
+	initReadinessCheckRoute(ws, "/healthz/ready", func() bool { return true })
205
+	initMetricsRoute(ws, "/metrics")
206
+
207
+	c.serve(hc, []string{"Started health checks at %s"})
208
+}
209
+
210
+// serve starts serving the provided http.Handler using security settings derived from the MasterConfig
211
+func (c *MasterConfig) serve(handler http.Handler, extra []string) {
191 212
 	timeout := c.Options.ServingInfo.RequestTimeoutSeconds
192 213
 	if timeout == -1 {
193 214
 		timeout = 0
... ...
@@ -219,20 +241,19 @@ func (c *MasterConfig) Run(protected []APIInstaller, unprotected []APIInstaller)
219 219
 			glog.Fatal(server.ListenAndServe())
220 220
 		}
221 221
 	}, 0)
222
+}
222 223
 
223
-	// Attempt to verify the server came up for 20 seconds (100 tries * 100ms, 100ms timeout per try)
224
-	cmdutil.WaitForSuccessfulDial(c.TLS, c.Options.ServingInfo.BindNetwork, c.Options.ServingInfo.BindAddress, 100*time.Millisecond, 100*time.Millisecond, 100)
225
-
224
+// InitializeObjects ensures objects in Kubernetes and etcd are properly populated.
225
+// Requires a Kube client to be established and that etcd be started.
226
+func (c *MasterConfig) InitializeObjects() {
226 227
 	// Create required policy rules if needed
227 228
 	c.ensureComponentAuthorizationRules()
228 229
 	// Ensure the default SCCs are created
229 230
 	c.ensureDefaultSecurityContextConstraints()
230 231
 	// Bind default roles for service accounts in the default namespace if needed
231 232
 	c.ensureDefaultNamespaceServiceAccountRoles()
232
-
233 233
 	// Create the infra namespace
234 234
 	c.ensureOpenShiftInfraNamespace()
235
-
236 235
 	// Create the shared resource namespace
237 236
 	c.ensureOpenShiftSharedResourcesNamespace()
238 237
 }
... ...
@@ -278,11 +299,12 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin
278 278
 		container.Add(root)
279 279
 	}
280 280
 
281
-	initControllerRoutes(root, "/controllers", c.Options.Controllers != configapi.ControllersDisabled, c.ControllerPlug)
282 281
 	initAPIVersionRoute(root, LegacyOpenShiftAPIPrefix, legacyAPIVersions...)
283 282
 	initAPIVersionRoute(root, OpenShiftAPIPrefix, currentAPIVersions...)
284
-	initHealthCheckRoute(root, "healthz")
285
-	initReadinessCheckRoute(root, "healthz/ready", c.ProjectAuthorizationCache.ReadyForAccess)
283
+
284
+	initControllerRoutes(root, "/controllers", c.Options.Controllers != configapi.ControllersDisabled, c.ControllerPlug)
285
+	initHealthCheckRoute(root, "/healthz")
286
+	initReadinessCheckRoute(root, "/healthz/ready", c.ProjectAuthorizationCache.ReadyForAccess)
286 287
 
287 288
 	return messages
288 289
 }
... ...
@@ -503,6 +525,17 @@ func initReadinessCheckRoute(root *restful.WebService, path string, readyFunc fu
503 503
 		Produces(restful.MIME_JSON))
504 504
 }
505 505
 
506
+// initHealthCheckRoute initalizes an HTTP endpoint for health checking.
507
+// OpenShift is deemed healthy if the API server can respond with an OK messages
508
+func initMetricsRoute(root *restful.WebService, path string) {
509
+	h := prometheus.Handler()
510
+	root.Route(root.GET(path).To(func(req *restful.Request, resp *restful.Response) {
511
+		h.ServeHTTP(resp.ResponseWriter, req.Request)
512
+	}).Doc("return metrics for this process").
513
+		Returns(http.StatusOK, "if metrics are available", nil).
514
+		Produces("text/plain"))
515
+}
516
+
506 517
 func (c *MasterConfig) defaultAPIGroupVersion() *apiserver.APIGroupVersion {
507 518
 	return &apiserver.APIGroupVersion{
508 519
 		Root: OpenShiftAPIPrefix,
... ...
@@ -75,6 +75,8 @@ type MasterArgs struct {
75 75
 	SchedulerConfigFile string
76 76
 
77 77
 	NetworkArgs *NetworkArgs
78
+
79
+	OverrideConfig func(config *configapi.MasterConfig) error
78 80
 }
79 81
 
80 82
 // BindMasterArgs binds the options to the flags with prefix + default flag names
... ...
@@ -70,7 +70,6 @@ func NewCommandStartMasterAPI(name, basename string, out io.Writer) (*cobra.Comm
70 70
 	// This command only supports reading from config and the listen argument
71 71
 	flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from. Required")
72 72
 	cmd.MarkFlagFilename("config", "yaml", "yml")
73
-	// TODO: add health and metrics endpoints on this listen argument
74 73
 	BindListenArg(options.MasterArgs.ListenArg, flags, "")
75 74
 
76 75
 	return cmd, options
... ...
@@ -10,6 +10,9 @@ import (
10 10
 
11 11
 	kerrors "k8s.io/kubernetes/pkg/api/errors"
12 12
 	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
13
+
14
+	"github.com/openshift/origin/pkg/cmd/flagtypes"
15
+	configapi "github.com/openshift/origin/pkg/cmd/server/api"
13 16
 )
14 17
 
15 18
 const controllersLong = `Start the master controllers
... ...
@@ -63,15 +66,28 @@ func NewCommandStartMasterControllers(name, basename string, out io.Writer) (*co
63 63
 		},
64 64
 	}
65 65
 
66
+	// start controllers on a non conflicting health port from the default master
67
+	listenArg := &ListenArg{
68
+		ListenAddr: flagtypes.Addr{
69
+			Value:         "127.0.0.1:8444",
70
+			DefaultScheme: "https",
71
+			DefaultPort:   8444,
72
+			AllowPrefix:   true,
73
+		}.Default(),
74
+	}
75
+
66 76
 	options.MasterArgs = NewDefaultMasterArgs()
67 77
 	options.MasterArgs.StartControllers = true
78
+	options.MasterArgs.OverrideConfig = func(config *configapi.MasterConfig) error {
79
+		config.ServingInfo.BindAddress = listenArg.ListenAddr.URL.Host
80
+		return nil
81
+	}
68 82
 
69 83
 	flags := cmd.Flags()
70 84
 	// This command only supports reading from config and the listen argument
71 85
 	flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from. Required")
72 86
 	cmd.MarkFlagFilename("config", "yaml", "yml")
73
-	// TODO: add health and metrics endpoints on this listen argument
74
-	BindListenArg(options.MasterArgs.ListenArg, flags, "")
87
+	BindListenArg(listenArg, flags, "")
75 88
 
76 89
 	return cmd, options
77 90
 }
... ...
@@ -182,6 +182,8 @@ func (o MasterOptions) StartMaster() error {
182 182
 		return nil
183 183
 	}
184 184
 
185
+	// TODO: this should be encapsulated by RunMaster, but StartAllInOne has no
186
+	// way to communicate whether RunMaster should block.
185 187
 	go daemon.SdNotify("READY=1")
186 188
 	select {}
187 189
 }
... ...
@@ -215,6 +217,12 @@ func (o MasterOptions) RunMaster() error {
215 215
 		return err
216 216
 	}
217 217
 
218
+	if o.MasterArgs.OverrideConfig != nil {
219
+		if err := o.MasterArgs.OverrideConfig(masterConfig); err != nil {
220
+			return err
221
+		}
222
+	}
223
+
218 224
 	if o.IsWriteConfigOnly() {
219 225
 		// Resolve relative to CWD
220 226
 		cwd, err := os.Getwd()
... ...
@@ -269,20 +277,12 @@ func (o MasterOptions) RunMaster() error {
269 269
 		masterConfig.Controllers = configapi.ControllersDisabled
270 270
 	}
271 271
 
272
-	if !o.MasterArgs.StartAPI {
273
-		openshiftConfig, err := origin.BuildMasterConfig(*masterConfig)
274
-		if err != nil {
275
-			return err
276
-		}
277
-
278
-		_, kubeMasterConfig, err := buildKubernetesMasterConfig(openshiftConfig)
279
-		if err != nil {
280
-			return err
281
-		}
282
-		return StartControllers(openshiftConfig, kubeMasterConfig)
272
+	m := &master{
273
+		config:      masterConfig,
274
+		api:         o.MasterArgs.StartAPI,
275
+		controllers: o.MasterArgs.StartControllers,
283 276
 	}
284
-
285
-	return StartMaster(masterConfig)
277
+	return m.Start()
286 278
 }
287 279
 
288 280
 func (o MasterOptions) CreateBootstrapPolicy() error {
... ...
@@ -327,25 +327,24 @@ func (o MasterOptions) CreateCerts() error {
327 327
 	return nil
328 328
 }
329 329
 
330
-func buildKubernetesMasterConfig(openshiftConfig *origin.MasterConfig) (bool, *kubernetes.MasterConfig, error) {
330
+func buildKubernetesMasterConfig(openshiftConfig *origin.MasterConfig) (*kubernetes.MasterConfig, error) {
331 331
 	if openshiftConfig.Options.KubernetesMasterConfig == nil {
332
-		return false, nil, nil
332
+		return nil, nil
333 333
 	}
334 334
 	kubeConfig, err := kubernetes.BuildKubernetesMasterConfig(openshiftConfig.Options, openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient())
335
-	return true, kubeConfig, err
335
+	return kubeConfig, err
336 336
 }
337 337
 
338
-func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error {
339
-	glog.Infof("Starting master on %s (%s)", openshiftMasterConfig.ServingInfo.BindAddress, version.Get().String())
340
-	glog.Infof("Public master address is %s", openshiftMasterConfig.AssetConfig.MasterPublicURL)
341
-	if len(openshiftMasterConfig.DisabledFeatures) > 0 {
342
-		glog.V(4).Infof("Disabled features: %s", strings.Join(openshiftMasterConfig.DisabledFeatures, ", "))
343
-	}
344
-
345
-	if openshiftMasterConfig.EtcdConfig != nil {
346
-		etcd.RunEtcd(openshiftMasterConfig.EtcdConfig)
347
-	}
338
+// master encapsulates starting the components of the master
339
+type master struct {
340
+	config      *configapi.MasterConfig
341
+	controllers bool
342
+	api         bool
343
+}
348 344
 
345
+// Start launches a master. It will error if possible, but some background processes may still
346
+// be running and the process should exit after it finishes.
347
+func (m *master) Start() error {
349 348
 	// Allow privileged containers
350 349
 	// TODO: make this configurable and not the default https://github.com/openshift/origin/issues/662
351 350
 	capabilities.Initialize(capabilities.Capabilities{
... ...
@@ -353,25 +352,85 @@ func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error {
353 353
 		HostNetworkSources: []string{kubelet.ApiserverSource, kubelet.FileSource},
354 354
 	})
355 355
 
356
-	openshiftConfig, err := origin.BuildMasterConfig(*openshiftMasterConfig)
356
+	openshiftConfig, err := origin.BuildMasterConfig(*m.config)
357 357
 	if err != nil {
358 358
 		return err
359 359
 	}
360 360
 
361
+	kubeMasterConfig, err := buildKubernetesMasterConfig(openshiftConfig)
362
+	if err != nil {
363
+		return err
364
+	}
365
+
366
+	if m.api {
367
+		glog.Infof("Starting master on %s (%s)", m.config.ServingInfo.BindAddress, version.Get().String())
368
+		glog.Infof("Public master address is %s", m.config.AssetConfig.MasterPublicURL)
369
+		if len(m.config.DisabledFeatures) > 0 {
370
+			glog.V(4).Infof("Disabled features: %s", strings.Join(m.config.DisabledFeatures, ", "))
371
+		}
372
+		glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>"))
373
+
374
+		if err := startAPI(openshiftConfig, kubeMasterConfig); err != nil {
375
+			return err
376
+		}
377
+		if m.controllers {
378
+			// run controllers asynchronously (not required to be "ready")
379
+			go func() {
380
+				if err := startControllers(openshiftConfig, kubeMasterConfig); err != nil {
381
+					glog.Fatal(err)
382
+				}
383
+			}()
384
+		}
385
+		return nil
386
+	}
387
+
388
+	if m.controllers {
389
+		glog.Infof("Starting controllers on %s (%s)", m.config.ServingInfo.BindAddress, version.Get().String())
390
+		if len(m.config.DisabledFeatures) > 0 {
391
+			glog.V(4).Infof("Disabled features: %s", strings.Join(m.config.DisabledFeatures, ", "))
392
+		}
393
+		glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>"))
394
+
395
+		if err := startHealth(openshiftConfig); err != nil {
396
+			return err
397
+		}
398
+		if err := startControllers(openshiftConfig, kubeMasterConfig); err != nil {
399
+			return err
400
+		}
401
+	}
402
+
403
+	return nil
404
+}
405
+
406
+func startHealth(openshiftConfig *origin.MasterConfig) error {
407
+	openshiftConfig.RunHealth()
408
+	return nil
409
+}
410
+
411
+// startAPI starts the components of the master that are considered part of the API - the Kubernetes
412
+// API and core controllers, the Origin API, the group, policy, project, and authorization caches,
413
+// etcd, the asset server (for the UI), the OAuth server endpoints, and the DNS server.
414
+// TODO: allow to be more granularly targeted
415
+func startAPI(oc *origin.MasterConfig, kc *kubernetes.MasterConfig) error {
416
+	// start etcd
417
+	if oc.Options.EtcdConfig != nil {
418
+		etcd.RunEtcd(oc.Options.EtcdConfig)
419
+	}
420
+
361 421
 	// verify we can connect to etcd with the provided config
362
-	if err := etcd.TestEtcdClient(openshiftConfig.EtcdClient); err != nil {
422
+	if err := etcd.TestEtcdClient(oc.EtcdClient); err != nil {
363 423
 		return err
364 424
 	}
365 425
 
366 426
 	// Must start policy caching immediately
367
-	openshiftConfig.RunGroupCache()
368
-	openshiftConfig.RunPolicyCache()
369
-	openshiftConfig.RunProjectCache()
427
+	oc.RunGroupCache()
428
+	oc.RunPolicyCache()
429
+	oc.RunProjectCache()
370 430
 
371 431
 	unprotectedInstallers := []origin.APIInstaller{}
372 432
 
373
-	if openshiftMasterConfig.OAuthConfig != nil {
374
-		authConfig, err := origin.BuildAuthConfig(*openshiftMasterConfig)
433
+	if oc.Options.OAuthConfig != nil {
434
+		authConfig, err := origin.BuildAuthConfig(oc.Options)
375 435
 		if err != nil {
376 436
 			return err
377 437
 		}
... ...
@@ -379,116 +438,109 @@ func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error {
379 379
 	}
380 380
 
381 381
 	var standaloneAssetConfig *origin.AssetConfig
382
-	if openshiftConfig.WebConsoleEnabled() {
383
-		config, err := origin.BuildAssetConfig(*openshiftMasterConfig.AssetConfig)
382
+	if oc.WebConsoleEnabled() {
383
+		config, err := origin.BuildAssetConfig(*oc.Options.AssetConfig)
384 384
 		if err != nil {
385 385
 			return err
386 386
 		}
387 387
 
388
-		if openshiftMasterConfig.AssetConfig.ServingInfo.BindAddress == openshiftMasterConfig.ServingInfo.BindAddress {
388
+		if oc.Options.AssetConfig.ServingInfo.BindAddress == oc.Options.ServingInfo.BindAddress {
389 389
 			unprotectedInstallers = append(unprotectedInstallers, config)
390 390
 		} else {
391 391
 			standaloneAssetConfig = config
392 392
 		}
393 393
 	}
394 394
 
395
-	startKubeMaster, kubeMasterConfig, err := buildKubernetesMasterConfig(openshiftConfig)
396
-	if err != nil {
397
-		return err
398
-	}
399
-	if startKubeMaster {
400
-		openshiftConfig.Run([]origin.APIInstaller{kubeMasterConfig}, unprotectedInstallers)
395
+	if kc != nil {
396
+		oc.Run([]origin.APIInstaller{kc}, unprotectedInstallers)
401 397
 	} else {
402
-		_, kubeMasterConfig, err := configapi.GetKubeClient(openshiftConfig.Options.MasterClients.ExternalKubernetesKubeConfig)
398
+		_, kubeClientConfig, err := configapi.GetKubeClient(oc.Options.MasterClients.ExternalKubernetesKubeConfig)
403 399
 		if err != nil {
404 400
 			return err
405 401
 		}
406 402
 		proxy := &kubernetes.ProxyConfig{
407
-			ClientConfig: kubeMasterConfig,
403
+			ClientConfig: kubeClientConfig,
408 404
 		}
409
-		openshiftConfig.Run([]origin.APIInstaller{proxy}, unprotectedInstallers)
405
+		oc.Run([]origin.APIInstaller{proxy}, unprotectedInstallers)
410 406
 	}
411 407
 
412
-	glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>"))
408
+	oc.InitializeObjects()
413 409
 
414 410
 	if standaloneAssetConfig != nil {
415 411
 		standaloneAssetConfig.Run()
416 412
 	}
417
-	if openshiftMasterConfig.DNSConfig != nil {
418
-		openshiftConfig.RunDNSServer()
419
-	}
420
-
421
-	openshiftConfig.RunProjectAuthorizationCache()
422 413
 
423
-	// controllers don't block startup
424
-	go func() {
425
-		if err := StartControllers(openshiftConfig, kubeMasterConfig); err != nil {
426
-			glog.Fatal(err)
427
-		}
428
-	}()
414
+	if oc.Options.DNSConfig != nil {
415
+		oc.RunDNSServer()
416
+	}
429 417
 
418
+	oc.RunProjectAuthorizationCache()
430 419
 	return nil
431 420
 }
432 421
 
433
-// StartControllers launches the controllers
434
-func StartControllers(openshiftConfig *origin.MasterConfig, kubeMasterConfig *kubernetes.MasterConfig) error {
435
-	if openshiftConfig.Options.Controllers == configapi.ControllersDisabled {
422
+// startControllers launches the controllers
423
+func startControllers(oc *origin.MasterConfig, kc *kubernetes.MasterConfig) error {
424
+	if oc.Options.Controllers == configapi.ControllersDisabled {
436 425
 		return nil
437 426
 	}
438 427
 
439 428
 	go func() {
440
-		openshiftConfig.ControllerPlugStart()
429
+		oc.ControllerPlugStart()
441 430
 		// when a manual shutdown (DELETE /controllers) or lease lost occurs, the process should exit
442 431
 		// this ensures no code is still running as a controller, and allows a process manager to reset
443 432
 		// the controller to come back into a candidate state and compete for the lease
444
-		openshiftConfig.ControllerPlug.WaitForStop()
433
+		oc.ControllerPlug.WaitForStop()
445 434
 		glog.Fatalf("Controller shutdown requested")
446 435
 	}()
447 436
 
448
-	openshiftConfig.ControllerPlug.WaitForStart()
449
-	glog.Infof("Controllers starting (%s)", openshiftConfig.Options.Controllers)
437
+	oc.ControllerPlug.WaitForStart()
438
+	glog.Infof("Controllers starting (%s)", oc.Options.Controllers)
450 439
 
451 440
 	// Start these first, because they provide credentials for other controllers' clients
452
-	openshiftConfig.RunServiceAccountsController()
453
-	openshiftConfig.RunServiceAccountTokensController()
441
+	oc.RunServiceAccountsController()
442
+	oc.RunServiceAccountTokensController()
454 443
 	// used by admission controllers
455
-	openshiftConfig.RunServiceAccountPullSecretsControllers()
456
-	openshiftConfig.RunSecurityAllocationController()
444
+	oc.RunServiceAccountPullSecretsControllers()
445
+	oc.RunSecurityAllocationController()
457 446
 
458
-	if kubeMasterConfig != nil {
459
-		_, rcClient, err := openshiftConfig.GetServiceAccountClients(openshiftConfig.ReplicationControllerServiceAccount)
447
+	if kc != nil {
448
+		_, rcClient, err := oc.GetServiceAccountClients(oc.ReplicationControllerServiceAccount)
460 449
 		if err != nil {
461 450
 			glog.Fatalf("Could not get client for replication controller: %v", err)
462 451
 		}
463 452
 
464 453
 		// called by admission control
465
-		kubeMasterConfig.RunResourceQuotaManager()
454
+		kc.RunResourceQuotaManager()
466 455
 
467 456
 		// no special order
468
-		kubeMasterConfig.RunNodeController()
469
-		kubeMasterConfig.RunScheduler()
470
-		kubeMasterConfig.RunReplicationController(rcClient)
471
-		kubeMasterConfig.RunEndpointController()
472
-		kubeMasterConfig.RunNamespaceController()
473
-		kubeMasterConfig.RunPersistentVolumeClaimBinder()
474
-		kubeMasterConfig.RunPersistentVolumeClaimRecycler(openshiftConfig.ImageFor("deployer"))
475
-	}
476
-
477
-	// no special order\
478
-	if configapi.IsBuildEnabled(&openshiftConfig.Options) {
479
-		openshiftConfig.RunBuildController()
480
-		openshiftConfig.RunBuildPodController()
481
-		openshiftConfig.RunBuildConfigChangeController()
482
-		openshiftConfig.RunBuildImageChangeTriggerController()
483
-	}
484
-	openshiftConfig.RunDeploymentController()
485
-	openshiftConfig.RunDeployerPodController()
486
-	openshiftConfig.RunDeploymentConfigController()
487
-	openshiftConfig.RunDeploymentConfigChangeController()
488
-	openshiftConfig.RunDeploymentImageChangeTriggerController()
489
-	openshiftConfig.RunImageImportController()
490
-	openshiftConfig.RunOriginNamespaceController()
491
-	openshiftConfig.RunSDNController()
457
+		kc.RunNodeController()
458
+		kc.RunScheduler()
459
+		kc.RunReplicationController(rcClient)
460
+		kc.RunEndpointController()
461
+		kc.RunNamespaceController()
462
+		kc.RunPersistentVolumeClaimBinder()
463
+		kc.RunPersistentVolumeClaimRecycler(oc.ImageFor("deployer"))
464
+	}
465
+
466
+	// no special order
467
+	if configapi.IsBuildEnabled(&oc.Options) {
468
+		oc.RunBuildController()
469
+		oc.RunBuildPodController()
470
+		oc.RunBuildConfigChangeController()
471
+		oc.RunBuildImageChangeTriggerController()
472
+	}
473
+	oc.RunBuildController()
474
+	oc.RunBuildPodController()
475
+	oc.RunBuildConfigChangeController()
476
+	oc.RunBuildImageChangeTriggerController()
477
+	oc.RunDeploymentController()
478
+	oc.RunDeployerPodController()
479
+	oc.RunDeploymentConfigController()
480
+	oc.RunDeploymentConfigChangeController()
481
+	oc.RunDeploymentImageChangeTriggerController()
482
+	oc.RunImageImportController()
483
+	oc.RunOriginNamespaceController()
484
+	oc.RunSDNController()
492 485
 
493 486
 	return nil
494 487
 }