Skip to content

Commit c075089

Browse files
MYSQLCLUSTER-4665: Setup release and debug builds
Ndb operator can be now built either in release mode or in debug mode. The debug mode is meant for development and enables verbose logging and more panics in the mgmapi module. The mode can be controlled by setting the WITH_DEBUG environment variable before calling make. Change-Id: I2450dd6fca7717a7b4b1490ba2c2111f8fad5e9e
1 parent eaf1480 commit c075089

15 files changed

+195
-77
lines changed

Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
ARCH ?= amd64
1111
OS ?= linux
1212

13+
# Set this to 1 or ON to build operator in debug mode
14+
WITH_DEBUG ?= OFF
15+
1316
# End of configurable variables
1417

1518
.PHONY: all
@@ -32,7 +35,7 @@ manifests: $(INSTALL_ARTIFACT)
3235

3336
.PHONY: build
3437
build: manifests
35-
ARCH=$(ARCH) OS=$(OS) ./hack/build.sh
38+
ARCH=$(ARCH) OS=$(OS) WITH_DEBUG=$(WITH_DEBUG) ./hack/build.sh
3639

3740
.PHONY: run
3841
run:
@@ -57,7 +60,7 @@ e2e-tests-image:
5760

5861
.PHONY: unit-test
5962
unit-test:
60-
go test -v --count=1 ./pkg/...
63+
go test -tags debug -v --count=1 ./pkg/...
6164

6265
# Run e2e tests against a local K8s Cluster
6366
.PHONY: e2e

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
# ndb-operator
22

3-
This repository implements a simple controller for watching Ndb resources as
4-
defined with a CustomResourceDefinition (CRD).
3+
The MySQL NDB Operator is a Kubernetes operator for managing a MySQL Cluster setup inside a Kubernetes Cluster.
54

6-
This is in preview state - mostly prototyping for testing concepts.
5+
This is in preview state - DO NOT USE FOR PRODUCTION.
76

87
## License
98

@@ -51,6 +50,8 @@ To build the ndb-operator run,
5150
make build
5251
```
5352

53+
By default the operator is built in release mode. It is also possible to build the operator in debug mode by setting WITH_DEBUG environment variable to 1/ON. The debug mode can be more useful during development.
54+
5455
Once the operator is built, a docker image can be built by running,
5556

5657
```sh

config/debug/build.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2021, Oracle and/or its affiliates.
2+
//
3+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
5+
package debug
6+
7+
import (
8+
"errors"
9+
"fmt"
10+
)
11+
12+
// Panic panics in debug builds
13+
func Panic(v interface{}) {
14+
if Enabled {
15+
panic(v)
16+
}
17+
}
18+
19+
// InternalError panics in a debug build and returns an error in a release build
20+
func InternalError(v interface{}) error {
21+
errMsg := fmt.Sprintf("internal error : %v", v)
22+
if Enabled {
23+
panic(errMsg)
24+
} else {
25+
return errors.New(errMsg)
26+
}
27+
}

config/debug/debug.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2021, Oracle and/or its affiliates.
2+
//
3+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
5+
// +build debug
6+
7+
package debug
8+
9+
const Enabled = true

config/debug/release.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) 2021, Oracle and/or its affiliates.
2+
//
3+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
5+
// +build !debug
6+
7+
package debug
8+
9+
const Enabled = false

config/version.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package config
66

7+
import "github.com/mysql/ndb-operator/config/debug"
8+
79
var version string
810
var gitCommit string
911

@@ -12,5 +14,10 @@ func GetBuildVersion() string {
1214
if version == "" || gitCommit == "" {
1315
panic("version or git commit was not set during build")
1416
}
15-
return version + "-" + gitCommit
17+
buildVersion := version + "-" + gitCommit
18+
if debug.Enabled {
19+
buildVersion += "-debug"
20+
}
21+
22+
return buildVersion
1623
}

e2e-tests/suites/mysql/custom_cnf.go

+38-18
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@ import (
1010
clientset "k8s.io/client-go/kubernetes"
1111
"k8s.io/kubernetes/test/e2e/framework"
1212

13+
"github.com/mysql/ndb-operator/pkg/apis/ndbcontroller/v1alpha1"
14+
"github.com/mysql/ndb-operator/pkg/helpers/testutils"
15+
1316
"github.com/mysql/ndb-operator/e2e-tests/utils/mysql"
1417
"github.com/mysql/ndb-operator/e2e-tests/utils/ndbtest"
18+
secretutils "github.com/mysql/ndb-operator/e2e-tests/utils/secret"
1519
)
1620

1721
var _ = ndbtest.DescribeFeature("MySQL Custom cnf", func() {
1822
var ns string
1923
var c clientset.Interface
24+
var ndbName, mysqlRootSecretName string
25+
var testNdb *v1alpha1.NdbCluster
2026

2127
ginkgo.BeforeEach(func() {
2228
ginkgo.By("extracting values from framework")
@@ -36,32 +42,46 @@ var _ = ndbtest.DescribeFeature("MySQL Custom cnf", func() {
3642
ginkgo.When("a custom cnf property is specified for MySQL Server", func() {
3743

3844
ginkgo.BeforeEach(func() {
39-
ndbtest.KubectlApplyNdbYaml(c, ns, "docs/examples", "example-ndb-cnf")
45+
ndbName = "ndb-custom-cnf-test"
46+
mysqlRootSecretName = ndbName + "-root-secret"
47+
// create the secret first
48+
secretutils.CreateSecretForMySQLRootAccount(c, mysqlRootSecretName, ns)
49+
// create the Ndb resource
50+
testNdb = testutils.NewTestNdb(ns, ndbName, 2)
51+
testNdb.Spec.Mysqld.RootPasswordSecretName = mysqlRootSecretName
52+
testNdb.Spec.Mysqld.MyCnf = "[mysqld]\nmax-user-connections=42\nlog-bin=ON"
53+
ndbtest.KubectlApplyNdbObj(c, testNdb)
4054
})
4155

4256
ginkgo.AfterEach(func() {
43-
ndbtest.KubectlDeleteNdbYaml(c, ns, "example-ndb", "docs/examples", "example-ndb-cnf")
57+
// cleanup
58+
ndbtest.KubectlDeleteNdbObj(c, testNdb)
59+
// drop the secret
60+
secretutils.DeleteSecret(c, mysqlRootSecretName, ns)
4461
})
4562

4663
ginkgo.It("should start the server with those values as the defaults", func() {
47-
db := mysql.Connect(c, ns, "example-ndb", "performance_schema")
64+
db := mysql.Connect(c, ns, ndbName, "performance_schema")
4865

49-
ginkgo.By("verifying that max_user_connections is properly set in server")
50-
row := db.QueryRow(
51-
"select variable_value from global_variables where variable_name = 'max_user_connections';")
52-
var value int
53-
framework.ExpectNoError(row.Scan(&value),
54-
"querying for max_user_connections returned an error")
55-
gomega.Expect(value).To(gomega.Equal(42),
56-
"max_user_connections had an unexpected value")
66+
ginkgo.By("verifying that max_user_connections is properly set in server", func() {
67+
row := db.QueryRow(
68+
"select variable_value from global_variables where variable_name = 'max_user_connections';")
69+
var value int
70+
framework.ExpectNoError(row.Scan(&value),
71+
"querying for max_user_connections returned an error")
72+
gomega.Expect(value).To(gomega.Equal(42),
73+
"max_user_connections had an unexpected value")
74+
})
5775

58-
ginkgo.By("verifying that the defaults doesn't override the value set by the operator")
59-
row = db.QueryRow(
60-
"select variable_value from global_variables where variable_name = 'ndb_extra_logging';")
61-
framework.ExpectNoError(row.Scan(&value),
62-
"querying for ndb_extra_logging returned an error")
63-
gomega.Expect(value).To(gomega.Equal(99),
64-
"ndb_extra_logging had an unexpected value")
76+
ginkgo.By("verifying that the defaults doesn't override the value set by the operator", func() {
77+
row := db.QueryRow(
78+
"select variable_value from global_variables where variable_name = 'log_bin';")
79+
var value string
80+
framework.ExpectNoError(row.Scan(&value),
81+
"querying for log_bin returned an error")
82+
gomega.Expect(value).To(gomega.Or(gomega.Equal("OFF")),
83+
"log_bin has an unexpected value")
84+
})
6585
})
6686
})
6787
})

hack/build.sh

+10
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,24 @@ set -o nounset
1010
# Required env variables :
1111
# ARCH - target golang architecture
1212
# OS - target golang OS
13+
# WITH_DEBUG - enable ndb operator debug build mode
1314

1415
PKG=$(go list -m)
1516
VERSION=$(cat VERSION)
1617

18+
BUILD_TAGS=
19+
if [ "${WITH_DEBUG}" = "1" ] || [ "${WITH_DEBUG}" = "ON" ]; then
20+
BUILD_TAGS="debug"
21+
else
22+
BUILD_TAGS="release"
23+
fi
24+
1725
echo "Building ndb operator..."
1826
echo "arch: ${ARCH}"
1927
echo "os: ${OS}"
2028
echo "version: ${VERSION}"
2129
echo "pkg: ${PKG}"
30+
echo "build: ${BUILD_TAGS}"
2231

2332
export CGO_ENABLED=0
2433
export GOARCH="${ARCH}"
@@ -34,4 +43,5 @@ go build \
3443
-v \
3544
-o "${BINARIES}" \
3645
-ldflags "${LDFLAGS}" \
46+
-tags "${BUILD_TAGS}" \
3747
./...

pkg/controllers/controller_test.go

-5
Original file line numberDiff line numberDiff line change
@@ -491,9 +491,4 @@ func TestCreatesCluster(t *testing.T) {
491491
//f.expectUpdateNdbStatusAction(ns, ndb)
492492

493493
f.run(getKey(ndb, t))
494-
495-
// run again;
496-
// only error allowed is "connection refused" as mgmd is not running
497-
expectedErrors := []string{"connection refused"}
498-
f.runController(getKey(ndb, t), true, expectedErrors)
499494
}

pkg/mgmapi/clusterstatus.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
package mgmapi
66

7-
import "sort"
7+
import (
8+
"github.com/mysql/ndb-operator/config/debug"
9+
"sort"
10+
)
811

912
// NodeTypeEnum identifies the node type used in NodeStatus object
1013
// there are more types defined in c-code, but they are not used here
@@ -28,7 +31,8 @@ func (t NodeTypeEnum) toString() string {
2831
case NodeTypeAPI:
2932
return "API"
3033
default:
31-
panic("unrecognized node type")
34+
debug.Panic("unrecognized node type")
35+
return ""
3236
}
3337
}
3438

@@ -74,7 +78,7 @@ func (ns *NodeStatus) setNodeTypeFromTLA(TLA string) {
7478
case "API":
7579
ns.NodeType = NodeTypeAPI
7680
default:
77-
panic("unsupported node type : " + TLA)
81+
debug.Panic("unsupported node type : " + TLA)
7882
}
7983
}
8084

@@ -144,7 +148,8 @@ func (cs ClusterStatus) GetNodesGroupedByNodegroup() [][]int {
144148
}
145149
if !node.IsConnected {
146150
// data node not connected
147-
panic("should be called only when the cluster is healthy")
151+
debug.Panic("should be called only when the cluster is healthy")
152+
return nil
148153
}
149154
nodegroup := node.NodeGroup
150155
if nodegroup == 65536 || nodegroup == -256 {

pkg/mgmapi/config_reader.go

+22-11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package mgmapi
77
import (
88
"encoding/base64"
99
"encoding/binary"
10+
"github.com/mysql/ndb-operator/config/debug"
1011
)
1112

1213
type configValue interface{}
@@ -29,7 +30,8 @@ func getNewConfigReader(base64EncodedData string) *configReader {
2930
// decode the string
3031
decodedData, err := base64.StdEncoding.DecodeString(base64EncodedData)
3132
if err != nil {
32-
panic("failed to decode config string : " + err.Error())
33+
debug.Panic("failed to decode config string : " + err.Error())
34+
return nil
3335
}
3436

3537
return &configReader{data: decodedData}
@@ -44,11 +46,11 @@ func (cr *configReader) readUint32() uint32 {
4446

4547
// readString reads a string from the data at the current offset
4648
func (cr *configReader) readString() string {
47-
// Extract the length of the string first - null character
48-
// is present at the end and should not be read.
49-
strLen := cr.readUint32() - 1
50-
//
51-
s := string(cr.data[cr.offset : cr.offset+strLen])
49+
// Extract the length of the string
50+
strLen := cr.readUint32()
51+
// Extract the string.
52+
// Null character is present at the end and should not be read.
53+
s := string(cr.data[cr.offset : cr.offset+strLen-1])
5254
// update offset
5355
strLen = strLen + ((4 - (strLen & 3)) & 3)
5456
cr.offset += strLen
@@ -97,6 +99,8 @@ func (cr *configReader) readEntry() (uint32, configValue) {
9799
{
98100
value = cr.readString()
99101
}
102+
default:
103+
debug.Panic("unsupported keyType in readEntry()")
100104
}
101105

102106
return key, value
@@ -172,10 +176,11 @@ func (cr *configReader) readEntryFromSection(
172176
// Node Section
173177
sectionNodeId := configValues[nodeCfgNodeId]
174178
if sectionNodeId == nil {
175-
panic("nodeId not found in section")
179+
debug.Panic("nodeId not found in section")
180+
return true
176181
}
177182

178-
if nodeIdFilter != 0 && nodeIdFilter != sectionNodeId {
183+
if nodeIdFilter != 0 && nodeIdFilter != sectionNodeId.(uint32) {
179184
// Caller not interested in this node
180185
return false
181186
}
@@ -220,9 +225,10 @@ func (cr *configReader) readConfig(sectionTypeFilter cfgSectionType, fromNodeId,
220225

221226
cr.totalLengthInWords = cr.readUint32()
222227
cr.version = cr.readUint32()
223-
// panic if the version is not what we expect
228+
// configReader can handle only version 2
224229
if cr.version != 2 {
225-
panic("unexpected version in get config reply")
230+
debug.Panic("unexpected version in get config reply")
231+
return nil
226232
}
227233

228234
cr.numOfDefaultSections = cr.readUint32()
@@ -264,7 +270,8 @@ func (cr *configReader) readConfig(sectionTypeFilter cfgSectionType, fromNodeId,
264270
}
265271

266272
// control should never reach here if the method is used right
267-
panic("failed to find the desired config key")
273+
debug.Panic("failed to find the desired config key")
274+
return nil
268275
}
269276

270277
// readConfigFromBase64EncodedData extracts and returns the config value
@@ -273,5 +280,9 @@ func readConfigFromBase64EncodedData(
273280
base64EncodedData string, sectionTypeFilter cfgSectionType, fromNodeId, configKey uint32) configValue {
274281
// create a config reader and read the data
275282
cr := getNewConfigReader(base64EncodedData)
283+
if cr == nil {
284+
return nil
285+
}
286+
276287
return cr.readConfig(sectionTypeFilter, fromNodeId, configKey)
277288
}

0 commit comments

Comments
 (0)