diff --git a/pkg/operator/ceph/cluster/osd/config/config.go b/pkg/operator/ceph/cluster/osd/config/config.go index e1ffedb7a..adb0a07ce 100644 --- a/pkg/operator/ceph/cluster/osd/config/config.go +++ b/pkg/operator/ceph/cluster/osd/config/config.go @@ -18,10 +18,10 @@ limitations under the License. package config import ( - "fmt" "strconv" "github.com/coreos/pkg/capnslog" + "github.com/rook/rook/pkg/operator/k8sutil" ) const ( @@ -33,7 +33,7 @@ const ( var logger = capnslog.NewPackageLogger("github.com/rook/rook", "osd-config") func GetConfigStoreName(nodeName string) string { - return fmt.Sprintf(configStoreNameFmt, nodeName) + return k8sutil.TruncateNodeName(configStoreNameFmt, nodeName) } const ( diff --git a/pkg/operator/ceph/cluster/osd/pod.go b/pkg/operator/ceph/cluster/osd/pod.go index 913aae053..cb3ed645b 100644 --- a/pkg/operator/ceph/cluster/osd/pod.go +++ b/pkg/operator/ceph/cluster/osd/pod.go @@ -58,7 +58,7 @@ func (c *Cluster) makeJob(nodeName string, devices []rookalpha.Device, job := &batch.Job{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf(prepareAppNameFmt, nodeName), + Name: k8sutil.TruncateNodeName(prepareAppNameFmt, nodeName), Namespace: c.Namespace, Labels: map[string]string{ k8sutil.AppAttr: prepareAppName, diff --git a/pkg/operator/ceph/cluster/osd/pod_test.go b/pkg/operator/ceph/cluster/osd/pod_test.go index 8dcf83d55..b72484bd7 100644 --- a/pkg/operator/ceph/cluster/osd/pod_test.go +++ b/pkg/operator/ceph/cluster/osd/pod_test.go @@ -194,6 +194,7 @@ func TestStorageSpecConfig(t *testing.T) { job, err := c.makeJob(n.Name, n.Devices, n.Selection, c.Storage.Nodes[0].Resources, storeConfig, metadataDevice, n.Location) assert.NotNil(t, job) assert.Nil(t, err) + assert.Equal(t, "rook-ceph-osd-prepare-node1", job.ObjectMeta.Name) container := job.Spec.Template.Spec.Containers[0] assert.NotNil(t, container) verifyEnvVar(t, container.Env, "ROOK_OSD_STORE", "bluestore", true) @@ -241,6 +242,7 @@ func TestHostNetwork(t *testing.T) { assert.NotNil(t, r) assert.Nil(t, err) + assert.Equal(t, "rook-ceph-osd-id-0", r.ObjectMeta.Name) assert.Equal(t, true, r.Spec.Template.Spec.HostNetwork) assert.Equal(t, v1.DNSClusterFirstWithHostNet, r.Spec.Template.Spec.DNSPolicy) } diff --git a/pkg/operator/k8sutil/k8sutil.go b/pkg/operator/k8sutil/k8sutil.go index 65369cfbe..3eae4814b 100644 --- a/pkg/operator/k8sutil/k8sutil.go +++ b/pkg/operator/k8sutil/k8sutil.go @@ -18,10 +18,12 @@ limitations under the License. package k8sutil import ( + "crypto/md5" "fmt" "strings" "github.com/coreos/pkg/capnslog" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/util/version" ) @@ -51,7 +53,7 @@ const ( func GetK8SVersion(clientset kubernetes.Interface) (*version.Version, error) { serverVersion, err := clientset.Discovery().ServerVersion() if err != nil { - return nil, fmt.Errorf("Error getting server version: %v", err) + return nil, fmt.Errorf("error getting server version: %v", err) } // make sure the kubernetes version is parseable @@ -63,3 +65,23 @@ func GetK8SVersion(clientset kubernetes.Interface) (*version.Version, error) { } return version.MustParseSemantic(serverVersion.GitVersion), nil } + +// Hash MD5 hash a given string +func Hash(s string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(s))) +} + +// TruncateNodeName hashes the nodeName in case it would case the name to be longer than 63 characters +// WARNING If your format and nodeName as a hash, are longer than 63 chars it won't be truncated! +// Your format alone should only be 31 chars at max because of MD5 hash being 32 chars. +// For more information, see the following resources: +// https://stackoverflow.com/a/50451893 +// https://stackoverflow.com/a/32294443 +func TruncateNodeName(format, nodeName string) string { + if len(nodeName)+len(fmt.Sprintf(format, "")) > validation.DNS1035LabelMaxLength { + hashed := Hash(nodeName) + logger.Infof("format and nodeName longer than %d chars, nodeName %s will be %s", validation.DNS1035LabelMaxLength, nodeName, hashed) + nodeName = hashed + } + return fmt.Sprintf(format, nodeName) +} diff --git a/pkg/operator/k8sutil/k8sutil_test.go b/pkg/operator/k8sutil/k8sutil_test.go new file mode 100644 index 000000000..c04d85193 --- /dev/null +++ b/pkg/operator/k8sutil/k8sutil_test.go @@ -0,0 +1,53 @@ +/* +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 k8sutil for Kubernetes helpers. +package k8sutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTruncateNodeName(t *testing.T) { + // An entry's key is the result. The first value in the []string is the format and the second is the nodeName + tests := map[string][]string{ + "rook-ceph-osd-prepare-47d1eb58e063be11c11c995b74cc5fbe-config": { // 61 chras + "rook-ceph-osd-prepare-%s-config", // 29 chars (without format) + "k8s-worker-1234567890.this.is.a.very.very.long.node.name.example.com", // 68 chars + }, + "rook-ceph-osd-prepare-k8s01": { // 27 chars + "rook-ceph-osd-prepare-%s", // 22 chars (without format) + "k8s01", // 5 chars + }, + "rook-ceph-osd-prepare-k8s-worker-500.this.is.a.not.so.long.name": { // 63 chars + "rook-ceph-osd-prepare-%s", // 22 chars (without format) + "k8s-worker-500.this.is.a.not.so.long.name", // 41 chars + }, + "47d1eb58e063be11c11c995b74cc5fbe": { // 32 chars + "%s", // 0 chars (without format) + "k8s-worker-1234567890.this.is.a.very.very.long.node.name.example.com", // 68 chars + }, + "rook-ceph-osd-prepare-test-very-long-name-47d1eb58e063be11c11c995b74cc5fbe": { // 74 chars + "rook-ceph-osd-prepare-test-very-long-name-%s", // 42 chars (without format) + "k8s-worker-1234567890.this.is.a.very.very.long.node.name.example.com", // 68 chars + }, + } + for result, params := range tests { + assert.Equal(t, result, TruncateNodeName(params[0], params[1])) + } +}