-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2679 from wfernandes/clusterctl-local-overrides
✨ Clusterctl local overrides
- Loading branch information
Showing
11 changed files
with
328 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
Copyright 2019 The Kubernetes Authors. | ||
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 repository | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
"k8s.io/client-go/util/homedir" | ||
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" | ||
) | ||
|
||
const ( | ||
overrideFolder = "overrides" | ||
overrideFolderKey = "overridesFolder" | ||
) | ||
|
||
// Overrider provides behavior to determine the overrides layer. | ||
type Overrider interface { | ||
Path() string | ||
} | ||
|
||
// overrides implements the Overrider interface. | ||
type overrides struct { | ||
configVariablesClient config.VariablesClient | ||
providerLabel string | ||
version string | ||
filePath string | ||
} | ||
|
||
type newOverrideInput struct { | ||
configVariablesClient config.VariablesClient | ||
provider config.Provider | ||
version string | ||
filePath string | ||
} | ||
|
||
// newOverride returns an Overrider. | ||
func newOverride(o *newOverrideInput) Overrider { | ||
return &overrides{ | ||
configVariablesClient: o.configVariablesClient, | ||
providerLabel: o.provider.ManifestLabel(), | ||
version: o.version, | ||
filePath: o.filePath, | ||
} | ||
} | ||
|
||
// Path returns the fully formed path to the file within the specified | ||
// overrides config. | ||
func (o *overrides) Path() string { | ||
basepath := filepath.Join(homedir.HomeDir(), config.ConfigFolder, overrideFolder) | ||
f, err := o.configVariablesClient.Get(overrideFolderKey) | ||
if err == nil && len(strings.TrimSpace(f)) != 0 { | ||
basepath = f | ||
} | ||
|
||
return filepath.Join( | ||
basepath, | ||
o.providerLabel, | ||
o.version, | ||
o.filePath, | ||
) | ||
} | ||
|
||
// getLocalOverride return local override file from the config folder, if it exists. | ||
// This is required for development purposes, but it can be used also in production as a workaround for problems on the official repositories | ||
func getLocalOverride(info *newOverrideInput) ([]byte, error) { | ||
overridePath := newOverride(info).Path() | ||
// it the local override exists, use it | ||
_, err := os.Stat(overridePath) | ||
if err == nil { | ||
content, err := ioutil.ReadFile(overridePath) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to read local override for %s", overridePath) | ||
} | ||
return content, nil | ||
} | ||
|
||
// it the local override does not exists, return (so files from the provider's repository could be used) | ||
if os.IsNotExist(err) { | ||
return nil, nil | ||
} | ||
|
||
// blocks for any other error | ||
return nil, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
Copyright 2019 The Kubernetes Authors. | ||
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 repository | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
. "github.com/onsi/gomega" | ||
"k8s.io/client-go/util/homedir" | ||
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" | ||
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" | ||
"sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" | ||
) | ||
|
||
func TestOverrides(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
configVarClient config.VariablesClient | ||
expectedPath string | ||
}{ | ||
{ | ||
name: "returns default overrides path if no config provided", | ||
configVarClient: test.NewFakeVariableClient(), | ||
expectedPath: filepath.Join(homedir.HomeDir(), config.ConfigFolder, overrideFolder, "infrastructure-myinfra", "v1.0.1", "infra-comp.yaml"), | ||
}, | ||
{ | ||
name: "returns default overrides path if config variable is empty", | ||
configVarClient: test.NewFakeVariableClient().WithVar(overrideFolderKey, ""), | ||
expectedPath: filepath.Join(homedir.HomeDir(), config.ConfigFolder, overrideFolder, "infrastructure-myinfra", "v1.0.1", "infra-comp.yaml"), | ||
}, | ||
{ | ||
name: "returns default overrides path if config variable is whitespace", | ||
configVarClient: test.NewFakeVariableClient().WithVar(overrideFolderKey, " "), | ||
expectedPath: filepath.Join(homedir.HomeDir(), config.ConfigFolder, overrideFolder, "infrastructure-myinfra", "v1.0.1", "infra-comp.yaml"), | ||
}, | ||
{ | ||
name: "uses overrides folder from the config variables", | ||
configVarClient: test.NewFakeVariableClient().WithVar(overrideFolderKey, "/Users/foobar/workspace/releases"), | ||
expectedPath: "/Users/foobar/workspace/releases/infrastructure-myinfra/v1.0.1/infra-comp.yaml", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
g := NewWithT(t) | ||
provider := config.NewProvider("myinfra", "", clusterctlv1.InfrastructureProviderType) | ||
override := newOverride(&newOverrideInput{ | ||
configVariablesClient: tt.configVarClient, | ||
provider: provider, | ||
version: "v1.0.1", | ||
filePath: "infra-comp.yaml", | ||
}) | ||
|
||
g.Expect(override.Path()).To(Equal(tt.expectedPath)) | ||
}) | ||
} | ||
} | ||
|
||
func TestGetLocalOverrides(t *testing.T) { | ||
t.Run("returns contents of file successfully", func(t *testing.T) { | ||
g := NewWithT(t) | ||
tmpDir := createTempDir(t) | ||
defer os.RemoveAll(tmpDir) | ||
|
||
createLocalTestProviderFile(t, tmpDir, "infrastructure-myinfra/v1.0.1/infra-comp.yaml", "foo: bar") | ||
|
||
info := &newOverrideInput{ | ||
configVariablesClient: test.NewFakeVariableClient().WithVar(overrideFolderKey, tmpDir), | ||
provider: config.NewProvider("myinfra", "", clusterctlv1.InfrastructureProviderType), | ||
version: "v1.0.1", | ||
filePath: "infra-comp.yaml", | ||
} | ||
|
||
b, err := getLocalOverride(info) | ||
g.Expect(err).ToNot(HaveOccurred()) | ||
g.Expect(string(b)).To(Equal("foo: bar")) | ||
}) | ||
|
||
t.Run("doesn't return error if file does not exist", func(t *testing.T) { | ||
g := NewWithT(t) | ||
|
||
info := &newOverrideInput{ | ||
configVariablesClient: test.NewFakeVariableClient().WithVar(overrideFolderKey, "do-not-exist"), | ||
provider: config.NewProvider("myinfra", "", clusterctlv1.InfrastructureProviderType), | ||
version: "v1.0.1", | ||
filePath: "infra-comp.yaml", | ||
} | ||
|
||
_, err := getLocalOverride(info) | ||
g.Expect(err).ToNot(HaveOccurred()) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.