package openshift
import (
"fmt"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
kapi "k8s.io/kubernetes/pkg/api"
apierrors "k8s.io/kubernetes/pkg/api/errors"
"github.com/openshift/origin/pkg/bootstrap/docker/errors"
)
const (
infraNamespace = "openshift-infra"
svcMetrics = "hawkular-metrics"
metricsDeployerSA = "metrics-deployer"
metricsDeployerSecret = "metrics-deployer"
metricsDeployerPodName = "metrics-deployer-pod"
)
// InstallMetrics checks whether metrics is installed and installs it if not already installed
func (h *Helper) InstallMetrics(f *clientcmd.Factory, hostName, imagePrefix, imageVersion string) error {
osClient, kubeClient, _, err := f.Clients()
if err != nil {
return errors.NewError("cannot obtain API clients").WithCause(err).WithDetails(h.OriginLog())
}
_, err = kubeClient.Services(infraNamespace).Get(svcMetrics)
if err == nil {
// If there's no error, the metrics service already exists
return nil
}
if !apierrors.IsNotFound(err) {
return errors.NewError("error retrieving metrics service").WithCause(err).WithDetails(h.OriginLog())
}
// Create metrics deployer service account
routerSA := &kapi.ServiceAccount{}
routerSA.Name = metricsDeployerSA
_, err = kubeClient.ServiceAccounts(infraNamespace).Create(routerSA)
if err != nil {
return errors.NewError("cannot create metrics deployer service account").WithCause(err).WithDetails(h.OriginLog())
}
// Add edit role to deployer service account
if err = AddRoleToServiceAccount(osClient, "edit", metricsDeployerSA, infraNamespace); err != nil {
return errors.NewError("cannot add edit role to metrics deployer service account").WithCause(err).WithDetails(h.OriginLog())
}
// Add view role to the hawkular service account
if err = AddRoleToServiceAccount(osClient, "view", "hawkular", infraNamespace); err != nil {
return errors.NewError("cannot add view role to the hawkular service account").WithCause(err).WithDetails(h.OriginLog())
}
// Add cluster reader role to heapster service account
if err = AddClusterRole(osClient, "cluster-reader", "system:serviceaccount:openshift-infra:heapster"); err != nil {
return errors.NewError("cannot add cluster reader role to heapster service account").WithCause(err).WithDetails(h.OriginLog())
}
// Create metrics deployer secret
deployerSecret := &kapi.Secret{}
deployerSecret.Name = metricsDeployerSecret
deployerSecret.Data = map[string][]byte{"nothing": []byte("/dev/null")}
if _, err = kubeClient.Secrets(infraNamespace).Create(deployerSecret); err != nil {
return errors.NewError("cannot create metrics deployer secret").WithCause(err).WithDetails(h.OriginLog())
}
// Create deployer Pod
deployerPod := metricsDeployerPod(hostName, imagePrefix, imageVersion)
if _, err = kubeClient.Pods(infraNamespace).Create(deployerPod); err != nil {
return errors.NewError("cannot create metrics deployer pod").WithCause(err).WithDetails(h.OriginLog())
}
return nil
}
func metricsDeployerPod(hostName, imagePrefix, imageVersion string) *kapi.Pod {
env := []kapi.EnvVar{
{
Name: "PROJECT",
ValueFrom: &kapi.EnvVarSource{
FieldRef: &kapi.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
{
Name: "POD_NAME",
ValueFrom: &kapi.EnvVarSource{
FieldRef: &kapi.ObjectFieldSelector{
FieldPath: "metadata.name",
},
},
},
{
Name: "IMAGE_PREFIX",
Value: fmt.Sprintf("%s-", imagePrefix),
},
{
Name: "IMAGE_VERSION",
Value: imageVersion,
},
{
Name: "MASTER_URL",
Value: "https://kubernetes.default.svc:443",
},
{
Name: "HAWKULAR_METRICS_HOSTNAME",
Value: hostName,
},
{
Name: "MODE",
Value: "deploy",
},
{
Name: "REDEPLOY",
Value: "false",
},
{
Name: "IGNORE_PREFLIGHT",
Value: "false",
},
{
Name: "USE_PERSISTENT_STORAGE",
Value: "false",
},
{
Name: "CASSANDRA_NODES",
Value: "1",
},
{
Name: "CASSANDRA_PV_SIZE",
Value: "10Gi",
},
{
Name: "METRIC_DURATION",
Value: "7",
},
{
Name: "HEAPSTER_NODE_ID",
Value: "nodename",
},
{
Name: "METRIC_RESOLUTION",
Value: "10s",
},
}
pod := &kapi.Pod{
Spec: kapi.PodSpec{
DNSPolicy: kapi.DNSClusterFirst,
RestartPolicy: kapi.RestartPolicyNever,
ServiceAccountName: metricsDeployerSA,
Volumes: []kapi.Volume{
{
Name: "empty",
VolumeSource: kapi.VolumeSource{
EmptyDir: &kapi.EmptyDirVolumeSource{},
},
},
{
Name: "secret",
VolumeSource: kapi.VolumeSource{
Secret: &kapi.SecretVolumeSource{
SecretName: metricsDeployerSecret,
},
},
},
},
},
}
pod.Name = metricsDeployerPodName
pod.Spec.Containers = []kapi.Container{
{
Image: fmt.Sprintf("%s-metrics-deployer:%s", imagePrefix, imageVersion),
Name: "deployer",
VolumeMounts: []kapi.VolumeMount{
{
Name: "secret",
MountPath: "/secret",
ReadOnly: true,
},
{
Name: "empty",
MountPath: "/etc/deploy",
},
},
Env: env,
},
}
return pod
}
func MetricsHost(routingSuffix, serverIP string) string {
if len(routingSuffix) > 0 {
return fmt.Sprintf("metrics-openshift-infra.%s", routingSuffix)
}
return fmt.Sprintf("metrics-openshift-infra.%s.xip.io", serverIP)
}