mirror of
https://github.com/1Password/onepassword-operator.git
synced 2025-10-22 23:48:05 +00:00
Auto restart one password custom resource will be be added to converted kubernetes secret
This commit is contained in:
12
README.md
12
README.md
@@ -176,6 +176,18 @@ metadata:
|
|||||||
```
|
```
|
||||||
If the value is not set, the auto reset settings on the namespace will be used.
|
If the value is not set, the auto reset settings on the namespace will be used.
|
||||||
|
|
||||||
|
**Per OnePasswordItem Custom Resource**
|
||||||
|
This method allows for managing auto restarts on a given OnePasswordItem custom resource. Auto restarts can by managed by setting the annotation `onepasswordoperator/auto_restart` to either `true` or `false` on the desired OnePasswordItem. An example of this is shown below:
|
||||||
|
```yaml
|
||||||
|
# enabled auto restarts for the OnePasswordItem
|
||||||
|
apiVersion: onepassword.com/v1
|
||||||
|
kind: OnePasswordItem
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
onepasswordoperator/auto_restart: "true"
|
||||||
|
```
|
||||||
|
If the value is not set, the auto reset settings on the deployment will be used.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Creating a Docker image
|
### Creating a Docker image
|
||||||
|
@@ -2,6 +2,5 @@ apiVersion: onepassword.com/v1
|
|||||||
kind: OnePasswordItem
|
kind: OnePasswordItem
|
||||||
metadata:
|
metadata:
|
||||||
name: example
|
name: example
|
||||||
onepasswordoperator/auto_restart: "true"
|
|
||||||
spec:
|
spec:
|
||||||
itemPath: "vaults/<vault_id>/items/<item_id>"
|
itemPath: "vaults/<vault_id>/items/<item_id>"
|
||||||
|
@@ -201,5 +201,5 @@ func (r *ReconcileDeployment) HandleApplyingDeployment(namespace string, annotat
|
|||||||
return fmt.Errorf("Failed to retrieve item: %v", err)
|
return fmt.Errorf("Failed to retrieve item: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, namespace, item)
|
return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, namespace, item, annotations[op.RestartDeploymentsAnnotation])
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
onepasswordv1 "github.com/1Password/onepassword-operator/pkg/apis/onepassword/v1"
|
onepasswordv1 "github.com/1Password/onepassword-operator/pkg/apis/onepassword/v1"
|
||||||
kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets"
|
kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets"
|
||||||
"github.com/1Password/onepassword-operator/pkg/onepassword"
|
"github.com/1Password/onepassword-operator/pkg/onepassword"
|
||||||
|
op "github.com/1Password/onepassword-operator/pkg/onepassword"
|
||||||
"github.com/1Password/onepassword-operator/pkg/utils"
|
"github.com/1Password/onepassword-operator/pkg/utils"
|
||||||
|
|
||||||
"github.com/1Password/connect-sdk-go/connect"
|
"github.com/1Password/connect-sdk-go/connect"
|
||||||
@@ -143,11 +144,12 @@ func (r *ReconcileOnePasswordItem) removeOnePasswordFinalizerFromOnePasswordItem
|
|||||||
|
|
||||||
func (r *ReconcileOnePasswordItem) HandleOnePasswordItem(resource *onepasswordv1.OnePasswordItem, request reconcile.Request) error {
|
func (r *ReconcileOnePasswordItem) HandleOnePasswordItem(resource *onepasswordv1.OnePasswordItem, request reconcile.Request) error {
|
||||||
secretName := resource.GetName()
|
secretName := resource.GetName()
|
||||||
|
autoRestart := resource.Annotations[op.RestartDeploymentsAnnotation]
|
||||||
|
|
||||||
item, err := onepassword.GetOnePasswordItemByPath(r.opConnectClient, resource.Spec.ItemPath)
|
item, err := onepassword.GetOnePasswordItemByPath(r.opConnectClient, resource.Spec.ItemPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to retrieve item: %v", err)
|
return fmt.Errorf("Failed to retrieve item: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, resource.Namespace, item)
|
return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, resource.Namespace, item, autoRestart)
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/1Password/connect-sdk-go/onepassword"
|
"github.com/1Password/connect-sdk-go/onepassword"
|
||||||
|
"github.com/1Password/onepassword-operator/pkg/utils"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -13,21 +14,30 @@ import (
|
|||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const onepasswordPrefix = "onepasswordoperator"
|
const OnepasswordPrefix = "onepasswordoperator"
|
||||||
const NameAnnotation = onepasswordPrefix + "/item-name"
|
const NameAnnotation = OnepasswordPrefix + "/item-name"
|
||||||
const VersionAnnotation = onepasswordPrefix + "/item-version"
|
const VersionAnnotation = OnepasswordPrefix + "/item-version"
|
||||||
const restartAnnotation = onepasswordPrefix + "/lastRestarted"
|
const restartAnnotation = OnepasswordPrefix + "/lastRestarted"
|
||||||
const ItemPathAnnotation = onepasswordPrefix + "/item-path"
|
const ItemPathAnnotation = OnepasswordPrefix + "/item-path"
|
||||||
|
const RestartDeploymentsAnnotation = OnepasswordPrefix + "/auto_restart"
|
||||||
|
|
||||||
var log = logf.Log
|
var log = logf.Log
|
||||||
|
|
||||||
func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretName, namespace string, item *onepassword.Item) error {
|
func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretName, namespace string, item *onepassword.Item, autoRestart string) error {
|
||||||
|
|
||||||
itemVersion := fmt.Sprint(item.Version)
|
itemVersion := fmt.Sprint(item.Version)
|
||||||
annotations := map[string]string{
|
annotations := map[string]string{
|
||||||
VersionAnnotation: itemVersion,
|
VersionAnnotation: itemVersion,
|
||||||
ItemPathAnnotation: fmt.Sprintf("vaults/%v/items/%v", item.Vault.ID, item.ID),
|
ItemPathAnnotation: fmt.Sprintf("vaults/%v/items/%v", item.Vault.ID, item.ID),
|
||||||
}
|
}
|
||||||
|
if autoRestart != "" {
|
||||||
|
_, err := utils.StringToBool(autoRestart)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Error parsing %v annotation on Secret %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, secretName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
annotations[RestartDeploymentsAnnotation] = autoRestart
|
||||||
|
}
|
||||||
secret := BuildKubernetesSecretFromOnePasswordItem(secretName, namespace, annotations, *item)
|
secret := BuildKubernetesSecretFromOnePasswordItem(secretName, namespace, annotations, *item)
|
||||||
|
|
||||||
currentSecret := &corev1.Secret{}
|
currentSecret := &corev1.Secret{}
|
||||||
|
@@ -13,6 +13,8 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const restartDeploymentAnnotation = "false"
|
||||||
|
|
||||||
type k8s struct {
|
type k8s struct {
|
||||||
clientset kubernetes.Interface
|
clientset kubernetes.Interface
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,7 @@ func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) {
|
|||||||
item.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
item.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
||||||
|
|
||||||
kubeClient := fake.NewFakeClient()
|
kubeClient := fake.NewFakeClient()
|
||||||
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item)
|
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -53,7 +55,7 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) {
|
|||||||
item.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
item.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
||||||
|
|
||||||
kubeClient := fake.NewFakeClient()
|
kubeClient := fake.NewFakeClient()
|
||||||
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item)
|
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -64,7 +66,7 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) {
|
|||||||
newItem.Version = 456
|
newItem.Version = 456
|
||||||
newItem.Vault.ID = "hfnjvi6aymbsnfc2xeeoheizda"
|
newItem.Vault.ID = "hfnjvi6aymbsnfc2xeeoheizda"
|
||||||
newItem.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
newItem.ID = "h46bb3jddvay7nxopfhvlwg35q"
|
||||||
err = CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &newItem)
|
err = CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &newItem, restartDeploymentAnnotation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error: %v", err)
|
t.Errorf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@@ -125,6 +127,10 @@ func compareAnnotationsToItem(annotations map[string]string, item onepassword.It
|
|||||||
if annotations[VersionAnnotation] != fmt.Sprint(item.Version) {
|
if annotations[VersionAnnotation] != fmt.Sprint(item.Version) {
|
||||||
t.Errorf("Expected annotation version to be %v but was %v", item.Version, annotations[VersionAnnotation])
|
t.Errorf("Expected annotation version to be %v but was %v", item.Version, annotations[VersionAnnotation])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if annotations[RestartDeploymentsAnnotation] != "false" {
|
||||||
|
t.Errorf("Expected restart deployments annotation to be %v but was %v", restartDeploymentAnnotation, RestartDeploymentsAnnotation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareFields(actualFields []*onepassword.ItemField, secretData map[string][]byte, t *testing.T) {
|
func compareFields(actualFields []*onepassword.ItemField, secretData map[string][]byte, t *testing.T) {
|
||||||
|
@@ -3,11 +3,10 @@ package onepassword
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets"
|
kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets"
|
||||||
|
"github.com/1Password/onepassword-operator/pkg/utils"
|
||||||
|
|
||||||
"github.com/1Password/connect-sdk-go/connect"
|
"github.com/1Password/connect-sdk-go/connect"
|
||||||
"github.com/1Password/connect-sdk-go/onepassword"
|
"github.com/1Password/connect-sdk-go/onepassword"
|
||||||
@@ -184,9 +183,9 @@ func isSecretSetForAutoRestart(secret *corev1.Secret, deployment *appsv1.Deploym
|
|||||||
return isDeploymentSetForAutoRestart(deployment, setForAutoRestartByNamespace)
|
return isDeploymentSetForAutoRestart(deployment, setForAutoRestartByNamespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
restartDeploymentBool, err := stringToBool(restartDeployment)
|
restartDeploymentBool, err := utils.StringToBool(restartDeployment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Error parsing %v annotation on Deployment %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, deployment.Name)
|
log.Error(err, "Error parsing %v annotation on Secret %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, secret.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return restartDeploymentBool
|
return restartDeploymentBool
|
||||||
@@ -199,7 +198,7 @@ func isDeploymentSetForAutoRestart(deployment *appsv1.Deployment, setForAutoRest
|
|||||||
return setForAutoRestartByNamespace[deployment.Namespace]
|
return setForAutoRestartByNamespace[deployment.Namespace]
|
||||||
}
|
}
|
||||||
|
|
||||||
restartDeploymentBool, err := stringToBool(restartDeployment)
|
restartDeploymentBool, err := utils.StringToBool(restartDeployment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Error parsing %v annotation on Deployment %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, deployment.Name)
|
log.Error(err, "Error parsing %v annotation on Deployment %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, deployment.Name)
|
||||||
return false
|
return false
|
||||||
@@ -214,18 +213,10 @@ func (h *SecretUpdateHandler) isNamespaceSetToAutoRestart(namespace *corev1.Name
|
|||||||
return h.shouldAutoRestartDeploymentsGlobal
|
return h.shouldAutoRestartDeploymentsGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
restartDeploymentBool, err := stringToBool(restartDeployment)
|
restartDeploymentBool, err := utils.StringToBool(restartDeployment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Error parsing %v annotation on Namespace %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, namespace.Name)
|
log.Error(err, "Error parsing %v annotation on Namespace %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, namespace.Name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return restartDeploymentBool
|
return restartDeploymentBool
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringToBool(str string) (bool, error) {
|
|
||||||
restartDeploymentBool, err := strconv.ParseBool(strings.ToLower(str))
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return restartDeploymentBool, nil
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func ContainsString(slice []string, s string) bool {
|
func ContainsString(slice []string, s string) bool {
|
||||||
for _, item := range slice {
|
for _, item := range slice {
|
||||||
if item == s {
|
if item == s {
|
||||||
@@ -18,3 +23,11 @@ func RemoveString(slice []string, s string) (result []string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToBool(str string) (bool, error) {
|
||||||
|
restartDeploymentBool, err := strconv.ParseBool(strings.ToLower(str))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return restartDeploymentBool, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user