package openshift import ( "bytes" "fmt" "io" "os" "path/filepath" "github.com/golang/glog" "github.com/openshift/origin/pkg/cmd/util/clientcmd" kapi "k8s.io/kubernetes/pkg/api" apierrors "k8s.io/kubernetes/pkg/api/errors" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/serviceaccount" "github.com/openshift/origin/pkg/bootstrap/docker/errors" "github.com/openshift/origin/pkg/client" "github.com/openshift/origin/pkg/cmd/admin/policy" "github.com/openshift/origin/pkg/cmd/admin/registry" "github.com/openshift/origin/pkg/cmd/admin/router" "github.com/openshift/origin/pkg/cmd/server/admin" "github.com/openshift/origin/pkg/cmd/util/variable" ) const ( DefaultNamespace = "default" SvcDockerRegistry = "docker-registry" SvcRouter = "router" masterConfigDir = "/var/lib/origin/openshift.local.config/master" ) // InstallRegistry checks whether a registry is installed and installs one if not already installed func (h *Helper) InstallRegistry(kubeClient kclientset.Interface, f *clientcmd.Factory, configDir, images string, out, errout io.Writer) error { _, err := kubeClient.Core().Services(DefaultNamespace).Get(SvcDockerRegistry) if err == nil { // If there's no error, the registry already exists return nil } if !apierrors.IsNotFound(err) { return errors.NewError("error retrieving docker registry service").WithCause(err).WithDetails(h.OriginLog()) } imageTemplate := variable.NewDefaultImageTemplate() imageTemplate.Format = images opts := ®istry.RegistryOptions{ Config: ®istry.RegistryConfig{ Name: "registry", Type: "docker-registry", ImageTemplate: imageTemplate, Ports: "5000", Replicas: 1, Labels: "docker-registry=default", Volume: "/registry", ServiceAccount: "registry", }, } cmd := registry.NewCmdRegistry(f, "", "registry", out, errout) output := &bytes.Buffer{} err = opts.Complete(f, cmd, output, output, []string{}) if err != nil { return errors.NewError("error completing the registry configuration").WithCause(err) } err = opts.RunCmdRegistry() glog.V(4).Infof("Registry command output:\n%s", output.String()) if err != nil { return errors.NewError("cannot install registry").WithCause(err).WithDetails(h.OriginLog()) } return nil } // InstallRouter installs a default router on the OpenShift server func (h *Helper) InstallRouter(kubeClient kclientset.Interface, f *clientcmd.Factory, configDir, images, hostIP string, portForwarding bool, out, errout io.Writer) error { _, err := kubeClient.Core().Services(DefaultNamespace).Get(SvcRouter) if err == nil { // Router service already exists, nothing to do return nil } if !apierrors.IsNotFound(err) { return errors.NewError("error retrieving router service").WithCause(err).WithDetails(h.OriginLog()) } masterDir := filepath.Join(configDir, "master") // Create service account for router routerSA := &kapi.ServiceAccount{} routerSA.Name = "router" _, err = kubeClient.Core().ServiceAccounts("default").Create(routerSA) if err != nil { return errors.NewError("cannot create router service account").WithCause(err).WithDetails(h.OriginLog()) } // Add router SA to privileged SCC privilegedSCC, err := kubeClient.Core().SecurityContextConstraints().Get("privileged") if err != nil { return errors.NewError("cannot retrieve privileged SCC").WithCause(err).WithDetails(h.OriginLog()) } privilegedSCC.Users = append(privilegedSCC.Users, serviceaccount.MakeUsername("default", "router")) _, err = kubeClient.Core().SecurityContextConstraints().Update(privilegedSCC) if err != nil { return errors.NewError("cannot update privileged SCC").WithCause(err).WithDetails(h.OriginLog()) } // Create router cert cmdOutput := &bytes.Buffer{} createCertOptions := &admin.CreateServerCertOptions{ SignerCertOptions: &admin.SignerCertOptions{ CertFile: filepath.Join(masterDir, "ca.crt"), KeyFile: filepath.Join(masterDir, "ca.key"), SerialFile: filepath.Join(masterDir, "ca.serial.txt"), }, Overwrite: true, Hostnames: []string{ fmt.Sprintf("%s.xip.io", hostIP), // This will ensure that routes using edge termination and the default // certs will use certs valid for their arbitrary subdomain names. fmt.Sprintf("*.%s.xip.io", hostIP), }, CertFile: filepath.Join(masterDir, "router.crt"), KeyFile: filepath.Join(masterDir, "router.key"), Output: cmdOutput, } _, err = createCertOptions.CreateServerCert() if err != nil { return errors.NewError("cannot create router cert").WithCause(err) } err = catFiles(filepath.Join(masterDir, "router.pem"), filepath.Join(masterDir, "router.crt"), filepath.Join(masterDir, "router.key"), filepath.Join(masterDir, "ca.crt")) if err != nil { return err } imageTemplate := variable.NewDefaultImageTemplate() imageTemplate.Format = images cfg := &router.RouterConfig{ Name: "router", Type: "haproxy-router", ImageTemplate: imageTemplate, Ports: "80:80,443:443", Replicas: 1, Labels: "router=", Credentials: filepath.Join(masterDir, "admin.kubeconfig"), DefaultCertificate: filepath.Join(masterDir, "router.pem"), StatsPort: 1936, StatsUsername: "admin", HostNetwork: !portForwarding, HostPorts: true, ServiceAccount: "router", } output := &bytes.Buffer{} cmd := router.NewCmdRouter(f, "", "router", out, errout) cmd.SetOutput(output) err = router.RunCmdRouter(f, cmd, output, output, cfg, []string{}) glog.V(4).Infof("Router command output:\n%s", output.String()) if err != nil { return errors.NewError("cannot install router").WithCause(err).WithDetails(h.OriginLog()) } return nil } func AddClusterRole(osClient client.Interface, role, user string) error { clusterRoleBindingAccessor := policy.NewClusterRoleBindingAccessor(osClient) addClusterReaderRole := policy.RoleModificationOptions{ RoleName: role, RoleBindingAccessor: clusterRoleBindingAccessor, Users: []string{user}, } return addClusterReaderRole.AddRole() } func AddRoleToServiceAccount(osClient client.Interface, role, sa, namespace string) error { roleBindingAccessor := policy.NewLocalRoleBindingAccessor(namespace, osClient) addRole := policy.RoleModificationOptions{ RoleName: role, RoleBindingAccessor: roleBindingAccessor, Subjects: []kapi.ObjectReference{ { Namespace: namespace, Name: sa, Kind: "ServiceAccount", }, }, } return addRole.AddRole() } func AddSCCToServiceAccount(kubeClient kclientset.Interface, scc, sa, namespace string) error { modifySCC := policy.SCCModificationOptions{ SCCName: scc, SCCInterface: kubeClient.Core(), Subjects: []kapi.ObjectReference{ { Namespace: namespace, Name: sa, Kind: "ServiceAccount", }, }, } return modifySCC.AddSCC() } // catFiles concatenates multiple source files into a single destination file func catFiles(dest string, src ...string) error { out, err := os.Create(dest) if err != nil { return err } defer out.Close() for _, f := range src { in, oerr := os.Open(f) if oerr != nil { return err } _, err = io.Copy(out, in) in.Close() if err != nil { return err } } return nil }