forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
pvsetup.go
183 lines (159 loc) · 5.6 KB
/
pvsetup.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
package openshift
import (
"bytes"
"fmt"
"os"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/serviceaccount"
kapi "k8s.io/kubernetes/pkg/api"
kbatch "k8s.io/kubernetes/pkg/apis/batch"
kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
authorizationtypedclient "github.com/openshift/origin/pkg/authorization/generated/internalclientset/typed/authorization/internalversion"
"github.com/openshift/origin/pkg/oc/bootstrap/docker/errors"
securityclient "github.com/openshift/origin/pkg/security/generated/internalclientset"
)
const (
pvCount = 100
pvSetupJobName = "persistent-volume-setup"
pvInstallerSA = "pvinstaller"
pvSetupNamespace = "default"
pvIgnoreMarkerFile = ".skip_pv"
)
const createPVScript = `#/bin/bash
set -e
function generate_pv() {
local basedir="${1}"
local name="${2}"
cat <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: ${name}
labels:
volume: ${name}
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
- ReadWriteMany
- ReadOnlyMany
hostPath:
path: ${basedir}/${name}
persistentVolumeReclaimPolicy: Recycle
EOF
}
function setup_pv_dir() {
local dir="${1}"
if [[ ! -d "${dir}" ]]; then
mkdir -p "${dir}"
fi
if ! chcon -t svirt_sandbox_file_t "${dir}" &> /dev/null; then
echo "Not setting SELinux content for ${dir}"
fi
chmod 770 "${dir}"
}
function create_pv() {
local basedir="${1}"
local name="${2}"
setup_pv_dir "${basedir}/${name}"
if ! oc get pv "${name}" &> /dev/null; then
generate_pv "${basedir}" "${name}" | oc create -f -
else
echo "persistentvolume ${name} already exists"
fi
}
basedir="%[2]s"
setup_pv_dir "${basedir}/registry"
for i in $(seq -f "%%04g" 1 %[1]d); do
create_pv "${basedir}" "pv${i}"
done
`
// SetupPersistentStorage sets up persistent storage
func (h *Helper) SetupPersistentStorage(authorizationClient authorizationtypedclient.ClusterRoleBindingsGetter, kclient kclientset.Interface, securityClient securityclient.Interface, dir, HostPersistentVolumesDir string) error {
err := h.ensurePVInstallerSA(authorizationClient, kclient, securityClient)
if err != nil {
return err
}
_, err = kclient.Batch().Jobs(pvSetupNamespace).Get(pvSetupJobName, metav1.GetOptions{})
if err == nil {
// Job exists, it should run to completion
return nil
}
if !kerrors.IsNotFound(err) {
return errors.NewError("error retrieving job to setup persistent volumes (%s/%s)", pvSetupNamespace, pvSetupJobName).WithCause(err).WithDetails(h.OriginLog())
}
// check if we need to create pv's
_, err = os.Stat(fmt.Sprintf("%s/%s", HostPersistentVolumesDir, pvIgnoreMarkerFile))
if !os.IsNotExist(err) {
fmt.Printf("Skip persistent volume creation \n")
} else {
setupJob := persistentStorageSetupJob(pvSetupJobName, dir, h.image, pvCount)
if _, err = kclient.Batch().Jobs(pvSetupNamespace).Create(setupJob); err != nil {
return errors.NewError("cannot create job to setup persistent volumes (%s/%s)", pvSetupNamespace, pvSetupJobName).WithCause(err).WithDetails(h.OriginLog())
}
}
return nil
}
func (h *Helper) ensurePVInstallerSA(authorizationClient authorizationtypedclient.ClusterRoleBindingsGetter, kclient kclientset.Interface, securityClient securityclient.Interface) error {
createSA := false
sa, err := kclient.Core().ServiceAccounts(pvSetupNamespace).Get(pvInstallerSA, metav1.GetOptions{})
if err != nil {
if !kerrors.IsNotFound(err) {
return errors.NewError("error retrieving installer service account (%s/%s)", pvSetupNamespace, pvInstallerSA).WithCause(err).WithDetails(h.OriginLog())
}
createSA = true
}
// Create installer SA
if createSA {
sa = &kapi.ServiceAccount{}
sa.Name = pvInstallerSA
_, err = kclient.Core().ServiceAccounts(pvSetupNamespace).Create(sa)
if err != nil {
return errors.NewError("cannot create pvinstaller service account").WithCause(err).WithDetails(h.OriginLog())
}
}
err = AddSCCToServiceAccount(securityClient.Security(), "privileged", "pvinstaller", "default", &bytes.Buffer{})
if err != nil {
return errors.NewError("cannot add privileged SCC to pvinstaller service account").WithCause(err).WithDetails(h.OriginLog())
}
saUser := serviceaccount.MakeUsername(pvSetupNamespace, pvInstallerSA)
err = AddClusterRole(authorizationClient, "cluster-admin", saUser)
if err != nil {
return errors.NewError("cannot add cluster role to service account (%s/%s)", pvSetupNamespace, pvInstallerSA).WithCause(err).WithDetails(h.OriginLog())
}
return nil
}
func persistentStorageSetupJob(name, dir, image string, pvCount int) *kbatch.Job {
// Job volume
volume := kapi.Volume{}
volume.Name = "pvdir"
volume.HostPath = &kapi.HostPathVolumeSource{Path: dir}
// Volume mount
mount := kapi.VolumeMount{}
mount.Name = "pvdir"
mount.MountPath = dir
// Job container
container := kapi.Container{}
container.Name = "storage-setup-job"
container.Image = image
container.Command = []string{"/bin/bash", "-c", fmt.Sprintf(createPVScript, pvCount, dir)}
privileged := true
container.SecurityContext = &kapi.SecurityContext{
Privileged: &privileged,
}
container.VolumeMounts = []kapi.VolumeMount{mount}
// Job
completions := int32(1)
deadline := int64(60 * 20)
job := &kbatch.Job{}
job.Name = name
job.Spec.Completions = &completions
job.Spec.ActiveDeadlineSeconds = &deadline
job.Spec.Template.Spec.Volumes = []kapi.Volume{volume}
job.Spec.Template.Spec.RestartPolicy = kapi.RestartPolicyNever
job.Spec.Template.Spec.ServiceAccountName = "pvinstaller"
job.Spec.Template.Spec.Containers = []kapi.Container{container}
return job
}