Skip to content

Commit d449c62

Browse files
committed
add openshift ex config patch to modify master-config.yaml
1 parent 16d6863 commit d449c62

File tree

8 files changed

+327
-46
lines changed

8 files changed

+327
-46
lines changed

contrib/completions/bash/openshift

+87
Original file line numberDiff line numberDiff line change
@@ -15537,6 +15537,92 @@ _openshift_ex_build-chain()
1553715537
must_have_one_noun=()
1553815538
}
1553915539

15540+
_openshift_ex_config_patch()
15541+
{
15542+
last_command="openshift_ex_config_patch"
15543+
commands=()
15544+
15545+
flags=()
15546+
two_word_flags=()
15547+
flags_with_completion=()
15548+
flags_completion=()
15549+
15550+
flags+=("--patch=")
15551+
two_word_flags+=("-p")
15552+
flags+=("--type=")
15553+
flags+=("--api-version=")
15554+
flags+=("--as=")
15555+
flags+=("--certificate-authority=")
15556+
flags_with_completion+=("--certificate-authority")
15557+
flags_completion+=("_filedir")
15558+
flags+=("--client-certificate=")
15559+
flags_with_completion+=("--client-certificate")
15560+
flags_completion+=("_filedir")
15561+
flags+=("--client-key=")
15562+
flags_with_completion+=("--client-key")
15563+
flags_completion+=("_filedir")
15564+
flags+=("--cluster=")
15565+
flags+=("--config=")
15566+
flags_with_completion+=("--config")
15567+
flags_completion+=("_filedir")
15568+
flags+=("--context=")
15569+
flags+=("--google-json-key=")
15570+
flags+=("--insecure-skip-tls-verify")
15571+
flags+=("--log-flush-frequency=")
15572+
flags+=("--match-server-version")
15573+
flags+=("--namespace=")
15574+
two_word_flags+=("-n")
15575+
flags+=("--server=")
15576+
flags+=("--token=")
15577+
flags+=("--user=")
15578+
15579+
must_have_one_flag=()
15580+
must_have_one_flag+=("--patch=")
15581+
must_have_one_flag+=("-p")
15582+
must_have_one_noun=()
15583+
}
15584+
15585+
_openshift_ex_config()
15586+
{
15587+
last_command="openshift_ex_config"
15588+
commands=()
15589+
commands+=("patch")
15590+
15591+
flags=()
15592+
two_word_flags=()
15593+
flags_with_completion=()
15594+
flags_completion=()
15595+
15596+
flags+=("--api-version=")
15597+
flags+=("--as=")
15598+
flags+=("--certificate-authority=")
15599+
flags_with_completion+=("--certificate-authority")
15600+
flags_completion+=("_filedir")
15601+
flags+=("--client-certificate=")
15602+
flags_with_completion+=("--client-certificate")
15603+
flags_completion+=("_filedir")
15604+
flags+=("--client-key=")
15605+
flags_with_completion+=("--client-key")
15606+
flags_completion+=("_filedir")
15607+
flags+=("--cluster=")
15608+
flags+=("--config=")
15609+
flags_with_completion+=("--config")
15610+
flags_completion+=("_filedir")
15611+
flags+=("--context=")
15612+
flags+=("--google-json-key=")
15613+
flags+=("--insecure-skip-tls-verify")
15614+
flags+=("--log-flush-frequency=")
15615+
flags+=("--match-server-version")
15616+
flags+=("--namespace=")
15617+
two_word_flags+=("-n")
15618+
flags+=("--server=")
15619+
flags+=("--token=")
15620+
flags+=("--user=")
15621+
15622+
must_have_one_flag=()
15623+
must_have_one_noun=()
15624+
}
15625+
1554015626
_openshift_ex_options()
1554115627
{
1554215628
last_command="openshift_ex_options"
@@ -15698,6 +15784,7 @@ _openshift_ex()
1569815784
commands=()
1569915785
commands+=("ipfailover")
1570015786
commands+=("build-chain")
15787+
commands+=("config")
1570115788
commands+=("options")
1570215789
commands+=("sync-groups")
1570315790
commands+=("prune-groups")

hack/test-cmd.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,12 @@ openshift start \
182182
--images="${USE_IMAGES}"
183183

184184
# Don't try this at home. We don't have flags for setting etcd ports in the config, but we want deconflicted ones. Use sed to replace defaults in a completely unsafe way
185-
os::util::sed "s/:4001$/:${ETCD_PORT}/g" ${SERVER_CONFIG_DIR}/master/master-config.yaml
186-
os::util::sed "s/:7001$/:${ETCD_PEER_PORT}/g" ${SERVER_CONFIG_DIR}/master/master-config.yaml
185+
cp ${SERVER_CONFIG_DIR}/master/master-config.yaml ${SERVER_CONFIG_DIR}/master/master-config.orig.yaml
186+
openshift ex config patch ${SERVER_CONFIG_DIR}/master/master-config.orig.yaml --patch="{\"etcdConfig\": {\"address\": \"${ETCD_HOST}:${ETCD_PORT}\"}}" | \
187+
openshift ex config patch - --patch="{\"etcdConfig\": {\"servingInfo\": {\"bindAddress\": \"${API_HOST}:${ETCD_PORT}\"}}}" | \
188+
openshift ex config patch - --type json --patch="[{\"op\": \"replace\", \"path\": \"/etcdClientInfo/urls/0\", \"value\": \"${API_SCHEME}://${ETCD_HOST}:${ETCD_PORT}\"},{\"op\": \"remove\", \"path\": \"/etcdClientInfo/urls/1\"}]" | \
189+
openshift ex config patch - --patch="{\"etcdConfig\": {\"peerAddress\": \"${ETCD_HOST}:${ETCD_PEER_PORT}\"}}" | \
190+
openshift ex config patch - --patch="{\"etcdConfig\": {\"peerServingInfo\": {\"bindAddress\": \"${API_HOST}:${ETCD_PEER_PORT}\"}}}" > ${SERVER_CONFIG_DIR}/master/master-config.yaml
187191

188192
# Start openshift
189193
OPENSHIFT_ON_PANIC=crash openshift start master \

hack/util.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ function configure_os_server {
8484

8585

8686
# Don't try this at home. We don't have flags for setting etcd ports in the config, but we want deconflicted ones. Use sed to replace defaults in a completely unsafe way
87-
os::util::sed "s/:4001$/:${ETCD_PORT}/g" ${SERVER_CONFIG_DIR}/master/master-config.yaml
88-
os::util::sed "s/:7001$/:${ETCD_PEER_PORT}/g" ${SERVER_CONFIG_DIR}/master/master-config.yaml
87+
cp ${SERVER_CONFIG_DIR}/master/master-config.yaml ${SERVER_CONFIG_DIR}/master/master-config.orig.yaml
88+
openshift ex config patch ${SERVER_CONFIG_DIR}/master/master-config.orig.yaml --patch="{\"etcdConfig\": {\"address\": \"${ETCD_HOST}:${ETCD_PORT}\"}}" | \
89+
openshift ex config patch - --patch="{\"etcdConfig\": {\"servingInfo\": {\"bindAddress\": \"${API_HOST}:${ETCD_PORT}\"}}}" | \
90+
openshift ex config patch - --type json --patch="[{\"op\": \"replace\", \"path\": \"/etcdClientInfo/urls/0\", \"value\": \"${API_SCHEME}://${ETCD_HOST}:${ETCD_PORT}\"},{\"op\": \"remove\", \"path\": \"/etcdClientInfo/urls/1\"}]" | \
91+
openshift ex config patch - --patch="{\"etcdConfig\": {\"peerAddress\": \"${ETCD_HOST}:${ETCD_PEER_PORT}\"}}" | \
92+
openshift ex config patch - --patch="{\"etcdConfig\": {\"peerServingInfo\": {\"bindAddress\": \"${API_HOST}:${ETCD_PEER_PORT}\"}}}" > ${SERVER_CONFIG_DIR}/master/master-config.yaml
8993

9094

9195
# Make oc use ${MASTER_CONFIG_DIR}/admin.kubeconfig, and ignore anything in the running user's $HOME dir

pkg/cmd/experimental/config/config.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package config
2+
3+
import (
4+
"io"
5+
6+
"github.com/spf13/cobra"
7+
8+
cmdutil "github.com/openshift/origin/pkg/cmd/util"
9+
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
10+
)
11+
12+
const ConfigRecommendedName = "config"
13+
14+
const configLong = `
15+
Manage cluster configuration files like master-config.yaml.
16+
`
17+
18+
func NewCmdConfig(name, fullName string, f *clientcmd.Factory, out, errout io.Writer) *cobra.Command {
19+
cmd := &cobra.Command{
20+
Use: name,
21+
Short: "Manage config",
22+
Long: configLong,
23+
Run: cmdutil.DefaultSubCommandRun(out),
24+
}
25+
26+
cmd.AddCommand(NewCmdPatch(PatchRecommendedName, fullName+" "+PatchRecommendedName, f, out))
27+
28+
return cmd
29+
}

pkg/cmd/experimental/config/patch.go

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package config
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"io"
7+
"strings"
8+
9+
"github.com/evanphx/json-patch"
10+
"github.com/spf13/cobra"
11+
12+
"k8s.io/kubernetes/pkg/api"
13+
"k8s.io/kubernetes/pkg/kubectl"
14+
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
15+
"k8s.io/kubernetes/pkg/kubectl/resource"
16+
"k8s.io/kubernetes/pkg/runtime"
17+
"k8s.io/kubernetes/pkg/util/sets"
18+
"k8s.io/kubernetes/pkg/util/strategicpatch"
19+
"k8s.io/kubernetes/pkg/util/yaml"
20+
21+
configapi "github.com/openshift/origin/pkg/cmd/server/api"
22+
configapiinstall "github.com/openshift/origin/pkg/cmd/server/api/install"
23+
"github.com/openshift/origin/pkg/cmd/util/clientcmd"
24+
)
25+
26+
const PatchRecommendedName = "patch"
27+
28+
var patchTypes = map[string]api.PatchType{"json": api.JSONPatchType, "merge": api.MergePatchType, "strategic": api.StrategicMergePatchType}
29+
30+
// PatchOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
31+
// referencing the cmd.Flags()
32+
type PatchOptions struct {
33+
Filename string
34+
Patch string
35+
PatchType api.PatchType
36+
37+
Builder *resource.Builder
38+
39+
Out io.Writer
40+
}
41+
42+
const (
43+
patch_long = `Patch the master-config.yaml or node-config.yaml`
44+
patch_example = `
45+
# Set the auditConfig.enabled value to true
46+
%[1]s openshift.local.config/master/master-config.yaml --patch='{"auditConfig": {"enabled": true}}'`
47+
)
48+
49+
func NewCmdPatch(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
50+
o := &PatchOptions{Out: out}
51+
52+
cmd := &cobra.Command{
53+
Use: name + " FILENAME -p PATCH",
54+
Short: "Update field(s) of a resource using a patch.",
55+
Long: patch_long,
56+
Example: patch_example,
57+
Run: func(cmd *cobra.Command, args []string) {
58+
cmdutil.CheckErr(o.Complete(f, cmd, args))
59+
cmdutil.CheckErr(o.Validate())
60+
cmdutil.CheckErr(o.RunPatch())
61+
},
62+
}
63+
cmd.Flags().StringVarP(&o.Patch, "patch", "p", "", "The patch to be applied to the resource JSON file.")
64+
cmd.MarkFlagRequired("patch")
65+
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
66+
67+
return cmd
68+
}
69+
70+
func (o *PatchOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string) error {
71+
if len(args) != 1 {
72+
return fmt.Errorf("exactly one FILENAME is allowed: %v", args)
73+
}
74+
o.Filename = args[0]
75+
76+
patchTypeString := strings.ToLower(cmdutil.GetFlagString(cmd, "type"))
77+
ok := false
78+
o.PatchType, ok = patchTypes[patchTypeString]
79+
if !ok {
80+
return cmdutil.UsageError(cmd, fmt.Sprintf("--type must be one of %v, not %q", sets.StringKeySet(patchTypes).List(), patchTypeString))
81+
}
82+
83+
o.Builder = resource.NewBuilder(configapiinstall.NewRESTMapper(), configapi.Scheme, resource.DisabledClientForMapping{}, configapi.Codecs.LegacyCodec())
84+
85+
return nil
86+
}
87+
88+
func (o *PatchOptions) Validate() error {
89+
if len(o.Patch) == 0 {
90+
return errors.New("must specify -p to patch")
91+
}
92+
if len(o.Filename) == 0 {
93+
return errors.New("filename is required")
94+
}
95+
96+
return nil
97+
}
98+
99+
func (o *PatchOptions) RunPatch() error {
100+
patchBytes, err := yaml.ToJSON([]byte(o.Patch))
101+
if err != nil {
102+
return fmt.Errorf("unable to parse %q: %v", o.Patch, err)
103+
}
104+
105+
r := o.Builder.
106+
FilenameParam(false, false, o.Filename).
107+
Flatten().
108+
Do()
109+
err = r.Err()
110+
if err != nil {
111+
return err
112+
}
113+
114+
infos, err := r.Infos()
115+
if err != nil {
116+
return err
117+
}
118+
if len(infos) > 1 {
119+
return fmt.Errorf("multiple resources provided")
120+
}
121+
info := infos[0]
122+
123+
originalObjJS, err := runtime.Encode(configapi.Codecs.LegacyCodec(), info.VersionedObject.(runtime.Object))
124+
if err != nil {
125+
return err
126+
}
127+
patchedObj, err := configapi.Scheme.DeepCopy(info.VersionedObject)
128+
if err != nil {
129+
return err
130+
}
131+
originalPatchedObjJS, err := getPatchedJS(o.PatchType, originalObjJS, patchBytes, patchedObj.(runtime.Object))
132+
if err != nil {
133+
return err
134+
}
135+
136+
rawExtension := &runtime.Unknown{
137+
Raw: originalPatchedObjJS,
138+
}
139+
printer, _, err := kubectl.GetPrinter("yaml", "")
140+
if err != nil {
141+
return err
142+
}
143+
if err := printer.PrintObj(rawExtension, o.Out); err != nil {
144+
return err
145+
}
146+
147+
return nil
148+
}
149+
150+
func getPatchedJS(patchType api.PatchType, originalJS, patchJS []byte, obj runtime.Object) ([]byte, error) {
151+
switch patchType {
152+
case api.JSONPatchType:
153+
patchObj, err := jsonpatch.DecodePatch(patchJS)
154+
if err != nil {
155+
return nil, err
156+
}
157+
return patchObj.Apply(originalJS)
158+
159+
case api.MergePatchType:
160+
return jsonpatch.MergePatch(originalJS, patchJS)
161+
162+
case api.StrategicMergePatchType:
163+
return strategicpatch.StrategicMergePatchData(originalJS, patchJS, obj)
164+
165+
default:
166+
// only here as a safety net - go-restful filters content-type
167+
return nil, fmt.Errorf("unknown Content-Type header for patch: %v", patchType)
168+
}
169+
}

pkg/cmd/openshift/openshift.go

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/openshift/origin/pkg/cmd/cli"
1616
"github.com/openshift/origin/pkg/cmd/cli/cmd"
1717
"github.com/openshift/origin/pkg/cmd/experimental/buildchain"
18+
configcmd "github.com/openshift/origin/pkg/cmd/experimental/config"
1819
exipfailover "github.com/openshift/origin/pkg/cmd/experimental/ipfailover"
1920
"github.com/openshift/origin/pkg/cmd/flagtypes"
2021
"github.com/openshift/origin/pkg/cmd/infra/builder"
@@ -161,6 +162,7 @@ func newExperimentalCommand(name, fullName string) *cobra.Command {
161162
experimental.AddCommand(validate.NewCommandValidate(validate.ValidateRecommendedName, fullName+" "+validate.ValidateRecommendedName, out))
162163
experimental.AddCommand(exipfailover.NewCmdIPFailoverConfig(f, fullName, "ipfailover", out, errout))
163164
experimental.AddCommand(buildchain.NewCmdBuildChain(name, fullName+" "+buildchain.BuildChainRecommendedCommandName, f, out))
165+
experimental.AddCommand(configcmd.NewCmdConfig(configcmd.ConfigRecommendedName, fullName+" "+configcmd.ConfigRecommendedName, f, out, errout))
164166
deprecatedDiag := diagnostics.NewCmdDiagnostics(diagnostics.DiagnosticsRecommendedName, fullName+" "+diagnostics.DiagnosticsRecommendedName, out)
165167
deprecatedDiag.Deprecated = fmt.Sprintf(`use "oadm %[1]s" to run diagnostics instead.`, diagnostics.DiagnosticsRecommendedName)
166168
experimental.AddCommand(deprecatedDiag)

pkg/cmd/server/api/install/install.go

+28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package install
22

33
import (
4+
"fmt"
5+
46
"github.com/golang/glog"
57

68
"k8s.io/kubernetes/pkg/api/meta"
@@ -54,3 +56,29 @@ func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
5456
}
5557
}
5658
}
59+
60+
func interfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
61+
switch version {
62+
case configapiv1.SchemeGroupVersion:
63+
return &meta.VersionInterfaces{
64+
ObjectConvertor: configapi.Scheme,
65+
MetadataAccessor: accessor,
66+
}, nil
67+
68+
default:
69+
return nil, fmt.Errorf("unsupported storage version: %s", version)
70+
}
71+
}
72+
73+
func NewRESTMapper() meta.RESTMapper {
74+
mapper := meta.NewDefaultRESTMapper(availableVersions, interfacesFor)
75+
// enumerate all supported versions, get the kinds, and register with the mapper how to address
76+
// our resources.
77+
for _, gv := range availableVersions {
78+
for kind := range configapi.Scheme.KnownTypes(gv) {
79+
mapper.Add(gv.WithKind(kind), meta.RESTScopeRoot)
80+
}
81+
}
82+
83+
return mapper
84+
}

0 commit comments

Comments
 (0)