Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Open sidebar
Ijaz Ahmad
ksonnet
Commits
e0e68f8f
Unverified
Commit
e0e68f8f
authored
Apr 03, 2018
by
bryanl
Browse files
Update `show` to ksonnet action
Signed-off-by:
bryanl
<
bryanliles@gmail.com
>
parent
352bbaa3
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
348 additions
and
144 deletions
+348
-144
actions/actions.go
actions/actions.go
+2
-0
actions/delete.go
actions/delete.go
+10
-10
actions/show.go
actions/show.go
+88
-0
actions/show_test.go
actions/show_test.go
+69
-0
cmd/actions.go
cmd/actions.go
+3
-3
cmd/flags.go
cmd/flags.go
+1
-0
cmd/show.go
cmd/show.go
+20
-36
cmd/show_test.go
cmd/show_test.go
+20
-95
cmd/version_test.go
cmd/version_test.go
+17
-0
pkg/cluster/show.go
pkg/cluster/show.go
+118
-0
No files found.
actions/actions.go
View file @
e0e68f8f
...
...
@@ -41,6 +41,8 @@ const (
OptionDryRun
=
"dry-run"
// OptionEnvName is envName option.
OptionEnvName
=
"env-name"
// OptionFormat is format option.
OptionFormat
=
"format"
// OptionFs is fs option.
OptionFs
=
"fs"
// OptionGcTag is gcTag option.
...
...
actions/delete.go
View file @
e0e68f8f
...
...
@@ -50,7 +50,7 @@ type Delete struct {
func
newDelete
(
m
map
[
string
]
interface
{},
opts
...
deleteOpt
)
(
*
Delete
,
error
)
{
ol
:=
newOptionLoader
(
m
)
a
:=
&
Delete
{
d
:=
&
Delete
{
app
:
ol
.
loadApp
(),
clientConfig
:
ol
.
loadClientConfig
(),
componentNames
:
ol
.
loadStringSlice
(
OptionComponentNames
),
...
...
@@ -65,20 +65,20 @@ func newDelete(m map[string]interface{}, opts ...deleteOpt) (*Delete, error) {
}
for
_
,
opt
:=
range
opts
{
opt
(
a
)
opt
(
d
)
}
return
a
,
nil
return
d
,
nil
}
func
(
a
*
Delete
)
run
()
error
{
func
(
d
*
Delete
)
run
()
error
{
config
:=
cluster
.
DeleteConfig
{
App
:
a
.
app
,
ClientConfig
:
a
.
clientConfig
,
ComponentNames
:
a
.
componentNames
,
EnvName
:
a
.
envName
,
GracePeriod
:
a
.
gracePeriod
,
App
:
d
.
app
,
ClientConfig
:
d
.
clientConfig
,
ComponentNames
:
d
.
componentNames
,
EnvName
:
d
.
envName
,
GracePeriod
:
d
.
gracePeriod
,
}
return
a
.
runDeleteFn
(
config
)
return
d
.
runDeleteFn
(
config
)
}
pkg/kubecfg/delete
.go
→
actions/show
.go
View file @
e0e68f8f
// Copyright 201
7
The k
ubecfg
authors
// Copyright 201
8
The k
sonnet
authors
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
...
...
@@ -13,72 +13,76 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package
kubecfg
package
actions
import
(
"fmt"
"sort"
log
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/api/errors"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"io"
"os"
"github.com/ksonnet/ksonnet/client"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/
utils
"
"github.com/ksonnet/ksonnet/
pkg/cluster
"
)
// DeleteCmd represents the delete subcommand
type
DeleteCmd
struct
{
App
app
.
App
ClientConfig
*
client
.
Config
Env
string
GracePeriod
int64
}
type
runShowFn
func
(
cluster
.
ShowConfig
,
...
cluster
.
ShowOpts
)
error
func
(
c
*
DeleteCmd
)
Run
(
apiObjects
[]
*
unstructured
.
Unstructured
)
error
{
clientPool
,
discovery
,
namespace
,
err
:=
c
.
ClientConfig
.
RestClient
(
c
.
App
,
&
c
.
Env
)
// RunShow runs `show`.
func
RunShow
(
m
map
[
string
]
interface
{})
error
{
a
,
err
:=
newShow
(
m
)
if
err
!=
nil
{
return
err
}
version
,
err
:=
utils
.
FetchVersion
(
discovery
)
if
err
!=
nil
{
return
err
}
sort
.
Sort
(
sort
.
Reverse
(
utils
.
DependencyOrder
(
apiObjects
)))
deleteOpts
:=
metav1
.
DeleteOptions
{}
if
version
.
Compare
(
1
,
6
)
<
0
{
// 1.5.x option
boolFalse
:=
false
deleteOpts
.
OrphanDependents
=
&
boolFalse
}
else
{
// 1.6.x option (NB: Background is broken)
fg
:=
metav1
.
DeletePropagationForeground
deleteOpts
.
PropagationPolicy
=
&
fg
}
if
c
.
GracePeriod
>=
0
{
deleteOpts
.
GracePeriodSeconds
=
&
c
.
GracePeriod
return
a
.
run
()
}
type
showOpt
func
(
*
Show
)
// Show shows objects.
type
Show
struct
{
app
app
.
App
clientConfig
*
client
.
Config
componentNames
[]
string
envName
string
format
string
out
io
.
Writer
runShowFn
runShowFn
}
// RunShow runs `show`
func
newShow
(
m
map
[
string
]
interface
{},
opts
...
showOpt
)
(
*
Show
,
error
)
{
ol
:=
newOptionLoader
(
m
)
s
:=
&
Show
{
app
:
ol
.
loadApp
(),
componentNames
:
ol
.
loadStringSlice
(
OptionComponentNames
),
envName
:
ol
.
loadString
(
OptionEnvName
),
format
:
ol
.
loadString
(
OptionFormat
),
out
:
os
.
Stdout
,
runShowFn
:
cluster
.
RunShow
,
}
for
_
,
obj
:=
range
apiObjects
{
desc
:=
fmt
.
Sprintf
(
"%s %s"
,
utils
.
ResourceNameFor
(
discovery
,
obj
),
utils
.
FqName
(
obj
))
log
.
Info
(
"Deleting "
,
desc
)
if
ol
.
err
!=
nil
{
return
nil
,
ol
.
err
}
client
,
err
:=
utils
.
ClientForResource
(
clientPool
,
discovery
,
obj
,
namespace
)
if
err
!=
nil
{
return
err
}
for
_
,
opt
:=
range
opts
{
opt
(
s
)
}
err
=
client
.
Delete
(
obj
.
GetName
(),
&
deleteOpts
)
if
err
!=
nil
&&
!
errors
.
IsNotFound
(
err
)
{
return
fmt
.
Errorf
(
"Error deleting %s: %s"
,
desc
,
err
)
}
return
s
,
nil
}
log
.
Debugf
(
"Deleted object: "
,
obj
)
func
(
s
*
Show
)
run
()
error
{
config
:=
cluster
.
ShowConfig
{
App
:
s
.
app
,
ComponentNames
:
s
.
componentNames
,
EnvName
:
s
.
envName
,
Format
:
s
.
format
,
Out
:
s
.
out
,
}
return
nil
return
s
.
runShowFn
(
config
)
}
pkg/kubecfg/show
.go
→
actions/show_test
.go
View file @
e0e68f8f
// Copyright 201
7
The k
ubecfg
authors
// Copyright 201
8
The k
sonnet
authors
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
...
...
@@ -13,59 +13,57 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package
kubecfg
package
actions
import
(
"encoding/json"
"fmt"
"io"
"os"
"testing"
yaml
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
amocks
"github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/ksonnet/ksonnet/pkg/cluster"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// ShowCmd represents the show subcommand
type
ShowCmd
struct
{
Format
string
}
func
TestShow
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionApp
:
appMock
,
OptionComponentNames
:
[]
string
{},
OptionEnvName
:
"default"
,
OptionFormat
:
"yaml"
,
}
func
(
c
ShowCmd
)
Run
(
apiObjects
[]
*
unstructured
.
Unstructured
,
out
io
.
Writer
)
error
{
switch
c
.
Format
{
case
"yaml"
:
for
_
,
obj
:=
range
apiObjects
{
fmt
.
Fprintln
(
out
,
"---"
)
// Urgh. Go via json because we need
// to trigger the custom scheme
// encoding.
buf
,
err
:=
json
.
Marshal
(
obj
)
if
err
!=
nil
{
return
err
}
o
:=
map
[
string
]
interface
{}{}
if
err
:=
json
.
Unmarshal
(
buf
,
&
o
);
err
!=
nil
{
return
err
}
buf
,
err
=
yaml
.
Marshal
(
o
)
if
err
!=
nil
{
return
err
}
out
.
Write
(
buf
)
expected
:=
cluster
.
ShowConfig
{
App
:
appMock
,
ComponentNames
:
[]
string
{},
EnvName
:
"default"
,
Format
:
"yaml"
,
Out
:
os
.
Stdout
,
}
case
"json"
:
enc
:=
json
.
NewEncoder
(
out
)
enc
.
SetIndent
(
""
,
" "
)
for
_
,
obj
:=
range
apiObjects
{
// TODO: this is not valid framing for JSON
if
len
(
apiObjects
)
>
1
{
fmt
.
Fprintln
(
out
,
"---"
)
}
if
err
:=
enc
.
Encode
(
obj
);
err
!=
nil
{
return
err
runShowOpt
:=
func
(
a
*
Show
)
{
a
.
runShowFn
=
func
(
config
cluster
.
ShowConfig
,
opts
...
cluster
.
ShowOpts
)
error
{
assert
.
Equal
(
t
,
expected
,
config
)
return
nil
}
}
default
:
return
fmt
.
Errorf
(
"Unknown --format: %s"
,
c
.
Format
)
}
return
nil
a
,
err
:=
newShow
(
in
,
runShowOpt
)
require
.
NoError
(
t
,
err
)
err
=
a
.
run
()
require
.
NoError
(
t
,
err
)
})
}
func
TestShow_invalid_input
(
t
*
testing
.
T
)
{
withApp
(
t
,
func
(
appMock
*
amocks
.
App
)
{
in
:=
map
[
string
]
interface
{}{
OptionClientConfig
:
"invalid"
,
}
_
,
err
:=
newShow
(
in
)
require
.
Error
(
t
,
err
)
})
}
cmd/actions.go
View file @
e0e68f8f
...
...
@@ -92,9 +92,9 @@ var (
actionRegistryAdd
:
actions
.
RunRegistryAdd
,
actionRegistryDescribe
:
actions
.
RunRegistryDescribe
,
actionRegistryList
:
actions
.
RunRegistryList
,
//
actionShow
actionUpgrade
:
actions
.
RunUpgrade
,
actionValidate
:
actions
.
RunValidate
,
actionShow
:
action
s
.
Run
Show
,
actionUpgrade
:
actions
.
RunUpgrade
,
actionValidate
:
actions
.
RunValidate
,
}
)
...
...
cmd/flags.go
View file @
e0e68f8f
...
...
@@ -46,6 +46,7 @@ const (
shortComponent
=
"c"
shortFilename
=
"f"
shortFormat
=
"o"
shortIndex
=
"i"
shortOutput
=
"o"
shortOverride
=
"o"
...
...
cmd/show.go
View file @
e0e68f8f
...
...
@@ -17,11 +17,10 @@ package cmd
import
(
"fmt"
"os"
"github.com/ksonnet/ksonnet/actions"
"github.com/spf13/cobra"
"github.com/ksonnet/ksonnet/pkg/kubecfg"
"github.com/spf13/viper"
)
const
(
...
...
@@ -29,11 +28,21 @@ const (
showShortDesc
=
"Show expanded manifests for a specific environment."
)
const
(
vShowComponent
=
"show-components"
vShowFormat
=
"show-format"
)
func
init
()
{
RootCmd
.
AddCommand
(
showCmd
)
addEnvCmdFlags
(
showCmd
)
bindJsonnetFlags
(
showCmd
)
showCmd
.
PersistentFlags
()
.
StringP
(
flagFormat
,
"o"
,
"yaml"
,
"Output format. Supported values are: json, yaml"
)
showCmd
.
Flags
()
.
StringSliceP
(
flagComponent
,
shortComponent
,
nil
,
"Name of a specific component (multiple -c flags accepted, allows YAML, JSON, and Jsonnet)"
)
viper
.
BindPFlag
(
vShowComponent
,
showCmd
.
Flags
()
.
Lookup
(
flagComponent
))
showCmd
.
Flags
()
.
StringP
(
flagFormat
,
shortFormat
,
"yaml"
,
"Output format. Supported values are: json, yaml"
)
viper
.
BindPFlag
(
vShowFormat
,
showCmd
.
Flags
()
.
Lookup
(
flagFormat
))
}
var
showCmd
=
&
cobra
.
Command
{
...
...
@@ -75,39 +84,14 @@ ks show dev -c redis -c nginx-server
if
len
(
args
)
!=
1
{
return
fmt
.
Errorf
(
"'show' requires an environment name; use `env list` to see available environments
\n\n
%s"
,
cmd
.
UsageString
())
}
env
:=
args
[
0
]
flags
:=
cmd
.
Flags
()
var
err
error
componentNames
,
err
:=
flags
.
GetStringSlice
(
flagComponent
)
if
err
!=
nil
{
return
err
}
c
:=
kubecfg
.
ShowCmd
{}
c
.
Format
,
err
=
flags
.
GetString
(
flagFormat
)
if
err
!=
nil
{
return
err
}
cwd
,
err
:=
os
.
Getwd
()
if
err
!=
nil
{
return
err
}
te
:=
newCmdObjExpander
(
cmdObjExpanderConfig
{
cmd
:
cmd
,
env
:
env
,
components
:
componentNames
,
cwd
:
cwd
,
})
objs
,
err
:=
te
.
Expand
()
if
err
!=
nil
{
return
err
m
:=
map
[
string
]
interface
{}{
actions
.
OptionApp
:
ka
,
actions
.
OptionComponentNames
:
viper
.
GetStringSlice
(
vShowComponent
),
actions
.
OptionEnvName
:
args
[
0
],
actions
.
OptionFormat
:
viper
.
GetString
(
vShowFormat
),
}
return
c
.
Run
(
objs
,
cmd
.
OutOrStdout
()
)
return
runAction
(
actionShow
,
m
)
},
}
cmd/show_test.go
View file @
e0e68f8f
...
...
@@ -16,106 +16,31 @@
package
cmd
import
(
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
)
func
cmdOutput
(
t
*
testing
.
T
,
args
[]
string
)
string
{
var
buf
bytes
.
Buffer
RootCmd
.
SetOutput
(
&
buf
)
defer
RootCmd
.
SetOutput
(
nil
)
t
.
Log
(
"Running args"
,
args
)
RootCmd
.
SetArgs
(
args
)
if
err
:=
RootCmd
.
Execute
();
err
!=
nil
{
fmt
.
Println
(
buf
.
String
())
t
.
Fatal
(
"command failed:"
,
err
)
}
return
buf
.
String
()
}
func
OffTestShow
(
t
*
testing
.
T
)
{
// cd to the test directory we can run the `show` command.
wd
,
err
:=
os
.
Getwd
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
os
.
Chdir
(
"../testdata/testapp"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
func
()
{
err
=
os
.
Chdir
(
wd
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}()
"github.com/ksonnet/ksonnet/actions"
)
// Run the show command.
formats
:=
map
[
string
]
func
(
string
)
(
interface
{},
error
){
"json"
:
func
(
text
string
)
(
ret
interface
{},
err
error
)
{
err
=
json
.
Unmarshal
([]
byte
(
text
),
&
ret
)
return
func
Test_showCmd
(
t
*
testing
.
T
)
{
cases
:=
[]
cmdTestCase
{
{
name
:
"with no options"
,
args
:
[]
string
{
"show"
,
"default"
},
action
:
actionShow
,
expected
:
map
[
string
]
interface
{}{
actions
.
OptionApp
:
nil
,
actions
.
OptionEnvName
:
"default"
,
actions
.
OptionComponentNames
:
make
([]
string
,
0
),
actions
.
OptionFormat
:
"yaml"
,
},
},
/* Temporarily(!) disabled due to
https://github.com/ksonnet/kubecfg/issues/99
"yaml": func(text string) (ret interface{}, err error) {
err = yaml.Unmarshal([]byte(text), &ret)
return
{
name
:
"with no env"
,
args
:
[]
string
{
"show"
},
action
:
actionShow
,
isErr
:
true
,
},
*/
}
// Use the fact that JSON is also valid YAML ..
expected
:=
`
{
"apiVersion": "v0alpha1",
"kind": "TestObject",
"nil": null,
"bool": true,
"number": 42,
"string": "bar",
"notAVal": "aVal",
"notAnotherVal": "aVal2",
"filevar": "foo\n",
"array": ["one", 2, [3]],
"object": {"foo": "bar"}
}
`
for
format
,
parser
:=
range
formats
{
expected
,
err
:=
parser
(
expected
)
if
err
!=
nil
{
t
.
Errorf
(
"error parsing *expected* value: %s"
,
err
)
}
os
.
Setenv
(
"anVar"
,
"aVal2"
)
defer
os
.
Unsetenv
(
"anVar"
)
output
:=
cmdOutput
(
t
,
[]
string
{
"show"
,
"default"
,
"-o"
,
format
,
"-c"
,
"test"
,
"-V"
,
"aVar=aVal"
,
"-V"
,
"anVar"
,
"--ext-str-file"
,
"filevar="
+
filepath
.
FromSlash
(
"../extvar.file"
),
})
t
.
Log
(
"output is"
,
output
)
actual
,
err
:=
parser
(
output
)
if
err
!=
nil
{
t
.
Errorf
(
"error parsing output of format %s: %s"
,
format
,
err
)
}
else
if
!
reflect
.
DeepEqual
(
expected
,
actual
)
{
t
.
Errorf
(
"format %s expected != actual: %s != %s"
,
format
,
expected
,
actual
)
}
}
runTestCmd
(
t
,
cases
)
}
cmd/version_test.go
View file @
e0e68f8f
...
...
@@ -16,6 +16,8 @@
package
cmd
import
(
"bytes"
"fmt"
"regexp"
"testing"
)
...
...
@@ -28,3 +30,18 @@ func TestVersion(t *testing.T) {
t
.
Error
(
"Failed to find jsonnet version in:"
,
output
)
}
}
func
cmdOutput
(
t
*
testing
.
T
,
args
[]
string
)
string
{
var
buf
bytes
.
Buffer
RootCmd
.
SetOutput
(
&
buf
)
defer
RootCmd
.
SetOutput
(
nil
)
t
.
Log
(
"Running args"
,
args
)
RootCmd
.
SetArgs
(
args
)
if
err
:=
RootCmd
.
Execute
();
err
!=
nil
{
fmt
.
Println
(
buf
.
String
())
t
.
Fatal
(
"command failed:"
,
err
)
}
return
buf
.
String
()
}
pkg/cluster/show.go
0 → 100644
View file @
e0e68f8f
// Copyright 2018 The ksonnet 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
cluster
import
(
"encoding/json"
"fmt"
"io"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/pkg/errors"
yaml
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// ShowConfig is configuration for Show.
type
ShowConfig
struct
{
App
app
.
App
ComponentNames
[]
string
EnvName
string
Format
string
Out
io
.
Writer
}
// ShowOpts is an option for configuring Show.
type
ShowOpts
func
(
*
Show
)
// Show shows objects.
type
Show
struct
{
ShowConfig
// these make it easier to test Show.
findObjectsFn
findObjectsFn
}
// RunShow shows objects for a given configuration.
func
RunShow
(
config
ShowConfig
,
opts
...
ShowOpts
)
error
{
s
:=
&
Show
{
ShowConfig
:
config
,
findObjectsFn
:
findObjects
,
}
for
_
,
opt
:=
range
opts
{
opt
(
s
)
}
return
s
.
Show
()
}
// Show shows objects.
func
(
s
*
Show
)
Show
()
error
{
apiObjects
,
err
:=
s
.
findObjectsFn
(
s
.
App
,
s
.
EnvName
,
s
.
ComponentNames
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"find objects"
)
}
switch
s
.
Format
{
case
"yaml"
:
return
s
.
showYAML
(
apiObjects
)
case
"json"
:
return
s
.
showJSON
(
apiObjects
)
default
:
return
fmt
.
Errorf
(
"Unknown --format: %s"
,
s
.
Format
)