Files
my-rook-config/pkg/operator/mgr/mgr.go
T
Alexander Trost 434e978b4d Added v1.ResourceRequirements to Cluster Spec
Added per node resource override/merge

Added unit tests to check for specs

Added documentation for resource requests/limits
2017-11-16 19:56:58 +01:00

210 lines
5.9 KiB
Go

/*
Copyright 2016 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 mgr for the Ceph manager.
package mgr
import (
"fmt"
"github.com/coreos/pkg/capnslog"
"github.com/rook/rook/pkg/ceph/client"
"github.com/rook/rook/pkg/clusterd"
"github.com/rook/rook/pkg/operator/k8sutil"
opmon "github.com/rook/rook/pkg/operator/mon"
"k8s.io/api/core/v1"
extensions "k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var logger = capnslog.NewPackageLogger("github.com/rook/rook", "op-mgr")
const (
appName = "rook-ceph-mgr"
keyringName = "keyring"
)
// Cluster is the ceph mgr manager
type Cluster struct {
Namespace string
Version string
Replicas int
placement k8sutil.Placement
context *clusterd.Context
dataDir string
HostNetwork bool
resources v1.ResourceRequirements
}
// New creates an instance of the mgr
func New(context *clusterd.Context, namespace, version string, placement k8sutil.Placement, hostNetwork bool, resources v1.ResourceRequirements) *Cluster {
return &Cluster{
context: context,
Namespace: namespace,
placement: placement,
Version: version,
Replicas: 2,
dataDir: k8sutil.DataDir,
HostNetwork: hostNetwork,
resources: resources,
}
}
// Start the mgr instance
func (c *Cluster) Start() error {
logger.Infof("start running mgr")
for i := 0; i < c.Replicas; i++ {
name := fmt.Sprintf("%s%d", appName, i)
err := c.createKeyring(c.Namespace, name)
if err != nil {
return fmt.Errorf("failed to create mgr keyring. %+v", err)
}
// start the deployment
deployment := c.makeDeployment(name)
_, err = c.context.Clientset.ExtensionsV1beta1().Deployments(c.Namespace).Create(deployment)
if err != nil {
if !errors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create mgr deployment. %+v", err)
}
logger.Infof("%s deployment already exists", name)
} else {
logger.Infof("%s deployment started", name)
}
}
return nil
}
func (c *Cluster) makeDeployment(name string) *extensions.Deployment {
deployment := &extensions.Deployment{}
deployment.Name = name
deployment.Namespace = c.Namespace
podSpec := v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: c.getLabels(),
Annotations: map[string]string{},
},
Spec: v1.PodSpec{
Containers: []v1.Container{c.mgrContainer(name)},
RestartPolicy: v1.RestartPolicyAlways,
Volumes: []v1.Volume{
{Name: k8sutil.DataDirVolume, VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}},
k8sutil.ConfigOverrideVolume(),
},
HostNetwork: c.HostNetwork,
},
}
if c.HostNetwork {
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
}
c.placement.ApplyToPodSpec(&podSpec.Spec)
replicas := int32(1)
deployment.Spec = extensions.DeploymentSpec{Template: podSpec, Replicas: &replicas}
return deployment
}
func (c *Cluster) mgrContainer(name string) v1.Container {
return v1.Container{
Args: []string{
"mgr",
fmt.Sprintf("--config-dir=%s", k8sutil.DataDir),
},
Name: name,
Image: k8sutil.MakeRookImage(c.Version),
VolumeMounts: []v1.VolumeMount{
{Name: k8sutil.DataDirVolume, MountPath: k8sutil.DataDir},
k8sutil.ConfigOverrideMount(),
},
Env: []v1.EnvVar{
{Name: "ROOK_MGR_NAME", Value: name},
{Name: "ROOK_MGR_KEYRING", ValueFrom: &v1.EnvVarSource{SecretKeyRef: &v1.SecretKeySelector{LocalObjectReference: v1.LocalObjectReference{Name: name}, Key: keyringName}}},
k8sutil.PodIPEnvVar(k8sutil.PrivateIPEnvVar),
k8sutil.PodIPEnvVar(k8sutil.PublicIPEnvVar),
opmon.ClusterNameEnvVar(c.Namespace),
opmon.EndpointEnvVar(),
opmon.SecretEnvVar(),
opmon.AdminSecretEnvVar(),
k8sutil.ConfigOverrideEnvVar(),
},
Resources: c.resources,
}
}
func (c *Cluster) getLabels() map[string]string {
return map[string]string{
k8sutil.AppAttr: appName,
k8sutil.ClusterAttr: c.Namespace,
}
}
func (c *Cluster) createKeyring(clusterName, name string) error {
_, err := c.context.Clientset.CoreV1().Secrets(c.Namespace).Get(name, metav1.GetOptions{})
if err == nil {
logger.Infof("the mgr keyring was already generated")
return nil
}
if !errors.IsNotFound(err) {
return fmt.Errorf("failed to get mgr secrets. %+v", err)
}
// get-or-create-key for the user account
keyring, err := createKeyring(c.context, clusterName, name)
if err != nil {
return fmt.Errorf("failed to create mgr keyring. %+v", err)
}
// Store the keyring in a secret
secrets := map[string]string{
keyringName: keyring,
}
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: c.Namespace},
StringData: secrets,
Type: k8sutil.RookType,
}
_, err = c.context.Clientset.CoreV1().Secrets(c.Namespace).Create(secret)
if err != nil {
return fmt.Errorf("failed to save mgr secrets. %+v", err)
}
return nil
}
func getKeyringProperties(name string) (string, []string) {
username := fmt.Sprintf("mgr.%s", name)
access := []string{"mon", "allow *"}
return username, access
}
// create a keyring for the mds client with a limited set of privileges
func createKeyring(context *clusterd.Context, clusterName, name string) (string, error) {
// get-or-create-key for the user account
username, access := getKeyringProperties(name)
keyring, err := client.AuthGetOrCreateKey(context, clusterName, username, access)
if err != nil {
return "", fmt.Errorf("failed to get or create auth key for %s. %+v", username, err)
}
return keyring, nil
}