2018-04-13 12:31:46 +00:00
|
|
|
/*
|
|
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package cephfs
|
|
|
|
|
|
|
|
import (
|
2018-08-28 08:13:53 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2018-04-13 12:31:46 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2019-01-28 13:59:16 +00:00
|
|
|
|
|
|
|
"github.com/golang/glog"
|
2018-04-13 12:31:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2018-07-28 08:24:07 +00:00
|
|
|
cephUserPrefix = "user-"
|
2018-04-13 12:31:46 +00:00
|
|
|
cephEntityClientPrefix = "client."
|
|
|
|
)
|
|
|
|
|
|
|
|
type cephEntityCaps struct {
|
|
|
|
Mds string `json:"mds"`
|
|
|
|
Mon string `json:"mon"`
|
|
|
|
Osd string `json:"osd"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type cephEntity struct {
|
|
|
|
Entity string `json:"entity"`
|
|
|
|
Key string `json:"key"`
|
|
|
|
Caps cephEntityCaps `json:"caps"`
|
|
|
|
}
|
|
|
|
|
2018-08-28 08:13:53 +00:00
|
|
|
func (ent *cephEntity) toCredentials() *credentials {
|
|
|
|
return &credentials{
|
|
|
|
id: ent.Entity[len(cephEntityClientPrefix):],
|
|
|
|
key: ent.Key,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-17 05:46:32 +00:00
|
|
|
func getCephUserName(volID volumeID) string {
|
|
|
|
return cephUserPrefix + string(volID)
|
2018-04-13 12:31:46 +00:00
|
|
|
}
|
|
|
|
|
2019-01-17 05:46:32 +00:00
|
|
|
func getCephUser(adminCr *credentials, volID volumeID) (*cephEntity, error) {
|
|
|
|
entityName := cephEntityClientPrefix + getCephUserName(volID)
|
2018-08-28 08:13:53 +00:00
|
|
|
|
2018-04-13 12:31:46 +00:00
|
|
|
var ents []cephEntity
|
2018-08-28 08:13:53 +00:00
|
|
|
args := [...]string{
|
2019-01-17 05:46:32 +00:00
|
|
|
"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
|
2018-08-28 08:13:53 +00:00
|
|
|
"get", entityName,
|
|
|
|
}
|
|
|
|
|
|
|
|
out, err := execCommand("ceph", args[:]...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("cephfs: ceph failed with following error: %s\ncephfs: ceph output: %s", err, out)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Workaround for output from `ceph auth get`
|
|
|
|
// Contains non-json data: "exported keyring for ENTITY\n\n"
|
|
|
|
offset := bytes.Index(out, []byte("[{"))
|
2018-04-13 12:31:46 +00:00
|
|
|
|
2019-01-17 07:37:40 +00:00
|
|
|
if err = json.NewDecoder(bytes.NewReader(out[offset:])).Decode(&ents); err != nil {
|
2018-08-28 08:13:53 +00:00
|
|
|
return nil, fmt.Errorf("failed to decode json: %v", err)
|
2018-04-13 12:31:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(ents) != 1 {
|
2018-08-28 08:13:53 +00:00
|
|
|
return nil, fmt.Errorf("got unexpected number of entities for %s: expected 1, got %d", entityName, len(ents))
|
2018-04-13 12:31:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &ents[0], nil
|
|
|
|
}
|
|
|
|
|
2019-01-17 05:46:32 +00:00
|
|
|
func createCephUser(volOptions *volumeOptions, adminCr *credentials, volID volumeID) (*cephEntity, error) {
|
2018-04-13 12:31:46 +00:00
|
|
|
caps := cephEntityCaps{
|
2019-01-17 05:46:32 +00:00
|
|
|
Mds: fmt.Sprintf("allow rw path=%s", getVolumeRootPathCeph(volID)),
|
2018-04-13 12:31:46 +00:00
|
|
|
Mon: "allow r",
|
2019-01-17 05:46:32 +00:00
|
|
|
Osd: fmt.Sprintf("allow rw pool=%s namespace=%s", volOptions.Pool, getVolumeNamespace(volID)),
|
2018-04-13 12:31:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var ents []cephEntity
|
|
|
|
args := [...]string{
|
2019-01-17 05:46:32 +00:00
|
|
|
"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
|
|
|
|
"get-or-create", cephEntityClientPrefix + getCephUserName(volID),
|
2018-04-13 12:31:46 +00:00
|
|
|
"mds", caps.Mds,
|
|
|
|
"mon", caps.Mon,
|
|
|
|
"osd", caps.Osd,
|
|
|
|
}
|
|
|
|
|
2019-01-17 07:59:29 +00:00
|
|
|
if err := execCommandJSON(&ents, args[:]...); err != nil {
|
2018-04-13 12:31:46 +00:00
|
|
|
return nil, fmt.Errorf("error creating ceph user: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ents[0], nil
|
|
|
|
}
|
|
|
|
|
2019-01-17 05:46:32 +00:00
|
|
|
func deleteCephUser(adminCr *credentials, volID volumeID) error {
|
|
|
|
userID := getCephUserName(volID)
|
2018-04-13 12:31:46 +00:00
|
|
|
|
2018-06-12 15:03:45 +00:00
|
|
|
args := [...]string{
|
2019-01-17 05:46:32 +00:00
|
|
|
"-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
|
|
|
|
"auth", "rm", cephEntityClientPrefix + userID,
|
2018-06-12 15:03:45 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 13:59:16 +00:00
|
|
|
var err error
|
|
|
|
if err = execCommandAndValidate("ceph", args[:]...); err != nil {
|
2018-04-13 12:31:46 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-01-28 13:59:16 +00:00
|
|
|
keyringPath := getCephKeyringPath(volID, userID)
|
|
|
|
if err = os.Remove(keyringPath); err != nil {
|
|
|
|
glog.Errorf("failed to remove keyring file %s with error %s", keyringPath, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
secretPath := getCephSecretPath(volID, userID)
|
|
|
|
if err = os.Remove(secretPath); err != nil {
|
|
|
|
glog.Errorf("failed to remove secret file %s with error %s", secretPath, err)
|
|
|
|
}
|
2018-04-13 12:31:46 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|