forked from hashicorp/hcp-terraform-operator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
211 lines (184 loc) · 6.21 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package main
import (
"flag"
"fmt"
"os"
"strings"
"time"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/config"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"github.com/go-logr/zapr"
appv1alpha2 "github.com/hashicorp/terraform-cloud-operator/api/v1alpha2"
"github.com/hashicorp/terraform-cloud-operator/controllers"
//+kubebuilder:scaffold:imports
)
const (
LOG_LEVEL_VAR = "TF_LOG_OPERATOR"
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(appv1alpha2.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
func main() {
// GLOBAL OPTIONS
var syncPeriod time.Duration
flag.DurationVar(&syncPeriod, "sync-period", 5*time.Minute,
"The minimum frequency at which watched resources are reconciled. Format: 5s, 1m, etc.")
var watchNamespaces cliNamespaces
flag.Var(&watchNamespaces, "namespace", "Namespace to watch")
// OPERATOR OPRTIONS
var agentPoolWorkers int
flag.IntVar(&agentPoolWorkers, "agent-pool-workers", 1,
"The number of the Agent Pool controller workers.")
var moduleWorkers int
flag.IntVar(&moduleWorkers, "module-workers", 1,
"The number of the Module controller workers.")
var projectWorkers int
flag.IntVar(&projectWorkers, "project-workers", 1,
"The number of the Workspace controller workers.")
var workspaceWorkers int
flag.IntVar(&workspaceWorkers, "workspace-workers", 1,
"The number of the Workspace controller workers.")
flag.Parse()
zapConfig := zap.NewProductionConfig()
zapConfig.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
zapConfig.EncoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder
zapConfig.Encoding = "console"
zapConfig.DisableCaller = true
zapConfig.DisableStacktrace = true
if ls, ok := os.LookupEnv(LOG_LEVEL_VAR); ok {
lv, lerr := zap.ParseAtomicLevel(ls)
if lerr == nil {
setupLog.Info("Set logging level to %q", ls)
zapConfig.Level = lv
} else {
setupLog.Error(lerr, "unable to set logging level")
}
}
logger, err := zapConfig.Build(zap.AddStacktrace(zapcore.DPanicLevel))
if err != nil {
setupLog.Error(err, "unable to set up logging")
os.Exit(1)
}
ctrl.SetLogger(zapr.NewLogger(logger))
options := ctrl.Options{
Controller: config.Controller{
GroupKindConcurrency: map[string]int{
"AgentPool.app.terraform.io": agentPoolWorkers,
"Module.app.terraform.io": moduleWorkers,
"Workspace.app.terraform.io": workspaceWorkers,
"Project.app.terraform.io": projectWorkers,
},
},
Scheme: scheme,
SyncPeriod: &syncPeriod,
MetricsBindAddress: "127.0.0.1:8080",
HealthProbeBindAddress: ":8081",
LeaderElection: true,
LeaderElectionReleaseOnCancel: true,
LeaderElectionID: "hashicorp-terraform-cloud-operator",
}
// When the Operator not running in a Kubernetes environment,
// i.e. during the development stage when it runs via the command 'make run',
// It requires a namespace to be specified for the Leader Election.
// We set it up to 'default' since this namespace always presents.
if _, err := rest.InClusterConfig(); err != nil {
if err == rest.ErrNotInCluster {
setupLog.Info("does not run in a Kubernetes environment")
options.LeaderElectionNamespace = "default"
} else {
// Ignore all other errors since it is affect only the dev end but print them out.
setupLog.Info("got an error when calling InClusterConfig:", err)
}
}
if len(watchNamespaces) != 0 {
setupLog.Info("Watching namespaces: " + strings.Join(watchNamespaces, " "))
options.Cache.Namespaces = watchNamespaces
} else {
setupLog.Info("Watching all namespaces")
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options)
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
if err = (&controllers.AgentPoolReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("AgentPoolController"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "AgentPool")
os.Exit(1)
}
if err = (&controllers.ModuleReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("ModuleController"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Module")
os.Exit(1)
}
if err = (&controllers.ProjectReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("ProjectController"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Project")
os.Exit(1)
}
if err = (&controllers.WorkspaceReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("WorkspaceController"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Workspace")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up ready check")
os.Exit(1)
}
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}
type cliNamespaces []string
func (n *cliNamespaces) String() string {
return strings.Join(*n, ",")
}
func (n *cliNamespaces) Set(s string) error {
if len(s) == 0 {
return fmt.Errorf("namespace cannot be empty")
}
for _, v := range *n {
if v == s {
return nil
}
}
*n = append(*n, s)
return nil
}