package openshift
import (
"bytes"
"fmt"
kapi "k8s.io/kubernetes/pkg/api"
kerrors "k8s.io/kubernetes/pkg/util/errors"
"github.com/openshift/origin/pkg/bootstrap/docker/errors"
"github.com/openshift/origin/pkg/client"
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
configcmd "github.com/openshift/origin/pkg/config/cmd"
genappcmd "github.com/openshift/origin/pkg/generate/app/cmd"
)
const (
loggingNamespace = "logging"
svcKibana = "kibana-logging"
loggingDeployerAccountTemplate = "logging-deployer-account-template"
loggingDeployerTemplate = "logging-deployer-template"
)
func instantiateTemplate(client client.Interface, mapper configcmd.Mapper, templateNamespace, templateName, targetNamespace string, params map[string]string) error {
template, err := client.Templates(templateNamespace).Get(templateName)
if err != nil {
return errors.NewError("cannot retrieve template %q from namespace %q", templateName, templateNamespace).WithCause(err)
}
// process the template
result, err := genappcmd.TransformTemplate(template, client, targetNamespace, params)
if err != nil {
return errors.NewError("cannot process template %s/%s", templateNamespace, templateName).WithCause(err)
}
// Create objects
bulk := &configcmd.Bulk{
Mapper: mapper,
Op: configcmd.Create,
}
itemsToCreate := &kapi.List{
Items: result.Objects,
}
if errs := bulk.Run(itemsToCreate, targetNamespace); len(errs) > 0 {
err = kerrors.NewAggregate(errs)
return errors.NewError("cannot create objects from template %s/%s", templateNamespace, templateName).WithCause(err)
}
return nil
}
// InstallLogging checks whether logging is installed and installs it if not already installed
func (h *Helper) InstallLogging(f *clientcmd.Factory, publicHostname, loggerHost, 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.Core().Namespaces().Get(loggingNamespace)
if err == nil {
// If there's no error, the logging namespace already exists and we won't initialize it
return nil
}
// Create logging namespace
out := &bytes.Buffer{}
err = CreateProject(f, loggingNamespace, "", "", "oc", out)
if err != nil {
return errors.NewError("cannot create logging project").WithCause(err).WithDetails(out.String())
}
// Instantiate logging deployer account template
err = instantiateTemplate(osClient, clientcmd.ResourceMapper(f), "openshift", loggingDeployerAccountTemplate, loggingNamespace, nil)
if err != nil {
return errors.NewError("cannot instantiate logger accounts").WithCause(err)
}
// Add oauth-editor cluster role to logging-deployer sa
if err = AddClusterRole(osClient, "oauth-editor", "system:serviceaccount:logging:logging-deployer"); err != nil {
return errors.NewError("cannot add oauth editor role to logging deployer service account").WithCause(err).WithDetails(h.OriginLog())
}
// Add cluster-reader cluster role to aggregated-logging-fluentd sa
if err = AddClusterRole(osClient, "cluster-reader", "system:serviceaccount:logging:aggregated-logging-fluentd"); err != nil {
return errors.NewError("cannot cluster reader role to logging fluentd service account").WithCause(err).WithDetails(h.OriginLog())
}
// Add privileged SCC to aggregated-logging-fluentd sa
if err = AddSCCToServiceAccount(kubeClient, "privileged", "aggregated-logging-fluentd", loggingNamespace); err != nil {
return errors.NewError("cannot add privileged security context constraint to logging fluentd service account").WithCause(err).WithDetails(h.OriginLog())
}
// Label all nodes with default fluentd label
nodeList, err := kubeClient.Core().Nodes().List(kapi.ListOptions{})
if err != nil {
return errors.NewError("cannot retrieve nodes").WithCause(err).WithDetails(h.OriginLog())
}
// Iterate through all nodes (there should only be one)
for _, node := range nodeList.Items {
node.Labels["logging-infra-fluentd"] = "true"
if _, err = kubeClient.Core().Nodes().Update(&node); err != nil {
return errors.NewError("cannot update labels on node %s", node.Name).WithCause(err)
}
}
// Create ConfigMap with deployment values
loggingConfig := &kapi.ConfigMap{}
loggingConfig.Name = "logging-deployer"
loggingConfig.Data = map[string]string{
"kibana-hostname": loggerHost,
"public-master-url": fmt.Sprintf("https://%s:8443", publicHostname),
"es-cluster-size": "1",
"es-instance-ram": "1024M",
}
kubeClient.Core().ConfigMaps(loggingNamespace).Create(loggingConfig)
// Instantiate logging deployer
deployerParams := map[string]string{
"IMAGE_VERSION": imageVersion,
"IMAGE_PREFIX": fmt.Sprintf("%s-", imagePrefix),
"MODE": "install",
}
err = instantiateTemplate(osClient, clientcmd.ResourceMapper(f), "openshift", loggingDeployerTemplate, loggingNamespace, deployerParams)
if err != nil {
return errors.NewError("cannot instantiate logging deployer").WithCause(err)
}
return nil
}
func LoggingHost(routingSuffix, serverIP string) string {
if len(routingSuffix) > 0 {
return fmt.Sprintf("kibana-logging.%s", routingSuffix)
}
return fmt.Sprintf("kibana-logging.%s.xip.io", serverIP)
}