Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve kubernetes object names #112

Merged
merged 1 commit into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions cmd/run/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import (
"github.com/hyperledger-labs/fabric-builder-k8s/internal/builder"
"github.com/hyperledger-labs/fabric-builder-k8s/internal/log"
"github.com/hyperledger-labs/fabric-builder-k8s/internal/util"
"k8s.io/apimachinery/pkg/api/validation"
)

const (
expectedArgsLength = 3
buildOutputDirectoryArg = 1
runMetadataDirectoryArg = 2
expectedArgsLength = 3
buildOutputDirectoryArg = 1
runMetadataDirectoryArg = 2
maximumKubeNamePrefixLength = 30
)

func main() {
Expand Down Expand Up @@ -50,20 +52,34 @@ func main() {
if kubeNamespace == "" {
kubeNamespace, err = util.GetKubeNamespace()
if err != nil {
kubeNamespace = "default"
kubeNamespace = util.DefaultNamespace
}
}

kubeServiceAccount := util.GetOptionalEnv(util.ChaincodeServiceAccountVariable, "default")
kubeServiceAccount := util.GetOptionalEnv(util.ChaincodeServiceAccountVariable, util.DefaultServiceAccountName)
logger.Debugf("%s=%s", util.ChaincodeServiceAccountVariable, kubeServiceAccount)

kubeNamePrefix := util.GetOptionalEnv(util.ObjectNamePrefixVariable, util.DefaultObjectNamePrefix)
logger.Debugf("%s=%s", util.ObjectNamePrefixVariable, kubeNamePrefix)

if len(kubeNamePrefix) > maximumKubeNamePrefixLength {
logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a maximum of 30 characters")
os.Exit(1)
}

if msgs := validation.NameIsDNS1035Label(kubeNamePrefix, true); len(msgs) > 0 {
logger.Printf("The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: %s", msgs[0])
os.Exit(1)
}

run := &builder.Run{
BuildOutputDirectory: buildOutputDirectory,
RunMetadataDirectory: runMetadataDirectory,
PeerID: peerID,
KubeconfigPath: kubeconfigPath,
KubeNamespace: kubeNamespace,
KubeServiceAccount: kubeServiceAccount,
KubeNamePrefix: kubeNamePrefix,
}

if err := run.Run(ctx); err != nil {
Expand Down
52 changes: 44 additions & 8 deletions cmd/run/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,60 @@ import (
)

var _ = Describe("Main", func() {
DescribeTable("Running the run command produces the correct error code",
func(expectedErrorCode int, args ...string) {
It("should return an error if the CORE_PEER_ID environment variable is not set", func() {
args := []string{"BUILD_OUTPUT_DIR", "RUN_METADATA_DIR"}
command := exec.Command(runCmdPath, args...)
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())

Eventually(session).Should(gexec.Exit(1))
Eventually(
session.Err,
).Should(gbytes.Say(`run \[\d+\]: Expected CORE_PEER_ID environment variable`))
})

DescribeTable("Running the run command with the wrong arguments produces the correct error",
func(args ...string) {
command := exec.Command(runCmdPath, args...)
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())

Eventually(session).Should(gexec.Exit(expectedErrorCode))
Eventually(session).Should(gexec.Exit(1))
Eventually(
session.Err,
).Should(gbytes.Say(`run \[\d+\]: Expected BUILD_OUTPUT_DIR and RUN_METADATA_DIR arguments`))
},
Entry("When too few arguments are provided", 1, "BUILD_OUTPUT_DIR"),
Entry("When too few arguments are provided", "BUILD_OUTPUT_DIR"),
Entry(
"When too many arguments are provided",
1,
"BUILD_OUTPUT_DIR",
"RUN_METADATA_DIR",
"UNEXPECTED_ARGUMENT",
),
)

DescribeTable("Running the run command produces the correct error for invalid FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable values",
func(kubeNamePrefixValue, expectedErrorMessage string) {
args := []string{"BUILD_OUTPUT_DIR", "RUN_METADATA_DIR"}
command := exec.Command(runCmdPath, args...)
command.Env = append(os.Environ(),
"CORE_PEER_ID=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789",
"FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX="+kubeNamePrefixValue,
)
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())

Eventually(session).Should(gexec.Exit(1))
Eventually(
session.Err,
).Should(gbytes.Say(expectedErrorMessage))
},
Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX is too long", "long-prefix-is-looooooooooooooooooooong", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a maximum of 30 characters`),
Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX contains invalid characters", "invalid/PREFIX*", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`),
Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX starts with a number", "1prefix", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`),
Entry("When the FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX starts with a dash", "-prefix", `run \[\d+\]: The FABRIC_K8S_BUILDER_OBJECT_NAME_PREFIX environment variable must be a valid DNS-1035 label: a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character`),
)

It(
"should start a chaincode pod using the supplied configuration environment variables",
Label("kind"),
Expand Down Expand Up @@ -59,7 +95,7 @@ var _ = Describe("Main", func() {
).Should(gbytes.Say(`run \[\d+\] DEBUG: FABRIC_K8S_BUILDER_SERVICE_ACCOUNT=chaincode`))
Eventually(
session.Err,
).Should(gbytes.Say(`run \[\d+\]: Running chaincode ID CHAINCODE_ID in kubernetes pod chaincode/cc-m4eml38l6lv2ost7v1i3q6698a5p4gu1l3lnflb4boi7jnle6lt0`))
).Should(gbytes.Say(`run \[\d+\]: Running chaincode ID CHAINCODE_LABEL:CHAINCODE_HASH in kubernetes pod chaincode/hlfcc-chaincodelabel-f15ukm9v906aq`))

pipe := script.Exec(
"kubectl wait --for=condition=ready pod --timeout=120s --namespace=chaincode -l fabric-builder-k8s-peerid=core-peer-id-abcdefghijklmnopqrstuvwxyz-0123456789",
Expand All @@ -84,8 +120,8 @@ var _ = Describe("Main", func() {
Eventually(descSession.Out).Should(gbytes.Say(`fabric-builder-k8s-mspid=MSPID`))
Eventually(
descSession.Out,
).Should(gbytes.Say(`fabric-builder-k8s-ccid:\s+CHAINCODE_ID`))
Eventually(descSession.Out).Should(gbytes.Say(`CORE_CHAINCODE_ID_NAME:\s+CHAINCODE_ID`))
).Should(gbytes.Say(`fabric-builder-k8s-ccid:\s+CHAINCODE_LABEL:CHAINCODE_HASH`))
Eventually(descSession.Out).Should(gbytes.Say(`CORE_CHAINCODE_ID_NAME:\s+CHAINCODE_LABEL:CHAINCODE_HASH`))
Eventually(descSession.Out).Should(gbytes.Say(`CORE_PEER_ADDRESS:\s+PEER_ADDRESS`))
Eventually(descSession.Out).Should(gbytes.Say(`CORE_PEER_LOCALMSPID:\s+MSPID`))
},
Expand Down
2 changes: 1 addition & 1 deletion cmd/run/testdata/validchaincode/chaincode.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"chaincode_id": "CHAINCODE_ID",
"chaincode_id": "CHAINCODE_LABEL:CHAINCODE_HASH",
"peer_address": "PEER_ADDRESS",
"client_cert": "CLIENT_CERT",
"client_key": "CLIENT_KEY",
Expand Down
5 changes: 5 additions & 0 deletions internal/builder/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Run struct {
KubeconfigPath string
KubeNamespace string
KubeServiceAccount string
KubeNamePrefix string
}

func (r *Run) Run(ctx context.Context) error {
Expand All @@ -33,6 +34,8 @@ func (r *Run) Run(ctx context.Context) error {
return err
}

kubeObjectName := util.GetValidRfc1035LabelName(r.KubeNamePrefix, r.PeerID, chaincodeData)

clientset, err := util.GetKubeClientset(logger, r.KubeconfigPath)
if err != nil {
return fmt.Errorf(
Expand All @@ -48,6 +51,7 @@ func (r *Run) Run(ctx context.Context) error {
ctx,
logger,
secretsClient,
kubeObjectName,
r.KubeNamespace,
r.PeerID,
chaincodeData,
Expand All @@ -66,6 +70,7 @@ func (r *Run) Run(ctx context.Context) error {
ctx,
logger,
podsClient,
kubeObjectName,
r.KubeNamespace,
r.KubeServiceAccount,
r.PeerID,
Expand Down
1 change: 1 addition & 0 deletions internal/util/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
const (
builderVariablePrefix = "FABRIC_K8S_BUILDER_"
ChaincodeNamespaceVariable = builderVariablePrefix + "NAMESPACE"
ObjectNamePrefixVariable = builderVariablePrefix + "OBJECT_NAME_PREFIX"
ChaincodeServiceAccountVariable = builderVariablePrefix + "SERVICE_ACCOUNT"
DebugVariable = builderVariablePrefix + "DEBUG"
KubeconfigPathVariable = "KUBECONFIG_PATH"
Expand Down
28 changes: 28 additions & 0 deletions internal/util/fabric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0

package util

import "strings"

type ChaincodePackageID struct {
Label string
Hash string
}

// NewChaincodePackageID returns a ChaincodePackageID created from the provided string.
func NewChaincodePackageID(chaincodeID string) *ChaincodePackageID {
substrings := strings.Split(chaincodeID, ":")

// If it doesn't look like a label and a hash, don't try and guess which is which
if len(substrings) == 1 {
return &ChaincodePackageID{
Label: "",
Hash: "",
}
}

return &ChaincodePackageID{
Label: strings.Join(substrings[:len(substrings)-1], ":"),
Hash: substrings[len(substrings)-1],
}
}
23 changes: 23 additions & 0 deletions internal/util/fabric_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package util_test

import (
"github.com/hyperledger-labs/fabric-builder-k8s/internal/util"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Fabric", func() {
DescribeTable("NewChaincodePackageID return a new ChaincodePackageID with the expected label and hash values",
func(chaincodeID, expectedLabel, expectedHash string) {
packageID := util.NewChaincodePackageID(chaincodeID)
Expect(packageID.Label).To(Equal(expectedLabel), "The ChaincodePackageID should include the expected label")
Expect(packageID.Hash).To(Equal(expectedHash), "The ChaincodePackageID should include the expected hash")
},
Entry("When the chaincode ID only contains one colon", "fabcar:cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b", "fabcar", "cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b"),
// The rest are a bit of a guess since I'm not sure the package ID format is defined in detail anywhere
Entry("When the chaincode ID contains more than one colon", "fab:car:cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b", "fab:car", "cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b"),
Entry("When the chaincode ID contains a double colon", "fab::car:cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b", "fab::car", "cffa266294278404e5071cb91150d550dc0bf855149908a170b1169d6160004b"),
Entry("When the chaincode ID is an empty string", "", "", ""),
Entry("When the chaincode ID does not contain a colon", "fabcar", "", ""),
)
})
Loading
Loading