Files
my-rook-config/pkg/operator/ceph/config/config.go
T
Sébastien Han d4c48bb293 ceph: expose /var/log/ceph to the host
It's quite convinient to expose /var/log/ceph so that we can decide to
activate logs locally on the machine and see what's going on.
This is only a placeholder when a daemon is stuck crashlooping and we
want to allow administrator to gather log files.
We still do not log on file but this can be activated via a config
option passed to the centralized config option store.

For some daemons, which typically do not store any data (rgw, rbd-mirror
and mds) we had to propagate dataDirHostPath from the cluster spec to
each creation call so that the bindmount can happen.

Fixes: https://github.com/rook/rook/issues/2881
Signed-off-by: Sébastien Han <seb@redhat.com>
2019-04-15 10:47:09 +02:00

218 lines
7.6 KiB
Go

/*
Copyright 2019 The Rook Authors. All rights reserved.
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 config provides methods for generating the Ceph config for a Ceph cluster and for
// producing a "ceph.conf" compatible file from the config as well as Ceph command line-compatible
// flags.
package config
import (
"fmt"
"strings"
"github.com/coreos/pkg/capnslog"
"github.com/go-ini/ini"
"github.com/rook/rook/pkg/clusterd"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var logger = capnslog.NewPackageLogger("github.com/rook/rook", "op-config")
// DaemonType defines the type of a daemon. e.g., mon, mgr, osd, mds, rgw
type DaemonType string
const (
// MonType defines the mon DaemonType
MonType DaemonType = "mon"
// MgrType defines the mgr DaemonType
MgrType DaemonType = "mgr"
// OsdType defines the osd DaemonType
OsdType DaemonType = "osd"
// MdsType defines the mds DaemonType
MdsType DaemonType = "mds"
// RgwType defines the rgw DaemonType
RgwType DaemonType = "rgw"
// RbdMirrorType defines the rbd-mirror DaemonType
RbdMirrorType DaemonType = "rbd-mirror"
)
var (
// VarLibCephDir is simply "/var/lib/ceph". It is made overwriteable only for unit tests where it
// may be needed to send data intended for /var/lib/ceph to a temporary test dir.
VarLibCephDir = "/var/lib/ceph"
// EtcCephDir is simply "/etc/ceph". It is made overwriteable only for unit tests where it
// may be needed to send data intended for /etc/ceph to a temporary test dir.
EtcCephDir = "/etc/ceph"
// VarLogCephDir defines Ceph logging directory. It is made overwriteable only for unit tests where it
// may be needed to send data intended for /var/log/ceph to a temporary test dir.
VarLogCephDir = "/var/log/ceph"
)
// Config is a Ceph config struct containing zero or more Ceph config sections.
type Config struct {
sections map[string]*Section
sectionOrder []string
context *clusterd.Context
namespace string
ownerRef *metav1.OwnerReference
dataDirHostPath string
}
// A Section is a collection of zero or more Ceph config key-value pairs.
type Section struct {
configs map[string]string
configOrder []string // allows us to make an ordered dict
}
// normalizeKey converts a key in any format to a key with underscores.
//
// The internal representation of Ceph config keys uses underscores only, where Ceph supports both
// spaces, underscores, and hyphens. This is so that Rook can properly match and override keys even
// when they are specified as "some config key" in one section, "some_config_key" in another
// section, and "some-config-key" in yet another section.
func normalizeKey(key string) string {
return strings.Replace(strings.Replace(key, " ", "_", -1), "-", "_", -1)
}
// NewConfig returns a new, blank Ceph Config.
func NewConfig() *Config {
return &Config{
sections: make(map[string]*Section),
sectionOrder: make([]string, 0, 1), // capacity=1 b/c usually we'll only create [global]
}
}
// Section returns a Ceph config Section with the given name from the Config. If the section does
// not exist, a new empty section is created and returned for the caller's use.
func (c *Config) Section(name string) *Section {
s, ok := c.sections[name]
if !ok {
s = &Section{
configs: make(map[string]string),
configOrder: []string{},
}
c.sections[name] = s
c.sectionOrder = append(c.sectionOrder, name)
}
return s
}
// Set sets the Ceph config key to the given value. Set accepts Ceph keys in both
// space-separated-words and underscore-separated-words formats. Set modifies the section in-place
// and also returns the same modified-in-place Section to give flexibility of usage.
//
// NOTE that if a config item in a map should have quotes around it, they will have to be added to
// the string explicitly. e.g., a Value of " test " will be interpreted as as 'Key = test', whereas
// a Value of "\" test \"" will be interpreted as 'Key = " test "'
func (s *Section) Set(key, value string) *Section {
key = normalizeKey(key)
_, ok := s.configs[key]
if !ok {
s.configOrder = append(s.configOrder, key)
}
s.configs[key] = value
return s
}
// Merge modifies the Section in-place adding values from the overrides Section and overriding
// existing values with the new value in overrides.
func (s *Section) Merge(overrides *Section) {
for _, k := range overrides.configOrder {
if v, ok := overrides.configs[k]; ok {
s.Set(k, v)
continue
}
// this condition should never exist except in case of some kind of mem corruption
logger.Errorf("override config key %s could not be applied. possible struct corruption of overrides: %+v", k, overrides)
}
}
// Merge modifies the Config in-place, adding Sections from the overrides config, and overriding
// existing Sections with Section values from overrides.
func (c *Config) Merge(overrides *Config) {
for _, hdr := range overrides.sectionOrder {
if s, ok := overrides.sections[hdr]; ok {
c.Section(hdr).Merge(s)
continue
}
// this condition should never exist except in case of some kind of mem corruption
logger.Errorf("override section %s could not be applied. possible struct corruption of overrides: %+v", hdr, overrides)
}
}
// IniFile converts the Ceph Config to an *ini.File.
func (c *Config) IniFile() (*ini.File, error) {
f := ini.Empty()
for _, hdr := range c.sectionOrder {
sec, ok := c.sections[hdr]
if !ok {
return nil, fmt.Errorf("Error: section header %s not found: %+v", hdr, c)
}
s, err := f.NewSection(hdr)
if err != nil {
return nil, fmt.Errorf("Error converting config to ini file text: %+v. %+v", c, err)
}
for _, k := range sec.configOrder {
v, ok := sec.configs[k]
if !ok {
return nil, fmt.Errorf("Error: config %s not found in section %s: %+v", k, hdr, sec)
}
if _, err := s.NewKey(k, v); err != nil {
return nil, fmt.Errorf("Error converting config to ini file text: %+v. %+v", c, err)
}
}
}
return f, nil
}
// NewFlag returns the key-value pair in the format of a Ceph command line-compatible flag.
func NewFlag(key, value string) string {
// A flag is a normalized key with underscores replaced by dashes.
// "debug default" ~normalize~> "debug_default" ~to~flag~> "debug-default"
n := normalizeKey(key)
f := strings.Replace(n, "_", "-", -1)
return fmt.Sprintf("--%s=%s", f, value)
}
// GlobalFlags converts the Config's 'global' Section to a list of command line flag strings which
// can be used with Kubernetes container specs for Ceph daemons.
//
// It should never be necessary to get flags for anything but the 'global' config section,
// otherwise, Rook will have to determine which sections apply for a given Ceph daemon. Does
// 'mon.a' apply to 'mon.b'? 'mon.aa'? 'osd.0'? The logic would be prone to errors, so only allow
// the 'global' section to be converted to flags.
func (c *Config) GlobalFlags() []string {
f := []string{}
g := c.Section("global")
for _, k := range g.configOrder {
if v, ok := g.configs[k]; ok {
f = append(f, NewFlag(k, v))
continue
}
// this condition should never exist except in case of some kind of mem corruption
logger.Errorf("override config key %s could not be applied. possible struct corruption of section: %+v", k, g)
}
return f
}