Migrate main.go

This commit is contained in:
Marton Soos
2022-04-15 11:44:20 +02:00
parent 1a085562e4
commit e39cff881d
5 changed files with 220 additions and 18 deletions

1
.VERSION Normal file
View File

@@ -0,0 +1 @@
1.4.0

View File

@@ -49,9 +49,9 @@ var log = logf.Log.WithName("controller_onepassworditem")
// OnePasswordItemReconciler reconciles a OnePasswordItem object
type OnePasswordItemReconciler struct {
kubeClient kubeClient.Client
scheme *runtime.Scheme
opConnectClient connect.Client
Client kubeClient.Client
Scheme *runtime.Scheme
OpConnectClient connect.Client
}
//+kubebuilder:rbac:groups=onepassword.onepassword.com,resources=onepassworditems,verbs=get;list;watch;create;update;patch;delete
@@ -72,7 +72,7 @@ func (r *OnePasswordItemReconciler) Reconcile(ctx context.Context, request ctrl.
reqLogger.Info("Reconciling OnePasswordItem")
onepassworditem := &onepasswordv1.OnePasswordItem{}
err := r.kubeClient.Get(context.Background(), request.NamespacedName, onepassworditem)
err := r.Client.Get(context.Background(), request.NamespacedName, onepassworditem)
if err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
@@ -86,7 +86,7 @@ func (r *OnePasswordItemReconciler) Reconcile(ctx context.Context, request ctrl.
// This is so we can handle cleanup of associated secrets properly
if !utils.ContainsString(onepassworditem.ObjectMeta.Finalizers, finalizer) {
onepassworditem.ObjectMeta.Finalizers = append(onepassworditem.ObjectMeta.Finalizers, finalizer)
if err := r.kubeClient.Update(context.Background(), onepassworditem); err != nil {
if err := r.Client.Update(context.Background(), onepassworditem); err != nil {
return reconcile.Result{}, err
}
}
@@ -135,7 +135,7 @@ func (r *OnePasswordItemReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *OnePasswordItemReconciler) removeFinalizer(onePasswordItem *onepasswordv1.OnePasswordItem) error {
onePasswordItem.ObjectMeta.Finalizers = utils.RemoveString(onePasswordItem.ObjectMeta.Finalizers, finalizer)
if err := r.kubeClient.Update(context.Background(), onePasswordItem); err != nil {
if err := r.Client.Update(context.Background(), onePasswordItem); err != nil {
return err
}
return nil
@@ -146,8 +146,8 @@ func (r *OnePasswordItemReconciler) cleanupKubernetesSecret(onePasswordItem *one
kubernetesSecret.ObjectMeta.Name = onePasswordItem.Name
kubernetesSecret.ObjectMeta.Namespace = onePasswordItem.Namespace
r.kubeClient.Delete(context.Background(), kubernetesSecret)
if err := r.kubeClient.Delete(context.Background(), kubernetesSecret); err != nil {
r.Client.Delete(context.Background(), kubernetesSecret)
if err := r.Client.Delete(context.Background(), kubernetesSecret); err != nil {
if !errors.IsNotFound(err) {
return err
}
@@ -162,13 +162,13 @@ func (r *OnePasswordItemReconciler) HandleOnePasswordItem(resource *onepasswordv
secretType := resource.Type
autoRestart := annotations[op.RestartDeploymentsAnnotation]
item, err := onepassword.GetOnePasswordItemByPath(r.opConnectClient, resource.Spec.ItemPath)
item, err := onepassword.GetOnePasswordItemByPath(r.OpConnectClient, resource.Spec.ItemPath)
if err != nil {
return fmt.Errorf("Failed to retrieve item: %v", err)
}
// Create owner reference.
gvk, err := apiutil.GVKForObject(resource, r.scheme)
gvk, err := apiutil.GVKForObject(resource, r.Scheme)
if err != nil {
return fmt.Errorf("could not to retrieve group version kind: %v", err)
}
@@ -179,5 +179,5 @@ func (r *OnePasswordItemReconciler) HandleOnePasswordItem(resource *onepasswordv
UID: resource.GetUID(),
}
return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, resource.Namespace, item, autoRestart, labels, secretType, annotations, ownerRef)
return kubeSecrets.CreateKubernetesSecretFromItem(r.Client, secretName, resource.Namespace, item, autoRestart, labels, secretType, annotations, ownerRef)
}

158
main.go
View File

@@ -17,14 +17,29 @@ limitations under the License.
package main
import (
"errors"
"flag"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/1Password/connect-sdk-go/connect"
op "github.com/1Password/onepassword-operator/pkg/onepassword"
"github.com/1Password/onepassword-operator/pkg/utils"
"github.com/1Password/onepassword-operator/version"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
// sdkVersion "github.com/operator-framework/operator-sdk/version"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
@@ -37,8 +52,9 @@ import (
)
var (
scheme = runtime.NewScheme()
scheme = k8sruntime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
WatchNamespaceEnvVar = "WATCH_NAMESPACE"
)
func init() {
@@ -48,6 +64,14 @@ func init() {
//+kubebuilder:scaffold:scheme
}
func printVersion() {
setupLog.Info(fmt.Sprintf("Operator Version: %s", version.Version))
setupLog.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
setupLog.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
// TODO figure out how to get operator-sdk version
// setupLog.Info(fmt.Sprintf("Version of operator-sdk: %v", sdkVersion.Version))
}
func main() {
var metricsAddr string
var enableLeaderElection bool
@@ -65,22 +89,45 @@ func main() {
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
printVersion()
namespace := os.Getenv(WatchNamespaceEnvVar)
options := ctrl.Options{
Scheme: scheme,
Namespace: namespace,
MetricsBindAddress: metricsAddr,
Port: 9443,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "c26807fd.onepassword.com",
})
}
// Add support for MultiNamespace set in WATCH_NAMESPACE (e.g ns1,ns2)
// Note that this is not intended to be used for excluding namespaces, this is better done via a Predicate
// Also note that you may face performance issues when using this with a high number of namespaces.
if strings.Contains(namespace, ",") {
options.Namespace = ""
options.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(namespace, ","))
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), options)
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
// Setup One Password Client
opConnectClient, err := connect.NewClientFromEnvironment()
if err != nil {
setupLog.Error(err, "failed to create 1Password client")
os.Exit(1)
}
if err = (&controllers.OnePasswordItemReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
OpConnectClient: opConnectClient,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "OnePasswordItem")
os.Exit(1)
@@ -101,4 +148,107 @@ func main() {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
deploymentNamespace, err := utils.GetOperatorNamespace()
if err != nil {
setupLog.Error(err, "Failed to get namespace")
os.Exit(1)
}
//Setup 1PasswordConnect
if shouldManageConnect() {
setupLog.Info("Automated Connect Management Enabled")
go func() {
connectStarted := false
for !connectStarted {
err := op.SetupConnect(mgr.GetClient(), deploymentNamespace)
// Cache Not Started is an acceptable error. Retry until cache is started.
if err != nil && !errors.Is(err, &cache.ErrCacheNotStarted{}) {
setupLog.Error(err, "")
os.Exit(1)
}
if err == nil {
connectStarted = true
}
}
}()
} else {
setupLog.Info("Automated Connect Management Disabled")
}
// TODO: Configure Metrics Service. See: https://sdk.operatorframework.io/docs/building-operators/golang/migration/#export-metrics
// Setup update secrets task
updatedSecretsPoller := op.NewManager(mgr.GetClient(), opConnectClient, shouldAutoRestartDeployments())
done := make(chan bool)
ticker := time.NewTicker(getPollingIntervalForUpdatingSecrets())
go func() {
for {
select {
case <-done:
ticker.Stop()
return
case <-ticker.C:
err := updatedSecretsPoller.UpdateKubernetesSecretsTask()
if err != nil {
setupLog.Error(err, "error running update kubernetes secret task")
}
}
}
}()
// Start the Cmd
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
setupLog.Error(err, "Manager exited non-zero")
done <- true
os.Exit(1)
}
}
const manageConnect = "MANAGE_CONNECT"
func shouldManageConnect() bool {
shouldManageConnect, found := os.LookupEnv(manageConnect)
if found {
shouldManageConnectBool, err := strconv.ParseBool(strings.ToLower(shouldManageConnect))
if err != nil {
setupLog.Error(err, "")
os.Exit(1)
}
return shouldManageConnectBool
}
return false
}
const envPollingIntervalVariable = "POLLING_INTERVAL"
const defaultPollingInterval = 600
func getPollingIntervalForUpdatingSecrets() time.Duration {
timeInSecondsString, found := os.LookupEnv(envPollingIntervalVariable)
if found {
timeInSeconds, err := strconv.Atoi(timeInSecondsString)
if err == nil {
return time.Duration(timeInSeconds) * time.Second
}
setupLog.Info("Invalid value set for polling interval. Must be a valid integer.")
}
setupLog.Info(fmt.Sprintf("Using default polling interval of %v seconds", defaultPollingInterval))
return time.Duration(defaultPollingInterval) * time.Second
}
const restartDeploymentsEnvVariable = "AUTO_RESTART"
func shouldAutoRestartDeployments() bool {
shouldAutoRestartDeployments, found := os.LookupEnv(restartDeploymentsEnvVariable)
if found {
shouldAutoRestartDeploymentsBool, err := strconv.ParseBool(strings.ToLower(shouldAutoRestartDeployments))
if err != nil {
setupLog.Error(err, "")
os.Exit(1)
}
return shouldAutoRestartDeploymentsBool
}
return false
}

45
pkg/utils/k8sutil.go Normal file
View File

@@ -0,0 +1,45 @@
package utils
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
var ForceRunModeEnv = "OSDK_FORCE_RUN_MODE"
type RunModeType string
const (
LocalRunMode RunModeType = "local"
ClusterRunMode RunModeType = "cluster"
)
// ErrNoNamespace indicates that a namespace could not be found for the current
// environment
var ErrNoNamespace = fmt.Errorf("namespace not found for current environment")
// ErrRunLocal indicates that the operator is set to run in local mode (this error
// is returned by functions that only work on operators running in cluster mode)
var ErrRunLocal = fmt.Errorf("operator run mode forced to local")
// GetOperatorNamespace returns the namespace the operator should be running in.
func GetOperatorNamespace() (string, error) {
if isRunModeLocal() {
return "", ErrRunLocal
}
nsBytes, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
if os.IsNotExist(err) {
return "", ErrNoNamespace
}
return "", err
}
ns := strings.TrimSpace(string(nsBytes))
return ns, nil
}
func isRunModeLocal() bool {
return os.Getenv(ForceRunModeEnv) == string(LocalRunMode)
}

6
version/version.go Normal file
View File

@@ -0,0 +1,6 @@
package version
// TODO figure out if this package makes sense.
var (
Version = "0.0.1"
)