| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
kapi "k8s.io/kubernetes/pkg/api" |
| 10 | 10 |
"k8s.io/kubernetes/pkg/api/errors" |
| 11 | 11 |
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
| 12 |
+ "k8s.io/kubernetes/pkg/kubectl/resource" |
|
| 12 | 13 |
|
| 13 | 14 |
buildapi "github.com/openshift/origin/pkg/build/api" |
| 14 | 15 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| ... | ... |
@@ -68,11 +69,20 @@ func RunCancelBuild(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, arg |
| 68 | 68 |
return err |
| 69 | 69 |
} |
| 70 | 70 |
buildClient := client.Builds(namespace) |
| 71 |
- build, err := buildClient.Get(buildName) |
|
| 71 |
+ |
|
| 72 |
+ mapper, typer := f.Object() |
|
| 73 |
+ obj, err := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). |
|
| 74 |
+ NamespaceParam(namespace). |
|
| 75 |
+ ResourceNames("builds", buildName).
|
|
| 76 |
+ SingleResourceType(). |
|
| 77 |
+ Do().Object() |
|
| 72 | 78 |
if err != nil {
|
| 73 | 79 |
return err |
| 74 | 80 |
} |
| 75 |
- |
|
| 81 |
+ build, ok := obj.(*buildapi.Build) |
|
| 82 |
+ if !ok {
|
|
| 83 |
+ return fmt.Errorf("%q is not a valid build", buildName)
|
|
| 84 |
+ } |
|
| 76 | 85 |
if !isBuildCancellable(build) {
|
| 77 | 86 |
return nil |
| 78 | 87 |
} |
| ... | ... |
@@ -120,7 +120,7 @@ func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.C |
| 120 | 120 |
|
| 121 | 121 |
func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error {
|
| 122 | 122 |
if len(args) > 1 {
|
| 123 |
- return errors.New("only one deploymentConfig name is supported as argument.")
|
|
| 123 |
+ return errors.New("only one deployment config name is supported as argument.")
|
|
| 124 | 124 |
} |
| 125 | 125 |
var err error |
| 126 | 126 |
|
| ... | ... |
@@ -139,11 +139,7 @@ func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Wri |
| 139 | 139 |
o.out = out |
| 140 | 140 |
|
| 141 | 141 |
if len(args) > 0 {
|
| 142 |
- name := args[0] |
|
| 143 |
- if strings.Index(name, "/") == -1 {
|
|
| 144 |
- name = fmt.Sprintf("dc/%s", name)
|
|
| 145 |
- } |
|
| 146 |
- o.deploymentConfigName = name |
|
| 142 |
+ o.deploymentConfigName = args[0] |
|
| 147 | 143 |
} |
| 148 | 144 |
|
| 149 | 145 |
return nil |
| ... | ... |
@@ -151,7 +147,7 @@ func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Wri |
| 151 | 151 |
|
| 152 | 152 |
func (o DeployOptions) Validate() error {
|
| 153 | 153 |
if len(o.deploymentConfigName) == 0 {
|
| 154 |
- return errors.New("a deploymentConfig name is required.")
|
|
| 154 |
+ return errors.New("a deployment config name is required.")
|
|
| 155 | 155 |
} |
| 156 | 156 |
numOptions := 0 |
| 157 | 157 |
if o.deployLatest {
|
| ... | ... |
@@ -175,7 +171,7 @@ func (o DeployOptions) Validate() error {
|
| 175 | 175 |
func (o DeployOptions) RunDeploy() error {
|
| 176 | 176 |
r := o.builder. |
| 177 | 177 |
NamespaceParam(o.namespace). |
| 178 |
- ResourceTypeOrNameArgs(false, o.deploymentConfigName). |
|
| 178 |
+ ResourceNames("deploymentconfigs", o.deploymentConfigName).
|
|
| 179 | 179 |
SingleResourceType(). |
| 180 | 180 |
Do() |
| 181 | 181 |
resultObj, err := r.Object() |
| ... | ... |
@@ -184,7 +180,7 @@ func (o DeployOptions) RunDeploy() error {
|
| 184 | 184 |
} |
| 185 | 185 |
config, ok := resultObj.(*deployapi.DeploymentConfig) |
| 186 | 186 |
if !ok {
|
| 187 |
- return fmt.Errorf("%s is not a valid deploymentconfig", o.deploymentConfigName)
|
|
| 187 |
+ return fmt.Errorf("%s is not a valid deployment config", o.deploymentConfigName)
|
|
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
switch {
|
| ... | ... |
@@ -27,6 +27,7 @@ import ( |
| 27 | 27 |
|
| 28 | 28 |
buildapi "github.com/openshift/origin/pkg/build/api" |
| 29 | 29 |
osclient "github.com/openshift/origin/pkg/client" |
| 30 |
+ osutil "github.com/openshift/origin/pkg/cmd/util" |
|
| 30 | 31 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 31 | 32 |
"github.com/openshift/origin/pkg/generate/git" |
| 32 | 33 |
"github.com/openshift/source-to-image/pkg/tar" |
| ... | ... |
@@ -129,15 +130,37 @@ func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra |
| 129 | 129 |
return cmdutil.UsageError(cmd, "Must pass a name of a build config or specify build name with '--from-build' flag") |
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 |
- name := buildName |
|
| 133 |
- isBuild := true |
|
| 132 |
+ namespace, _, err := f.DefaultNamespace() |
|
| 133 |
+ if err != nil {
|
|
| 134 |
+ return err |
|
| 135 |
+ } |
|
| 136 |
+ |
|
| 137 |
+ var ( |
|
| 138 |
+ name = buildName |
|
| 139 |
+ resource = "builds" |
|
| 140 |
+ ) |
|
| 141 |
+ |
|
| 142 |
+ if len(name) == 0 && len(args) > 0 && len(args[0]) > 0 {
|
|
| 143 |
+ mapper, _ := f.Object() |
|
| 144 |
+ resource, name, err = osutil.ResolveResource("buildconfigs", args[0], mapper)
|
|
| 145 |
+ if err != nil {
|
|
| 146 |
+ return err |
|
| 147 |
+ } |
|
| 148 |
+ switch resource {
|
|
| 149 |
+ case "buildconfigs": |
|
| 150 |
+ // no special handling required |
|
| 151 |
+ case "builds": |
|
| 152 |
+ return fmt.Errorf("use --from-build to rerun your builds")
|
|
| 153 |
+ default: |
|
| 154 |
+ return fmt.Errorf("invalid resource provided: %s", resource)
|
|
| 155 |
+ } |
|
| 156 |
+ } |
|
| 134 | 157 |
if len(name) == 0 {
|
| 135 |
- name = args[0] |
|
| 136 |
- isBuild = false |
|
| 158 |
+ return fmt.Errorf("a resource name is required either as an argument or by using --from-build")
|
|
| 137 | 159 |
} |
| 138 | 160 |
|
| 139 | 161 |
if webhooks.Provided() {
|
| 140 |
- return RunListBuildWebHooks(f, out, cmd.Out(), name, isBuild, webhooks.String()) |
|
| 162 |
+ return RunListBuildWebHooks(f, out, cmd.Out(), name, resource, webhooks.String()) |
|
| 141 | 163 |
} |
| 142 | 164 |
|
| 143 | 165 |
client, _, err := f.Clients() |
| ... | ... |
@@ -145,11 +168,6 @@ func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra |
| 145 | 145 |
return err |
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 |
- namespace, _, err := f.DefaultNamespace() |
|
| 149 |
- if err != nil {
|
|
| 150 |
- return err |
|
| 151 |
- } |
|
| 152 |
- |
|
| 153 | 148 |
request := &buildapi.BuildRequest{
|
| 154 | 149 |
ObjectMeta: kapi.ObjectMeta{Name: name},
|
| 155 | 150 |
} |
| ... | ... |
@@ -166,7 +184,7 @@ func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra |
| 166 | 166 |
|
| 167 | 167 |
var newBuild *buildapi.Build |
| 168 | 168 |
switch {
|
| 169 |
- case !isBuild && (len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0): |
|
| 169 |
+ case len(args) > 0 && (len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0): |
|
| 170 | 170 |
request := &buildapi.BinaryBuildRequestOptions{
|
| 171 | 171 |
ObjectMeta: kapi.ObjectMeta{
|
| 172 | 172 |
Name: name, |
| ... | ... |
@@ -177,16 +195,16 @@ func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra |
| 177 | 177 |
if newBuild, err = streamPathToBuild(git, in, cmd.Out(), client.BuildConfigs(namespace), fromDir, fromFile, fromRepo, request); err != nil {
|
| 178 | 178 |
return err |
| 179 | 179 |
} |
| 180 |
- |
|
| 181 |
- case isBuild: |
|
| 180 |
+ case resource == "builds": |
|
| 182 | 181 |
if newBuild, err = client.Builds(namespace).Clone(request); err != nil {
|
| 183 | 182 |
return err |
| 184 | 183 |
} |
| 185 |
- |
|
| 186 |
- default: |
|
| 184 |
+ case resource == "buildconfigs": |
|
| 187 | 185 |
if newBuild, err = client.BuildConfigs(namespace).Instantiate(request); err != nil {
|
| 188 | 186 |
return err |
| 189 | 187 |
} |
| 188 |
+ default: |
|
| 189 |
+ return fmt.Errorf("invalid resource provided: %s", resource)
|
|
| 190 | 190 |
} |
| 191 | 191 |
|
| 192 | 192 |
fmt.Fprintln(out, newBuild.Name) |
| ... | ... |
@@ -240,7 +258,7 @@ func RunStartBuild(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra |
| 240 | 240 |
} |
| 241 | 241 |
|
| 242 | 242 |
// RunListBuildWebHooks prints the webhooks for the provided build config. |
| 243 |
-func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name string, isBuild bool, webhookFilter string) error {
|
|
| 243 |
+func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name, resource, webhookFilter string) error {
|
|
| 244 | 244 |
generic, github := false, false |
| 245 | 245 |
prefix := false |
| 246 | 246 |
switch webhookFilter {
|
| ... | ... |
@@ -263,7 +281,10 @@ func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name stri |
| 263 | 263 |
return err |
| 264 | 264 |
} |
| 265 | 265 |
|
| 266 |
- if isBuild {
|
|
| 266 |
+ switch resource {
|
|
| 267 |
+ case "buildconfigs": |
|
| 268 |
+ // no special handling required |
|
| 269 |
+ case "builds": |
|
| 267 | 270 |
build, err := client.Builds(namespace).Get(name) |
| 268 | 271 |
if err != nil {
|
| 269 | 272 |
return err |
| ... | ... |
@@ -276,7 +297,10 @@ func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name stri |
| 276 | 276 |
namespace = ref.Namespace |
| 277 | 277 |
} |
| 278 | 278 |
name = ref.Name |
| 279 |
+ default: |
|
| 280 |
+ return fmt.Errorf("invalid resource provided: %s", resource)
|
|
| 279 | 281 |
} |
| 282 |
+ |
|
| 280 | 283 |
config, err := client.BuildConfigs(namespace).Get(name) |
| 281 | 284 |
if err != nil {
|
| 282 | 285 |
return err |
| ... | ... |
@@ -162,7 +162,7 @@ func (o AddSecretOptions) Validate() error {
|
| 162 | 162 |
func (o AddSecretOptions) AddSecrets() error {
|
| 163 | 163 |
r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper). |
| 164 | 164 |
NamespaceParam(o.Namespace). |
| 165 |
- ResourceTypeOrNameArgs(false, o.TargetName). |
|
| 165 |
+ ResourceNames("serviceaccounts", o.TargetName).
|
|
| 166 | 166 |
SingleResourceType(). |
| 167 | 167 |
Do() |
| 168 | 168 |
if r.Err() != nil {
|
| ... | ... |
@@ -223,7 +223,7 @@ func (o AddSecretOptions) addSecretsToServiceAccount(serviceaccount *kapi.Servic |
| 223 | 223 |
func (o AddSecretOptions) getSecrets() ([]*kapi.Secret, error) {
|
| 224 | 224 |
r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper). |
| 225 | 225 |
NamespaceParam(o.Namespace). |
| 226 |
- ResourceTypeOrNameArgs(false, o.SecretNames...). |
|
| 226 |
+ ResourceNames("secrets", o.SecretNames...).
|
|
| 227 | 227 |
SingleResourceType(). |
| 228 | 228 |
Do() |
| 229 | 229 |
if r.Err() != nil {
|
| ... | ... |
@@ -14,6 +14,7 @@ import ( |
| 14 | 14 |
|
| 15 | 15 |
"github.com/openshift/origin/pkg/client" |
| 16 | 16 |
"github.com/openshift/origin/pkg/cmd/cli/describe" |
| 17 |
+ osutil "github.com/openshift/origin/pkg/cmd/util" |
|
| 17 | 18 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 18 | 19 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 19 | 20 |
imagegraph "github.com/openshift/origin/pkg/image/graph/nodes" |
| ... | ... |
@@ -43,7 +44,6 @@ const BuildChainRecommendedCommandName = "build-chain" |
| 43 | 43 |
// BuildChainOptions contains all the options needed for build-chain |
| 44 | 44 |
type BuildChainOptions struct {
|
| 45 | 45 |
name string |
| 46 |
- tag string |
|
| 47 | 46 |
|
| 48 | 47 |
defaultNamespace string |
| 49 | 48 |
namespaces sets.String |
| ... | ... |
@@ -62,7 +62,7 @@ func NewCmdBuildChain(name, fullName string, f *clientcmd.Factory, out io.Writer |
| 62 | 62 |
namespaces: sets.NewString(), |
| 63 | 63 |
} |
| 64 | 64 |
cmd := &cobra.Command{
|
| 65 |
- Use: "build-chain [IMAGESTREAM:TAG]", |
|
| 65 |
+ Use: "build-chain IMAGESTREAMTAG", |
|
| 66 | 66 |
Short: "Output the inputs and dependencies of your builds", |
| 67 | 67 |
Long: buildChainLong, |
| 68 | 68 |
Example: fmt.Sprintf(buildChainExample, fullName), |
| ... | ... |
@@ -84,7 +84,7 @@ func NewCmdBuildChain(name, fullName string, f *clientcmd.Factory, out io.Writer |
| 84 | 84 |
// Complete completes the required options for build-chain |
| 85 | 85 |
func (o *BuildChainOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
|
| 86 | 86 |
if len(args) != 1 {
|
| 87 |
- return cmdutil.UsageError(cmd, "Must pass an image stream name and optionally a tag. In case of an empty tag, 'latest' will be used.") |
|
| 87 |
+ return cmdutil.UsageError(cmd, "Must pass an image stream tag. If only an image stream name is specified, 'latest' will be used for the tag.") |
|
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 | 90 |
// Setup client |
| ... | ... |
@@ -94,12 +94,20 @@ func (o *BuildChainOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, a |
| 94 | 94 |
} |
| 95 | 95 |
o.c, o.t = oc, oc |
| 96 | 96 |
|
| 97 |
- // Parse user input |
|
| 98 |
- o.name, o.tag, err = buildChainInput(args[0]) |
|
| 97 |
+ resource := "" |
|
| 98 |
+ mapper, _ := f.Object() |
|
| 99 |
+ resource, o.name, err = osutil.ResolveResource("imagestreamtags", args[0], mapper)
|
|
| 99 | 100 |
if err != nil {
|
| 100 |
- return cmdutil.UsageError(cmd, err.Error()) |
|
| 101 |
+ return err |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ switch resource {
|
|
| 105 |
+ case "imagestreamtags": |
|
| 106 |
+ o.name = imageapi.NormalizeImageStreamTag(o.name) |
|
| 107 |
+ glog.V(4).Infof("Using %q as the image stream tag to look dependencies for", o.name)
|
|
| 108 |
+ default: |
|
| 109 |
+ return fmt.Errorf("invalid resource provided: %s", resource)
|
|
| 101 | 110 |
} |
| 102 |
- glog.V(4).Infof("Using '%s:%s' as the image stream tag to look dependencies for", o.name, o.tag)
|
|
| 103 | 111 |
|
| 104 | 112 |
// Setup namespace |
| 105 | 113 |
if o.allNamespaces {
|
| ... | ... |
@@ -120,7 +128,7 @@ func (o *BuildChainOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, a |
| 120 | 120 |
} |
| 121 | 121 |
|
| 122 | 122 |
o.defaultNamespace = namespace |
| 123 |
- glog.V(4).Infof("Using %q as the namespace for '%s:%s'", o.defaultNamespace, o.name, o.tag)
|
|
| 123 |
+ glog.V(4).Infof("Using %q as the namespace for %q", o.defaultNamespace, o.name)
|
|
| 124 | 124 |
o.namespaces.Insert(namespace) |
| 125 | 125 |
glog.V(4).Infof("Will look for deps in %s", strings.Join(o.namespaces.List(), ","))
|
| 126 | 126 |
|
| ... | ... |
@@ -130,10 +138,7 @@ func (o *BuildChainOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, a |
| 130 | 130 |
// Validate returns validation errors regarding build-chain |
| 131 | 131 |
func (o *BuildChainOptions) Validate() error {
|
| 132 | 132 |
if len(o.name) == 0 {
|
| 133 |
- return fmt.Errorf("image stream name cannot be empty")
|
|
| 134 |
- } |
|
| 135 |
- if len(o.tag) == 0 {
|
|
| 136 |
- o.tag = imageapi.DefaultImageTag |
|
| 133 |
+ return fmt.Errorf("image stream tag cannot be empty")
|
|
| 137 | 134 |
} |
| 138 | 135 |
if len(o.defaultNamespace) == 0 {
|
| 139 | 136 |
return fmt.Errorf("default namespace cannot be empty")
|
| ... | ... |
@@ -153,15 +158,17 @@ func (o *BuildChainOptions) Validate() error {
|
| 153 | 153 |
// RunBuildChain contains all the necessary functionality for the OpenShift |
| 154 | 154 |
// experimental build-chain command |
| 155 | 155 |
func (o *BuildChainOptions) RunBuildChain() error {
|
| 156 |
- ist := imagegraph.MakeImageStreamTagObjectMeta(o.defaultNamespace, o.name, o.tag) |
|
| 156 |
+ ist := imagegraph.MakeImageStreamTagObjectMeta2(o.defaultNamespace, o.name) |
|
| 157 |
+ |
|
| 157 | 158 |
desc, err := describe.NewChainDescriber(o.c, o.namespaces, o.output).Describe(ist, !o.triggerOnly) |
| 158 | 159 |
if err != nil {
|
| 159 | 160 |
if _, isNotFoundErr := err.(describe.NotFoundErr); isNotFoundErr {
|
| 161 |
+ name, tag, _ := imageapi.SplitImageStreamTag(o.name) |
|
| 160 | 162 |
// Try to get the imageStreamTag via a direct GET |
| 161 |
- if _, getErr := o.t.ImageStreamTags(o.defaultNamespace).Get(o.name, o.tag); getErr != nil {
|
|
| 163 |
+ if _, getErr := o.t.ImageStreamTags(o.defaultNamespace).Get(name, tag); getErr != nil {
|
|
| 162 | 164 |
return getErr |
| 163 | 165 |
} |
| 164 |
- fmt.Printf("Image stream tag '%s:%s' in %q doesn't have any dependencies.\n", o.name, o.tag, o.defaultNamespace)
|
|
| 166 |
+ fmt.Printf("Image stream tag %q in %q doesn't have any dependencies.\n", o.name, o.defaultNamespace)
|
|
| 165 | 167 |
return nil |
| 166 | 168 |
} |
| 167 | 169 |
return err |
| ... | ... |
@@ -171,26 +178,3 @@ func (o *BuildChainOptions) RunBuildChain() error {
|
| 171 | 171 |
|
| 172 | 172 |
return nil |
| 173 | 173 |
} |
| 174 |
- |
|
| 175 |
-// buildChainInput parses user input and returns a stream name, a tag |
|
| 176 |
-// and an error if any |
|
| 177 |
-func buildChainInput(input string) (string, string, error) {
|
|
| 178 |
- // Split name and tag |
|
| 179 |
- name, tag, _ := imageapi.SplitImageStreamTag(input) |
|
| 180 |
- |
|
| 181 |
- // Support resource type/name syntax |
|
| 182 |
- // TODO: Use the RESTMapper to resolve this |
|
| 183 |
- resource := strings.Split(name, "/") |
|
| 184 |
- switch len(resource) {
|
|
| 185 |
- case 1: |
|
| 186 |
- case 2: |
|
| 187 |
- resourceType := resource[0] |
|
| 188 |
- if resourceType != "istag" && resourceType != "imagestreamtag" {
|
|
| 189 |
- return "", "", fmt.Errorf("invalid resource type %q", resourceType)
|
|
| 190 |
- } |
|
| 191 |
- default: |
|
| 192 |
- return "", "", fmt.Errorf("invalid image stream name %q", name)
|
|
| 193 |
- } |
|
| 194 |
- |
|
| 195 |
- return name, tag, nil |
|
| 196 |
-} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package util |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "errors" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"io" |
| 6 | 7 |
"path/filepath" |
| ... | ... |
@@ -8,6 +9,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
"github.com/spf13/cobra" |
| 10 | 10 |
|
| 11 |
+ "k8s.io/kubernetes/pkg/api/meta" |
|
| 11 | 12 |
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
| 12 | 13 |
) |
| 13 | 14 |
|
| ... | ... |
@@ -31,3 +33,30 @@ func GetDisplayFilename(filename string) string {
|
| 31 | 31 |
|
| 32 | 32 |
return filename |
| 33 | 33 |
} |
| 34 |
+ |
|
| 35 |
+// ResolveResource returns the resource type and name of the resourceString. |
|
| 36 |
+// If the resource string has no specified type, defaultResource will be returned. |
|
| 37 |
+func ResolveResource(defaultResource, resourceString string, mapper meta.RESTMapper) (string, string, error) {
|
|
| 38 |
+ if mapper == nil {
|
|
| 39 |
+ return "", "", errors.New("mapper cannot be nil")
|
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ var name string |
|
| 43 |
+ parts := strings.Split(resourceString, "/") |
|
| 44 |
+ switch len(parts) {
|
|
| 45 |
+ case 1: |
|
| 46 |
+ name = parts[0] |
|
| 47 |
+ case 2: |
|
| 48 |
+ _, kind, err := mapper.VersionAndKindForResource(parts[0]) |
|
| 49 |
+ if err != nil {
|
|
| 50 |
+ return "", "", err |
|
| 51 |
+ } |
|
| 52 |
+ name = parts[1] |
|
| 53 |
+ resource, _ := meta.KindToResource(kind, false) |
|
| 54 |
+ return resource, name, nil |
|
| 55 |
+ default: |
|
| 56 |
+ return "", "", fmt.Errorf("invalid resource format: %s", resourceString)
|
|
| 57 |
+ } |
|
| 58 |
+ |
|
| 59 |
+ return defaultResource, name, nil |
|
| 60 |
+} |
| 34 | 61 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,181 @@ |
| 0 |
+package util_test |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ "k8s.io/kubernetes/pkg/kubectl" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/openshift/origin/pkg/api/latest" |
|
| 8 |
+ "github.com/openshift/origin/pkg/cmd/util" |
|
| 9 |
+ "github.com/openshift/origin/pkg/cmd/util/clientcmd" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+func TestResolveResource(t *testing.T) {
|
|
| 13 |
+ mapper := clientcmd.ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: latest.RESTMapper}}
|
|
| 14 |
+ |
|
| 15 |
+ tests := []struct {
|
|
| 16 |
+ name string |
|
| 17 |
+ defaultResource string |
|
| 18 |
+ resourceString string |
|
| 19 |
+ expectedResource string |
|
| 20 |
+ expectedName string |
|
| 21 |
+ expectedErr bool |
|
| 22 |
+ }{
|
|
| 23 |
+ {
|
|
| 24 |
+ name: "invalid case #1", |
|
| 25 |
+ defaultResource: "", |
|
| 26 |
+ resourceString: "a/b/c", |
|
| 27 |
+ expectedResource: "", |
|
| 28 |
+ expectedName: "", |
|
| 29 |
+ expectedErr: true, |
|
| 30 |
+ }, |
|
| 31 |
+ {
|
|
| 32 |
+ name: "invalid case #2", |
|
| 33 |
+ defaultResource: "", |
|
| 34 |
+ resourceString: "foo/bar", |
|
| 35 |
+ expectedResource: "", |
|
| 36 |
+ expectedName: "", |
|
| 37 |
+ expectedErr: true, |
|
| 38 |
+ }, |
|
| 39 |
+ {
|
|
| 40 |
+ name: "empty resource string case #1", |
|
| 41 |
+ defaultResource: "", |
|
| 42 |
+ resourceString: "", |
|
| 43 |
+ expectedResource: "", |
|
| 44 |
+ expectedName: "", |
|
| 45 |
+ expectedErr: false, |
|
| 46 |
+ }, |
|
| 47 |
+ {
|
|
| 48 |
+ name: "empty resource string case #2", |
|
| 49 |
+ defaultResource: "", |
|
| 50 |
+ resourceString: "bar", |
|
| 51 |
+ expectedResource: "", |
|
| 52 |
+ expectedName: "bar", |
|
| 53 |
+ expectedErr: false, |
|
| 54 |
+ }, |
|
| 55 |
+ {
|
|
| 56 |
+ name: "empty resource string case #3", |
|
| 57 |
+ defaultResource: "foo", |
|
| 58 |
+ resourceString: "bar", |
|
| 59 |
+ expectedResource: "foo", |
|
| 60 |
+ expectedName: "bar", |
|
| 61 |
+ expectedErr: false, |
|
| 62 |
+ }, |
|
| 63 |
+ {
|
|
| 64 |
+ name: "(KUBE) short name", |
|
| 65 |
+ defaultResource: "foo", |
|
| 66 |
+ resourceString: "rc/bar", |
|
| 67 |
+ expectedResource: "replicationcontrollers", |
|
| 68 |
+ expectedName: "bar", |
|
| 69 |
+ expectedErr: false, |
|
| 70 |
+ }, |
|
| 71 |
+ {
|
|
| 72 |
+ name: "(KUBE) long name, case insensitive #1", |
|
| 73 |
+ defaultResource: "foo", |
|
| 74 |
+ resourceString: "replicationcontroller/bar", |
|
| 75 |
+ expectedResource: "replicationcontrollers", |
|
| 76 |
+ expectedName: "bar", |
|
| 77 |
+ expectedErr: false, |
|
| 78 |
+ }, |
|
| 79 |
+ {
|
|
| 80 |
+ name: "(KUBE) long name, case insensitive #2", |
|
| 81 |
+ defaultResource: "foo", |
|
| 82 |
+ resourceString: "replicationcontrollers/bar", |
|
| 83 |
+ expectedResource: "replicationcontrollers", |
|
| 84 |
+ expectedName: "bar", |
|
| 85 |
+ expectedErr: false, |
|
| 86 |
+ }, |
|
| 87 |
+ {
|
|
| 88 |
+ name: "(KUBE) long name, case insensitive #3", |
|
| 89 |
+ defaultResource: "foo", |
|
| 90 |
+ resourceString: "ReplicationControllers/bar", |
|
| 91 |
+ expectedResource: "replicationcontrollers", |
|
| 92 |
+ expectedName: "bar", |
|
| 93 |
+ expectedErr: false, |
|
| 94 |
+ }, |
|
| 95 |
+ {
|
|
| 96 |
+ name: "(KUBE) long name, case insensitive #4", |
|
| 97 |
+ defaultResource: "foo", |
|
| 98 |
+ resourceString: "ReplicationControllers/bar", |
|
| 99 |
+ expectedResource: "replicationcontrollers", |
|
| 100 |
+ expectedName: "bar", |
|
| 101 |
+ expectedErr: false, |
|
| 102 |
+ }, |
|
| 103 |
+ {
|
|
| 104 |
+ name: "(KUBE) long name, case insensitive #5", |
|
| 105 |
+ defaultResource: "foo", |
|
| 106 |
+ resourceString: "ReplicationControllers/Bar", |
|
| 107 |
+ expectedResource: "replicationcontrollers", |
|
| 108 |
+ expectedName: "Bar", |
|
| 109 |
+ expectedErr: false, |
|
| 110 |
+ }, |
|
| 111 |
+ {
|
|
| 112 |
+ name: "(ORIGIN) short name", |
|
| 113 |
+ defaultResource: "foo", |
|
| 114 |
+ resourceString: "bc/bar", |
|
| 115 |
+ expectedResource: "buildconfigs", |
|
| 116 |
+ expectedName: "bar", |
|
| 117 |
+ expectedErr: false, |
|
| 118 |
+ }, |
|
| 119 |
+ {
|
|
| 120 |
+ name: "(ORIGIN) long name, case insensitive #1", |
|
| 121 |
+ defaultResource: "foo", |
|
| 122 |
+ resourceString: "buildconfig/bar", |
|
| 123 |
+ expectedResource: "buildconfigs", |
|
| 124 |
+ expectedName: "bar", |
|
| 125 |
+ expectedErr: false, |
|
| 126 |
+ }, |
|
| 127 |
+ {
|
|
| 128 |
+ name: "(ORIGIN) long name, case insensitive #2", |
|
| 129 |
+ defaultResource: "foo", |
|
| 130 |
+ resourceString: "buildconfigs/bar", |
|
| 131 |
+ expectedResource: "buildconfigs", |
|
| 132 |
+ expectedName: "bar", |
|
| 133 |
+ expectedErr: false, |
|
| 134 |
+ }, |
|
| 135 |
+ {
|
|
| 136 |
+ name: "(ORIGIN) long name, case insensitive #3", |
|
| 137 |
+ defaultResource: "foo", |
|
| 138 |
+ resourceString: "BuildConfigs/bar", |
|
| 139 |
+ expectedResource: "buildconfigs", |
|
| 140 |
+ expectedName: "bar", |
|
| 141 |
+ expectedErr: false, |
|
| 142 |
+ }, |
|
| 143 |
+ {
|
|
| 144 |
+ name: "(ORIGIN) long name, case insensitive #4", |
|
| 145 |
+ defaultResource: "foo", |
|
| 146 |
+ resourceString: "BuildConfigs/bar", |
|
| 147 |
+ expectedResource: "buildconfigs", |
|
| 148 |
+ expectedName: "bar", |
|
| 149 |
+ expectedErr: false, |
|
| 150 |
+ }, |
|
| 151 |
+ {
|
|
| 152 |
+ name: "(ORIGIN) long name, case insensitive #5", |
|
| 153 |
+ defaultResource: "foo", |
|
| 154 |
+ resourceString: "BuildConfigs/Bar", |
|
| 155 |
+ expectedResource: "buildconfigs", |
|
| 156 |
+ expectedName: "Bar", |
|
| 157 |
+ expectedErr: false, |
|
| 158 |
+ }, |
|
| 159 |
+ } |
|
| 160 |
+ |
|
| 161 |
+ for _, test := range tests {
|
|
| 162 |
+ gotResource, gotName, gotErr := util.ResolveResource(test.defaultResource, test.resourceString, mapper) |
|
| 163 |
+ if gotErr != nil && !test.expectedErr {
|
|
| 164 |
+ t.Errorf("%s: expected no error, got %v", test.name, gotErr)
|
|
| 165 |
+ continue |
|
| 166 |
+ } |
|
| 167 |
+ if gotErr == nil && test.expectedErr {
|
|
| 168 |
+ t.Errorf("%s: expected error but got none", test.name)
|
|
| 169 |
+ continue |
|
| 170 |
+ } |
|
| 171 |
+ if gotResource != test.expectedResource {
|
|
| 172 |
+ t.Errorf("%s: expected resource type %s, got %s", test.name, test.expectedResource, gotResource)
|
|
| 173 |
+ continue |
|
| 174 |
+ } |
|
| 175 |
+ if gotName != test.expectedName {
|
|
| 176 |
+ t.Errorf("%s: expected resource name %s, got %s", test.name, test.expectedName, gotName)
|
|
| 177 |
+ continue |
|
| 178 |
+ } |
|
| 179 |
+ } |
|
| 180 |
+} |
| ... | ... |
@@ -210,6 +210,16 @@ func JoinImageStreamTag(name, tag string) string {
|
| 210 | 210 |
return fmt.Sprintf("%s:%s", name, tag)
|
| 211 | 211 |
} |
| 212 | 212 |
|
| 213 |
+// NormalizeImageStreamTag normalizes an image stream tag by defaulting to 'latest' |
|
| 214 |
+// if no tag has been specified. |
|
| 215 |
+func NormalizeImageStreamTag(name string) string {
|
|
| 216 |
+ if !strings.Contains(name, ":") {
|
|
| 217 |
+ // Default to latest |
|
| 218 |
+ return JoinImageStreamTag(name, DefaultImageTag) |
|
| 219 |
+ } |
|
| 220 |
+ return name |
|
| 221 |
+} |
|
| 222 |
+ |
|
| 213 | 223 |
// ImageWithMetadata returns a copy of image with the DockerImageMetadata filled in |
| 214 | 224 |
// from the raw DockerImageManifest data stored in the image. |
| 215 | 225 |
func ImageWithMetadata(image Image) (*Image, error) {
|
| ... | ... |
@@ -173,6 +173,9 @@ echo "registry: ok" |
| 173 | 173 |
|
| 174 | 174 |
# Test building a dependency tree |
| 175 | 175 |
oc process -f examples/sample-app/application-template-stibuild.json -l build=sti | oc create -f - |
| 176 |
+# Test both the type/name resource syntax and the fact that istag/origin-ruby-sample:latest is still |
|
| 177 |
+# not created but due to a buildConfig pointing to it, we get back its graph of deps. |
|
| 178 |
+[ "$(oadm build-chain istag/origin-ruby-sample | grep 'imagestreamtag/origin-ruby-sample:latest')" ] |
|
| 176 | 179 |
[ "$(oadm build-chain ruby-20-centos7 -o dot | grep 'graph')" ] |
| 177 | 180 |
oc delete all -l build=sti |
| 178 | 181 |
echo "ex build-chain: ok" |
| ... | ... |
@@ -26,16 +26,16 @@ oc get buildConfigs |
| 26 | 26 |
oc get bc |
| 27 | 27 |
oc get builds |
| 28 | 28 |
|
| 29 |
-REAL_OUTPUT_TO=$(oc get bc/ruby-sample-build -t '{{ .spec.output.to.name }}')
|
|
| 29 |
+REAL_OUTPUT_TO=$(oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}')
|
|
| 30 | 30 |
oc patch bc/ruby-sample-build -p '{"spec":{"output":{"to":{"name":"different:tag1"}}}}'
|
| 31 |
-oc get bc/ruby-sample-build -t '{{ .spec.output.to.name }}' | grep 'different'
|
|
| 31 |
+oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}' | grep 'different'
|
|
| 32 | 32 |
oc patch bc/ruby-sample-build -p "{\"spec\":{\"output\":{\"to\":{\"name\":\"${REAL_OUTPUT_TO}\"}}}}"
|
| 33 | 33 |
echo "patchAnonFields: ok" |
| 34 | 34 |
|
| 35 | 35 |
[ "$(oc describe buildConfigs ruby-sample-build | grep --text "Webhook GitHub" | grep -F "${url}/oapi/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks/secret101/github")" ]
|
| 36 | 36 |
[ "$(oc describe buildConfigs ruby-sample-build | grep --text "Webhook Generic" | grep -F "${url}/oapi/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks/secret101/generic")" ]
|
| 37 | 37 |
oc start-build --list-webhooks='all' ruby-sample-build |
| 38 |
-[ "$(oc start-build --list-webhooks='all' ruby-sample-build | grep --text "generic")" ] |
|
| 38 |
+[ "$(oc start-build --list-webhooks='all' bc/ruby-sample-build | grep --text "generic")" ] |
|
| 39 | 39 |
[ "$(oc start-build --list-webhooks='all' ruby-sample-build | grep --text "github")" ] |
| 40 | 40 |
[ "$(oc start-build --list-webhooks='github' ruby-sample-build | grep --text "secret101")" ] |
| 41 | 41 |
[ ! "$(oc start-build --list-webhooks='blah')" ] |
| ... | ... |
@@ -50,11 +50,15 @@ oc create -f test/integration/fixtures/test-buildcli.json |
| 50 | 50 |
# the build should use the image field as defined in the buildconfig |
| 51 | 51 |
started=$(oc start-build ruby-sample-build-invalidtag) |
| 52 | 52 |
oc describe build ${started} | grep openshift/ruby-20-centos7$
|
| 53 |
+frombuild=$(oc start-build --from-build="${started}")
|
|
| 54 |
+oc describe build ${frombuild} | grep openshift/ruby-20-centos7$
|
|
| 53 | 55 |
echo "start-build: ok" |
| 54 | 56 |
|
| 55 | 57 |
oc cancel-build "${started}" --dump-logs --restart
|
| 58 |
+oc delete all --all |
|
| 59 |
+oc process -f examples/sample-app/application-template-dockerbuild.json -l build=docker | oc create -f - |
|
| 60 |
+tryuntil oc get build/ruby-sample-build-1 |
|
| 61 |
+# Uses type/name resource syntax |
|
| 62 |
+oc cancel-build build/ruby-sample-build-1 |
|
| 63 |
+oc delete all --all |
|
| 56 | 64 |
echo "cancel-build: ok" |
| 57 |
- |
|
| 58 |
-[ "$(oc delete is/ruby-20-centos7-buildcli | grep 'imagestream "ruby-20-centos7-buildcli" deleted')" ] |
|
| 59 |
-[ "$(oc delete bc/ruby-sample-build-validtag -o name | grep 'buildconfig/ruby-sample-build-validtag')" ] |
|
| 60 |
-[ "$(oc delete bc/ruby-sample-build-invalidtag | grep 'buildconfig "ruby-sample-build-invalidtag" deleted')" ] |
| ... | ... |
@@ -31,6 +31,7 @@ oc describe deploymentConfigs test-deployment-config |
| 31 | 31 |
[ "$(oc env dc/test-deployment-config TEST=bar OTHER=baz BAR-)" ] |
| 32 | 32 |
|
| 33 | 33 |
oc deploy test-deployment-config |
| 34 |
+oc deploy dc/test-deployment-config |
|
| 34 | 35 |
oc delete deploymentConfigs test-deployment-config |
| 35 | 36 |
echo "deploymentConfigs: ok" |
| 36 | 37 |
|
| ... | ... |
@@ -24,11 +24,11 @@ oc secrets new from-file .dockercfg=${HOME}/dockerconfig
|
| 24 | 24 |
|
| 25 | 25 |
# attach secrets to service account |
| 26 | 26 |
# single secret with prefix |
| 27 |
-oc secrets add serviceaccounts/deployer secrets/dockercfg |
|
| 27 |
+oc secrets add deployer dockercfg |
|
| 28 | 28 |
# don't add the same secret twice |
| 29 |
-oc secrets add serviceaccounts/deployer secrets/dockercfg secrets/from-file |
|
| 29 |
+oc secrets add serviceaccounts/deployer dockercfg secrets/from-file |
|
| 30 | 30 |
# make sure we can add as as pull secret |
| 31 |
-oc secrets add serviceaccounts/deployer secrets/dockercfg secrets/from-file --for=pull |
|
| 31 |
+oc secrets add deployer dockercfg from-file --for=pull |
|
| 32 | 32 |
# make sure we can add as as pull secret and mount secret at once |
| 33 | 33 |
oc secrets add serviceaccounts/deployer secrets/dockercfg secrets/from-file --for=pull,mount |
| 34 | 34 |
|