1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] Version Check V2 (#1348)

This commit is contained in:
Adam Janikowski 2023-07-06 14:33:39 +02:00 committed by GitHub
parent a3206f0c58
commit 44792d2679
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 401 additions and 17 deletions

View file

@ -8,6 +8,7 @@
- (Improvement) Extract Agency Timeout
- (Feature) Rebalancer V2
- (Bugfix) Fix for ContextExceeded error during backup upload
- (Feature) Version Check V2
## [1.2.30](https://github.com/arangodb/kube-arangodb/tree/1.2.30) (2023-06-16)
- (Feature) AgencyCache Interface

View file

@ -506,6 +506,7 @@ run-unit-tests: $(SOURCES)
$(REPOPATH)/pkg/storage \
$(REPOPATH)/pkg/crd/... \
$(REPOPATH)/pkg/util/... \
$(REPOPATH)/cmd/... \
$(REPOPATH)/pkg/handlers/...
# Release building

View file

@ -63,6 +63,7 @@ covers individual newer features separately.
| Encryption Key Rotation Support | 1.2.0 | > 3.7.0 | Enterprise | 1.0.3 | NotSupported | False | --deployment.feature.encryption-rotation | N/A |
| Version Check | 1.1.4 | >= 3.6.0 | Community, Enterprise | 1.1.4 | Alpha | False | --deployment.feature.upgrade-version-check | N/A |
| Version Check | 1.2.23 | >= 3.6.0 | Community, Enterprise | 1.1.4 | Production | True | --deployment.feature.upgrade-version-check | N/A |
| Version Check V2 | 1.2.31 | >= 3.6.0 | Community, Enterprise | 1.2.31 | Alpha | False | --deployment.feature.upgrade-version-check-v2 | N/A |
| Operator Maintenance Management Support | 1.2.0 | >= 3.6.0 | Community, Enterprise | 1.0.7 | Production | True | --deployment.feature.maintenance | N/A |
| Graceful Restart | 1.2.5 | >= 3.6.0 | Community, Enterprise | 1.0.7 | Production | True | --deployment.feature.graceful-shutdown | N/A |
| Optional Graceful Restart | 1.2.25 | >= 3.6.0 | Community, Enterprise | 1.2.5 | Beta | True | --deployment.feature.optional-graceful-shutdown | N/A |

View file

@ -242,6 +242,10 @@ func Execute() int {
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
if err := cmdMain.Execute(); err != nil {
if v, ok := err.(CommandExitCode); ok {
return v.ExitCode
}
return 1
}

39
cmd/cmd_exit_code.go Normal file
View file

@ -0,0 +1,39 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import (
"fmt"
)
type CommandExitCode struct {
ExitCode int
}
func (c CommandExitCode) Error() string {
return fmt.Sprintf("Command exit: %d", c.ExitCode)
}
func Exit(code int) error {
return CommandExitCode{
ExitCode: code,
}
}

34
cmd/cmd_exit_code_test.go Normal file
View file

@ -0,0 +1,34 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import (
"testing"
"github.com/stretchr/testify/require"
)
func ensureExitCode(t *testing.T, err error, code int) {
require.Error(t, err)
v, ok := err.(CommandExitCode)
require.True(t, ok)
require.Equal(t, v.ExitCode, code)
}

View file

@ -0,0 +1,99 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import (
"encoding/json"
"os"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
const cmdVersionCheckInitContainersInvalidVersionExitCode = 11
type cmdVersionCheckInitContainersInputStruct struct {
versionPath string
major, minor int
}
var (
cmdVersionCheckInitContainers = &cobra.Command{
Use: "version-check",
RunE: cmdVersionCheckInitContainersInput.Run,
}
cmdVersionCheckInitContainersInput cmdVersionCheckInitContainersInputStruct
)
type cmdVersionCheckInitContainersData struct {
Version int `json:"version,omitempty"`
}
func init() {
cmdInitContainers.AddCommand(cmdVersionCheckInitContainers)
f := cmdVersionCheckInitContainers.Flags()
f.StringVar(&cmdVersionCheckInitContainersInput.versionPath, "path", "", "Path to the VERSION file")
f.IntVar(&cmdVersionCheckInitContainersInput.major, "major", 0, "Major version of the ArangoDB. 0 if check is disabled")
f.IntVar(&cmdVersionCheckInitContainersInput.minor, "minor", 0, "Minor version of the ArangoDB. 0 if check is disabled")
}
func (c cmdVersionCheckInitContainersInputStruct) Run(cmd *cobra.Command, args []string) error {
if c.versionPath == "" {
return errors.Errorf("Path cannot be empty")
}
if data, err := os.ReadFile(c.versionPath); err != nil {
log.Err(err).Msg("File is not readable, continue")
return nil
} else {
major, minor, _, ok := extractVersionFromData(data)
if !ok {
return nil
}
if c.major != 0 {
if c.major != major {
return Exit(cmdVersionCheckInitContainersInvalidVersionExitCode)
}
if c.minor != 0 {
if c.minor != minor {
return Exit(cmdVersionCheckInitContainersInvalidVersionExitCode)
}
}
}
return nil
}
}
func extractVersionFromData(data []byte) (int, int, int, bool) {
var c cmdVersionCheckInitContainersData
if err := json.Unmarshal(data, &c); err != nil {
log.Err(err).Msg("Invalid json, continue")
return 0, 0, 0, false
}
return c.Version / 10000, c.Version % 10000 / 100, c.Version % 100, true
}

View file

@ -0,0 +1,88 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import (
"encoding/json"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
)
func saveVersionFile(t *testing.T, v int, updates ...func(in *cmdVersionCheckInitContainersInputStruct)) *cmdVersionCheckInitContainersInputStruct {
var q cmdVersionCheckInitContainersData
q.Version = v
d, err := json.Marshal(q)
require.NoError(t, err)
var n cmdVersionCheckInitContainersInputStruct
n.versionPath = fmt.Sprintf("%s/VERSION", t.TempDir())
require.NoError(t, os.WriteFile(n.versionPath, d, 0644))
for _, u := range updates {
u(&n)
}
return &n
}
func Test_extractVersionFromData(t *testing.T) {
check := func(valid bool, name string, version int, updates ...func(in *cmdVersionCheckInitContainersInputStruct)) {
t.Run(name, func(t *testing.T) {
err := saveVersionFile(t, version, updates...).Run(nil, nil)
if valid {
require.NoError(t, err)
} else {
ensureExitCode(t, err, cmdVersionCheckInitContainersInvalidVersionExitCode)
}
})
}
check(true, "3.9.10_optional", 30910)
check(true, "3.9.10_required_major", 30910, func(in *cmdVersionCheckInitContainersInputStruct) {
in.major = 3
})
check(true, "3.9.10_required_minor", 30910, func(in *cmdVersionCheckInitContainersInputStruct) {
in.major = 3
in.minor = 9
})
check(false, "3.9.10_required_major_mismatch", 30910, func(in *cmdVersionCheckInitContainersInputStruct) {
in.major = 4
})
check(false, "3.9.10_required_minor_mismatch", 30910, func(in *cmdVersionCheckInitContainersInputStruct) {
in.major = 3
in.minor = 5
})
check(true, "3.9.10_required_minor_only_mismatch", 30910, func(in *cmdVersionCheckInitContainersInputStruct) {
in.minor = 5
})
}

37
cmd/init_containers.go Normal file
View file

@ -0,0 +1,37 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package cmd
import "github.com/spf13/cobra"
var (
cmdInitContainers = &cobra.Command{
Use: "init-containers",
Run: func(cmd *cobra.Command, args []string) {
},
Hidden: true,
}
)
func init() {
cmdMain.AddCommand(cmdInitContainers)
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ package features
func init() {
registerFeature(upgradeVersionCheck)
registerFeature(upgradeVersionCheckV2)
}
var upgradeVersionCheck Feature = &feature{
@ -32,6 +33,18 @@ var upgradeVersionCheck Feature = &feature{
enabledByDefault: true,
}
var upgradeVersionCheckV2 Feature = &feature{
name: "upgrade-version-check-v2",
description: "Enable initContainer with pre version check based by Operator",
version: "3.6.0",
enterpriseRequired: false,
enabledByDefault: true,
}
func UpgradeVersionCheck() Feature {
return upgradeVersionCheck
}
func UpgradeVersionCheckV2() Feature {
return upgradeVersionCheckV2
}

View file

@ -470,13 +470,18 @@ func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector)
// VersionCheck Container
{
versionArgs := pod.UpgradeVersionCheck().Args(m.AsInput())
if len(versionArgs) > 0 {
switch m.group {
case api.ServerGroupAgents, api.ServerGroupDBServers, api.ServerGroupSingle:
if features.UpgradeVersionCheckV2().Enabled() {
c := k8sutil.ArangodVersionCheckInitContainer(api.ServerGroupReservedInitContainerNameVersionCheck, executable, m.resources.context.GetOperatorImage(),
m.imageInfo.ArangoDBVersion, m.groupSpec.SecurityContext.NewSecurityContext())
initContainers = append(initContainers, c)
} else if features.UpgradeVersionCheck().Enabled() {
upgradeContainer := &ArangoVersionCheckContainer{
m.GetContainerCreator(),
cachedStatus,
m.AsInput(),
versionArgs,
pod.UpgradeVersionCheck().Args(m.AsInput()),
}
c, err := k8sutil.NewContainer(upgradeContainer)
@ -488,6 +493,7 @@ func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector)
}
}
}
}
return initContainers, nil
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View file

@ -0,0 +1,61 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package k8sutil
import (
"fmt"
"path/filepath"
core "k8s.io/api/core/v1"
"github.com/arangodb/go-driver"
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
)
// ArangodVersionCheckInitContainer creates a container configured to check version.
func ArangodVersionCheckInitContainer(name, executable, operatorImage string, version driver.Version, securityContext *core.SecurityContext) core.Container {
versionFile := filepath.Join(shared.ArangodVolumeMountDir, "VERSION-1")
var command = []string{
executable,
"init-containers",
"version-check",
"--path",
versionFile,
}
if v := version.Major(); v > 0 {
command = append(command,
"--major",
fmt.Sprintf("%d", v))
if v := version.Minor(); v > 0 {
command = append(command,
"--minor",
fmt.Sprintf("%d", v))
}
}
volumes := []core.VolumeMount{
ArangodVolumeMount(),
}
return operatorInitContainer(name, operatorImage, command, securityContext, volumes)
}