Skip to content

Commit b410fa5

Browse files
authored
feat(hook): load hook configuration using file instead of configmap (#120)
This commit does the following changes: * updating provisioner to load hook configuration from pre-defined file '/etc/nfs-provisioner-hook/config' * updating hook design document to include changes on loading hook configuration using file * bdd(hook): updating hook BDD test to mount configmap in nfs-provisioner deployment Signed-off-by: mayank <mayank.patel@mayadata.io>
1 parent 1ae6401 commit b410fa5

File tree

6 files changed

+125
-62
lines changed

6 files changed

+125
-62
lines changed

deploy/kubectl/openebs-nfs-provisioner.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ spec:
140140
- name: OPENEBS_IO_NFS_SERVER_IMG
141141
value: openebs/nfs-server-alpine:ci
142142
# OPENEBS_IO_NFS_HOOK_CONFIGMAP defines configmap to use for hook
143-
#- name: OPENEBS_IO_NFS_HOOK_CONFIGMAP
144-
# value: "nfs-hook"
145143
# LEADER_ELECTION_ENABLED is used to enable/disable leader election. By default
146144
# leader election is enabled.
147145
#- name: LEADER_ELECTION_ENABLED
@@ -178,6 +176,16 @@ spec:
178176
limits:
179177
cpu: 200m
180178
memory: 200M
179+
# uncomment below lines to use nfs-hooks
180+
# volumeMounts:
181+
# - mountPath: /etc/nfs-provisioner
182+
# name: hook-config
183+
# uncomment below lines to use nfs-hooks
184+
# volumes:
185+
# - name: hook-config
186+
# configMap:
187+
# name: hook-config
188+
181189
---
182190
#Sample storage classes for OpenEBS Local PV
183191
apiVersion: storage.k8s.io/v1

docs/design/hooks.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ I should be able to configure nfs-provisioner to set the provided annotation and
3939
I should be able to configure nfs-provisioner to set the provided annotation and finalizer on specific resources created by nfs-provisioner.
4040

4141
### Proposed Implementation
42-
NFS-Provisioner will use user-provided Configmap to learn hooks configuration. These hooks will be executed on volume provisioning or deleting events to set the given information on provided resources.
42+
NFS-Provisioner will use user-provided Config file to learn hooks configuration. These hooks will be executed on volume provisioning or deleting events to set the given information on provided resources.
4343

4444
### High-Level Design
45-
User will deploy nfs-provisioner with Configmap having information about hook information. This Configmap should exist in the same namespace in which nfs-provisioner is deployed. Sample nfs-provisioner deployment config is as below:
45+
NFS Provisioner will load the hook configuration from the file located at pre-defined path. User can create a configmap with hook configuration and mount it at pre-defined path. Sample nfs-provisioner deployment config is as below:
4646

4747
```yaml
4848
spec:
@@ -61,9 +61,16 @@ User will deploy nfs-provisioner with Configmap having information about hook in
6161
- test `pgrep "^provisioner-nfs.*"` = 1
6262
initialDelaySeconds: 30
6363
periodSeconds: 60
64+
volumeMounts:
65+
- mountPath: /etc/nfs-provisioner
66+
name: hook-config
67+
volumes:
68+
- name: hook-config
69+
configMap:
70+
name: hook-config
6471
```
6572
66-
User needs to provide Configmap name as a value of `OPENEBS_IO_NFS_HOOK_CONFIGMAP` environment variable.
73+
User needs to create a configmap named 'hook-config' in provisioner's namespace.
6774
6875
### Low-Level Design
6976
#### Hook Definition
@@ -192,7 +199,7 @@ type Provisioner struct {
192199
```
193200

194201
#### Configmap structure
195-
User needs to create hook Configmap resource in nfs-provisioner namespace. Hook configuration needs to be provided in data field **config**.
202+
User needs to create hook Configmap resource in nfs-provisioner namespace. Hook configuration needs to be provided in data field **hook-config**.
196203
Configmap needs be defined as below:
197204

198205
```yaml
@@ -202,7 +209,7 @@ metadata:
202209
name: hook-config
203210
namespace: openebs
204211
data:
205-
config: |
212+
hook-config: |
206213
hooks:
207214
addOrUpdateEntriesOnCreateVolumeEvent:
208215
backendPV:
@@ -274,7 +281,8 @@ For initial development, following template variables will be supported:
274281
275282
276283
#### NFS Provisioner changes
277-
If NFS Provisioner is configured with environment variable **OPENEBS_IO_NFS_HOOK_CONFIGMAP** set then Provisioner needs to lookup the provided Configmap in nfs-provisioner namespace. If Configmap exists then provisioner needs to initialize **Provisioner** with hook configuration provided in Configmap.
284+
NFS Provisioner will initialize the hook configuration using pre-defined hook config file(*/etc/nfs-provisioner/hook-config*). If hook config file is not found then NFS Provisioner will skip the initialization of hooks and continue with provisioning.
285+
278286
NFS Provisioner executes two events, volume provisioning, and volume deletion. On these two events provisioner needs to execute all the hooks as per the given hook Action.
279287
280288
NFS Provisioner will initialize the hook on startup. If Hook configuration is invalid then NFS Provisioner will throw the error and exit.

provisioner/config.go

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ package provisioner
1919

2020
import (
2121
"context"
22+
"github.com/pkg/errors"
23+
"io/ioutil"
24+
"os"
2225
"strconv"
2326
"strings"
2427

2528
"github.com/ghodss/yaml"
29+
nfshook "github.com/openebs/dynamic-nfs-provisioner/pkg/hook"
2630
mconfig "github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
2731
cast "github.com/openebs/maya/pkg/castemplate/v1alpha1"
2832
"github.com/openebs/maya/pkg/util"
29-
"k8s.io/klog/v2"
30-
31-
//"github.com/pkg/errors"
32-
errors "github.com/pkg/errors"
3333
v1 "k8s.io/api/core/v1"
3434
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35-
//storagev1 "k8s.io/api/storage/v1"
35+
"k8s.io/klog/v2"
3636
)
3737

3838
const (
@@ -66,6 +66,15 @@ const (
6666

6767
// NFSServerResourceLimits holds key name that represent NFS Resource Limits
6868
NFSServerResourceLimits = "NFSServerResourceLimits"
69+
70+
// HookConfigFileName represent file name for hook configuration
71+
HookConfigFileName = "hook-config"
72+
73+
// ConfigDirectory defines directory to store config files specific to NFS provisioner
74+
ConfigDirectory = "/etc/nfs-provisioner"
75+
76+
// HookConfigFilePath defines path for hook config file
77+
HookConfigFilePath = ConfigDirectory + "/" + HookConfigFileName
6978
)
7079

7180
const (
@@ -265,3 +274,49 @@ func GetNFSServerTypeFromPV(pv *v1.PersistentVolume) string {
265274
//TODO extract this from PV annotations
266275
return "kernel"
267276
}
277+
278+
// hookConfigFileExist check if hook config file exists or not
279+
func hookConfigFileExist() (bool, error) {
280+
// HookConfigFilePath
281+
_, err := os.Stat(HookConfigFilePath)
282+
if err == nil {
283+
return true, nil
284+
}
285+
286+
if os.IsNotExist(err) {
287+
return false, nil
288+
}
289+
290+
return false, err
291+
}
292+
293+
// initializeHook read the hook config file and update the given hook variable
294+
// return value:
295+
// - nil
296+
// - If hook config file doesn't exists
297+
// - If hook config file is parsed and given hook variable is updated
298+
// - error
299+
// - If hook config is invalid
300+
func initializeHook(hook **nfshook.Hook) error {
301+
hookFileExists, err := hookConfigFileExist()
302+
if err != nil {
303+
return errors.Errorf("failed to check hook config file, err=%s", err)
304+
}
305+
306+
if !hookFileExists {
307+
return nil
308+
}
309+
310+
data, err := ioutil.ReadFile(HookConfigFilePath)
311+
if err != nil {
312+
return errors.Errorf("failed to read hook config file, err=%s", err)
313+
}
314+
315+
hookObj, err := nfshook.ParseHooks(data)
316+
if err != nil {
317+
return err
318+
}
319+
320+
*hook = hookObj
321+
return nil
322+
}

provisioner/env.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ const (
6060

6161
// NFSServerImagePullSecret defines the env name to store the name of the image pull secret
6262
NFSServerImagePullSecret menv.ENVKey = "OPENEBS_IO_NFS_SERVER_IMAGE_PULL_SECRET"
63-
64-
// NFSHookConfigMapName defines env variable name to hold hook configmap name
65-
NFSHookConfigMapName menv.ENVKey = "OPENEBS_IO_NFS_HOOK_CONFIGMAP"
6663
)
6764

6865
var (
@@ -111,7 +108,3 @@ func getBackendPvcTimeout() string {
111108
func getNfsServerImagePullSecret() string {
112109
return menv.GetOrDefault(NFSServerImagePullSecret, "")
113110
}
114-
115-
func getHookConfigMapName() string {
116-
return menv.Get(NFSHookConfigMapName)
117-
}

provisioner/provisioner.go

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,15 @@ import (
5151
v1 "k8s.io/api/core/v1"
5252
"k8s.io/apimachinery/pkg/api/resource"
5353
kubeinformers "k8s.io/client-go/informers"
54-
"k8s.io/client-go/kubernetes"
5554
listersv1 "k8s.io/client-go/listers/core/v1"
5655
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
5756

5857
nfshook "github.com/openebs/dynamic-nfs-provisioner/pkg/hook"
59-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
6058
clientset "k8s.io/client-go/kubernetes"
6159
)
6260

6361
var (
6462
NodeAffinityRulesMismatchEvent = "No matching nodes found for given affinity rules"
65-
66-
// HookConfigMapDataField defines configmap data key for hook config
67-
HookConfigMapDataField = "config"
6863
)
6964

7065
// NewProvisioner will create a new Provisioner object and initialize
@@ -89,12 +84,9 @@ func NewProvisioner(ctx context.Context, kubeClient *clientset.Clientset) (*Prov
8984
nfsServerNs := getNfsServerNamespace()
9085

9186
var hook *nfshook.Hook
92-
hookCmap := getHookConfigMapName()
93-
if hookCmap != "" {
94-
err := initializeHook(kubeClient, ctx, namespace, hookCmap, &hook)
95-
if err != nil {
96-
return nil, errors.Errorf("failed to initialize hooks, err={%s}", err)
97-
}
87+
err = initializeHook(&hook)
88+
if err != nil {
89+
return nil, errors.Errorf("failed to initialize hooks, err={%s}", err)
9890
}
9991

10092
pvTracker := NewProvisioningTracker()
@@ -302,22 +294,3 @@ func sendEventOrIgnore(pvcName, pvName, capacity, stgType, method string) {
302294
SetCategory(method).
303295
SetVolumeCapacity(capacity).Send()
304296
}
305-
306-
func initializeHook(kubeClient kubernetes.Interface, ctx context.Context, namespace, hookCmap string, hook **nfshook.Hook) error {
307-
cmapObj, err := kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, hookCmap, metav1.GetOptions{})
308-
if err != nil {
309-
return errors.Wrapf(err, "failed to fetch hook configmap=%s", hookCmap)
310-
}
311-
312-
data, ok := cmapObj.Data[HookConfigMapDataField]
313-
if !ok {
314-
return errors.Errorf("hook configmap=%s doesn't have data field=%s", hookCmap, HookConfigMapDataField)
315-
}
316-
317-
hookObj, err := nfshook.ParseHooks([]byte(data))
318-
if err != nil {
319-
return err
320-
}
321-
*hook = hookObj
322-
return nil
323-
}

tests/nfs_hook_test.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ var _ = Describe("TEST NFS HOOK", func() {
112112

113113
backendPVName = ""
114114
hookConfigMapName = "nfs-hook"
115+
hookVolumeName = "nfs-hook-vol"
115116
hook *nfshook.Hook
116117
NFSProvisionerName = "openebs-nfs-provisioner"
117118
openebsNamespace = "openebs"
@@ -128,7 +129,7 @@ var _ = Describe("TEST NFS HOOK", func() {
128129
cmap.Name = hookConfigMapName
129130
cmap.Namespace = openebsNamespace
130131
cmap.Data = map[string]string{
131-
"config": string(data),
132+
provisioner.HookConfigFileName: string(data),
132133
}
133134

134135
err = Client.createConfigMap(&cmap)
@@ -154,15 +155,26 @@ var _ = Describe("TEST NFS HOOK", func() {
154155
)
155156

156157
By("updating the deployment")
157-
nsEnv := corev1.EnvVar{
158-
Name: string(provisioner.NFSHookConfigMapName),
159-
Value: hookConfigMapName,
160-
}
158+
deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes,
159+
corev1.Volume{
160+
Name: hookVolumeName,
161+
VolumeSource: corev1.VolumeSource{
162+
ConfigMap: &corev1.ConfigMapVolumeSource{
163+
LocalObjectReference: corev1.LocalObjectReference{
164+
Name: hookConfigMapName,
165+
},
166+
},
167+
},
168+
},
169+
)
161170

162-
deploy.Spec.Template.Spec.Containers[0].Env = append(
163-
deploy.Spec.Template.Spec.Containers[0].Env,
164-
nsEnv,
171+
deploy.Spec.Template.Spec.Containers[0].VolumeMounts = append(deploy.Spec.Template.Spec.Containers[0].VolumeMounts,
172+
corev1.VolumeMount{
173+
Name: hookVolumeName,
174+
MountPath: provisioner.ConfigDirectory,
175+
},
165176
)
177+
166178
_, err = Client.updateDeployment(deploy)
167179
Expect(err).To(BeNil(), "while updating deployment %s/%s", openebsNamespace, NFSProvisionerName)
168180

@@ -335,16 +347,30 @@ var _ = Describe("TEST NFS HOOK", func() {
335347
Expect(err).To(BeNil(), "while fetching deployment %s/%s", openebsNamespace, NFSProvisionerName)
336348

337349
By("updating the provisioner deployment")
350+
// Removing volumeMount
338351
idx := 0
339-
for idx < len(deploy.Spec.Template.Spec.Containers[0].Env) {
340-
if deploy.Spec.Template.Spec.Containers[0].Env[idx].Name == string(provisioner.NFSHookConfigMapName) {
352+
for idx < len(deploy.Spec.Template.Spec.Containers[0].VolumeMounts) {
353+
if deploy.Spec.Template.Spec.Containers[0].VolumeMounts[idx].Name == hookVolumeName {
354+
break
355+
}
356+
idx++
357+
}
358+
deploy.Spec.Template.Spec.Containers[0].VolumeMounts = append(deploy.Spec.Template.Spec.Containers[0].VolumeMounts[:idx],
359+
deploy.Spec.Template.Spec.Containers[0].VolumeMounts[idx+1:]...)
360+
361+
// Removing volume
362+
idx = 0
363+
for idx < len(deploy.Spec.Template.Spec.Volumes) {
364+
if deploy.Spec.Template.Spec.Volumes[idx].Name == hookVolumeName {
341365
break
342366
}
343367
idx++
344368
}
345-
deploy.Spec.Template.Spec.Containers[0].Env = append(deploy.Spec.Template.Spec.Containers[0].Env[:idx], deploy.Spec.Template.Spec.Containers[0].Env[idx+1:]...)
369+
deploy.Spec.Template.Spec.Volumes = append(deploy.Spec.Template.Spec.Volumes[:idx],
370+
deploy.Spec.Template.Spec.Volumes[idx+1:]...)
371+
346372
_, err = Client.updateDeployment(deploy)
347-
Expect(err).To(BeNil(), "while updateingupdating deployment %s/%s", openebsNamespace, NFSProvisionerName)
373+
Expect(err).To(BeNil(), "while updating deployment %s/%s", openebsNamespace, NFSProvisionerName)
348374

349375
By("waiting for deployment rollout")
350376
err = Client.waitForDeploymentRollout(OpenEBSNamespace, NFSProvisionerName)

0 commit comments

Comments
 (0)