Skip to content

Commit e243771

Browse files
committed
Add support to list N deployments in 'osc deploy'
1 parent 4afc220 commit e243771

File tree

4 files changed

+74
-50
lines changed

4 files changed

+74
-50
lines changed

hack/test-cmd.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ osc get dc
402402
osc create -f test/integration/fixtures/test-deployment-config.json
403403
osc describe deploymentConfigs test-deployment-config
404404
osc deploy test-deployment-config
405+
osc deploy test-deployment-config -L
406+
osc deploy test-deployment-config -L 3
405407
osc delete deploymentConfigs test-deployment-config
406408
echo "deploymentConfigs: ok"
407409

pkg/cmd/cli/cmd/deploy.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ NOTE: This command is still under active development and is subject to change.`
2626
deploy_example = ` // Display the latest deployment for the 'database' deployment config
2727
$ %[1]s deploy database
2828
29+
// List the most recent deployments for the 'database' deployment config
30+
$ %[1]s deploy database -L
31+
32+
// List the most recent deployments for the 'database' deployment config, limited to three
33+
$ %[1]s deploy database -L 3
34+
2935
// Start a new deployment based on the 'frontend' deployment config
3036
$ %[1]s deploy frontend --latest`
3137
)
@@ -34,6 +40,7 @@ NOTE: This command is still under active development and is subject to change.`
3440
func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
3541
var deployLatest bool
3642
var retryDeploy bool
43+
var listSize int
3744

3845
cmd := &cobra.Command{
3946
Use: "deploy DEPLOYMENTCONFIG",
@@ -45,10 +52,22 @@ func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.C
4552
fmt.Println(cmdutil.UsageError(cmd, "A deploymentConfig name is required."))
4653
return
4754
}
55+
listFlag := cmd.Flags().Lookup("list")
56+
if listFlag.Changed && (deployLatest || retryDeploy) {
57+
fmt.Println(cmdutil.UsageError(cmd, "The -L|--list flag can't be used with --latest or --retry."))
58+
return
59+
}
4860
if deployLatest && retryDeploy {
4961
fmt.Println(cmdutil.UsageError(cmd, "Only one of --latest or --retry is allowed."))
5062
return
5163
}
64+
if listSize < 1 {
65+
fmt.Println(cmdutil.UsageError(cmd, "The -L|--list flag require a value greater than zero."))
66+
return
67+
}
68+
if !listFlag.Changed {
69+
listSize = 1
70+
}
5271

5372
configName := args[0]
5473

@@ -81,7 +100,7 @@ func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.C
81100
c := &retryDeploymentCommand{client: commandClient}
82101
err = c.retry(config, out)
83102
default:
84-
describer := describe.NewLatestDeploymentDescriber(osClient, kubeClient)
103+
describer := describe.NewLatestDeploymentsDescriber(osClient, kubeClient, listSize)
85104
desc, err := describer.Describe(config.Namespace, config.Name)
86105
cmdutil.CheckErr(err)
87106
fmt.Fprintln(out, desc)
@@ -92,6 +111,8 @@ func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.C
92111

93112
cmd.Flags().BoolVar(&deployLatest, "latest", false, "Start a new deployment now.")
94113
cmd.Flags().BoolVar(&retryDeploy, "retry", false, "Retry the latest failed deployment.")
114+
cmd.Flags().IntVarP(&listSize, "list", "L", 10, "Print a list of the latest deployments, limited to the amount provided.")
115+
cmd.Flags().MarkOptional("list")
95116

96117
return cmd
97118
}

pkg/cmd/cli/describe/deployments.go

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ type DeploymentConfigDescriber struct {
2929
type deploymentDescriberClient interface {
3030
getDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
3131
getDeployment(namespace, name string) (*kapi.ReplicationController, error)
32+
listDeployments(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error)
3233
listPods(namespace string, selector labels.Selector) (*kapi.PodList, error)
3334
listEvents(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error)
3435
}
3536

3637
type genericDeploymentDescriberClient struct {
3738
getDeploymentConfigFunc func(namespace, name string) (*deployapi.DeploymentConfig, error)
3839
getDeploymentFunc func(namespace, name string) (*kapi.ReplicationController, error)
40+
listDeploymentsFunc func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error)
3941
listPodsFunc func(namespace string, selector labels.Selector) (*kapi.PodList, error)
4042
listEventsFunc func(deploymentConfig *deployapi.DeploymentConfig) (*kapi.EventList, error)
4143
}
@@ -48,6 +50,10 @@ func (c *genericDeploymentDescriberClient) getDeployment(namespace, name string)
4850
return c.getDeploymentFunc(namespace, name)
4951
}
5052

53+
func (c *genericDeploymentDescriberClient) listDeployments(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
54+
return c.listDeploymentsFunc(namespace, selector)
55+
}
56+
5157
func (c *genericDeploymentDescriberClient) listPods(namespace string, selector labels.Selector) (*kapi.PodList, error) {
5258
return c.listPodsFunc(namespace, selector)
5359
}
@@ -253,19 +259,24 @@ func getPodStatusForDeployment(deployment *kapi.ReplicationController, client de
253259
return
254260
}
255261

256-
type LatestDeploymentDescriber struct {
262+
type LatestDeploymentsDescriber struct {
263+
size int
257264
client deploymentDescriberClient
258265
}
259266

260-
func NewLatestDeploymentDescriber(client client.Interface, kclient kclient.Interface) *LatestDeploymentDescriber {
261-
return &LatestDeploymentDescriber{
267+
func NewLatestDeploymentsDescriber(client client.Interface, kclient kclient.Interface, size int) *LatestDeploymentsDescriber {
268+
return &LatestDeploymentsDescriber{
269+
size: size,
262270
client: &genericDeploymentDescriberClient{
263271
getDeploymentConfigFunc: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
264272
return client.DeploymentConfigs(namespace).Get(name)
265273
},
266274
getDeploymentFunc: func(namespace, name string) (*kapi.ReplicationController, error) {
267275
return kclient.ReplicationControllers(namespace).Get(name)
268276
},
277+
listDeploymentsFunc: func(namespace string, selector labels.Selector) (*kapi.ReplicationControllerList, error) {
278+
return kclient.ReplicationControllers(namespace).List(selector)
279+
},
269280
listPodsFunc: func(namespace string, selector labels.Selector) (*kapi.PodList, error) {
270281
return kclient.Pods(namespace).List(selector, fields.Everything())
271282
},
@@ -276,66 +287,56 @@ func NewLatestDeploymentDescriber(client client.Interface, kclient kclient.Inter
276287
}
277288
}
278289

279-
func (d *LatestDeploymentDescriber) Describe(namespace, name string) (string, error) {
290+
func (d *LatestDeploymentsDescriber) Describe(namespace, name string) (string, error) {
280291
config, err := d.client.getDeploymentConfig(namespace, name)
281292
if err != nil {
282293
return "", err
283294
}
284295

285-
deploymentName := deployutil.LatestDeploymentNameForConfig(config)
286-
deployment, err := d.client.getDeployment(config.Namespace, deploymentName)
287-
if err != nil && !kerrors.IsNotFound(err) {
288-
return "", err
296+
var deployments []kapi.ReplicationController
297+
if d.size > 1 {
298+
list, err := d.client.listDeployments(namespace, labels.Everything())
299+
if err != nil && !kerrors.IsNotFound(err) {
300+
return "", err
301+
}
302+
deployments = list.Items
303+
} else {
304+
deploymentName := deployutil.LatestDeploymentNameForConfig(config)
305+
deployment, err := d.client.getDeployment(config.Namespace, deploymentName)
306+
if err != nil && !kerrors.IsNotFound(err) {
307+
return "", err
308+
}
309+
if deployment != nil {
310+
deployments = []kapi.ReplicationController{*deployment}
311+
}
289312
}
290313

291314
g := graph.New()
292315
deploy := graph.DeploymentConfig(g, config)
293-
if deployment != nil {
294-
graph.JoinDeployments(deploy.(*graph.DeploymentConfigNode), []kapi.ReplicationController{*deployment})
316+
if len(deployments) > 0 {
317+
graph.JoinDeployments(deploy.(*graph.DeploymentConfigNode), deployments)
295318
}
296319

297320
return tabbedString(func(out *tabwriter.Writer) error {
298321
indent := " "
299-
fmt.Fprintf(out, "Latest deployment for %s/%s:\n", namespace, name)
300-
printLines(out, indent, 1, d.describeDeployment(deploy.(*graph.DeploymentConfigNode))...)
322+
node := deploy.(*graph.DeploymentConfigNode)
323+
nDeployments := len(node.Deployments) + 1
324+
var msg string
325+
if d.size == 1 || nDeployments == 1 {
326+
msg = fmt.Sprintf("Latest deployment for %s/%s:\n", namespace, name)
327+
} else {
328+
if nDeployments > d.size {
329+
msg = fmt.Sprintf("Latest %v deployments for %s/%s:\n", d.size, namespace, name)
330+
} else {
331+
msg = fmt.Sprintf("All %v deployments for %s/%s:\n", nDeployments, namespace, name)
332+
}
333+
}
334+
descriptions := describeDeployments(node, d.size)
335+
printLines(out, indent, 0, append([]string{msg}, descriptions...)...)
301336
return nil
302337
})
303338
}
304339

305-
func (d *LatestDeploymentDescriber) describeDeployment(node *graph.DeploymentConfigNode) []string {
306-
if node == nil {
307-
return nil
308-
}
309-
out := []string{}
310-
311-
if node.ActiveDeployment == nil {
312-
on, auto := describeDeploymentConfigTriggers(node.DeploymentConfig)
313-
if node.DeploymentConfig.LatestVersion == 0 {
314-
out = append(out, fmt.Sprintf("#1 waiting %s. Run osc deploy --latest to deploy now.", on))
315-
} else if auto {
316-
out = append(out, fmt.Sprintf("#%d pending %s. Run osc deploy --latest to deploy now.", node.DeploymentConfig.LatestVersion, on))
317-
}
318-
// TODO: detect new image available?
319-
} else {
320-
out = append(out, d.describeDeploymentStatus(node.ActiveDeployment))
321-
}
322-
return out
323-
}
324-
325-
func (d *LatestDeploymentDescriber) describeDeploymentStatus(deploy *kapi.ReplicationController) string {
326-
timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time))
327-
switch s := deploy.Annotations[deployapi.DeploymentStatusAnnotation]; deployapi.DeploymentStatus(s) {
328-
case deployapi.DeploymentStatusFailed:
329-
// TODO: encode fail time in the rc
330-
return fmt.Sprintf("#%s failed %s ago. You can restart this deployment with osc deploy --retry.", deploy.Annotations[deployapi.DeploymentVersionAnnotation], timeAt)
331-
case deployapi.DeploymentStatusComplete:
332-
// TODO: pod status output
333-
return fmt.Sprintf("#%s deployed %s ago", deploy.Annotations[deployapi.DeploymentVersionAnnotation], timeAt)
334-
default:
335-
return fmt.Sprintf("#%s deployment %s %s ago", deploy.Annotations[deployapi.DeploymentVersionAnnotation], strings.ToLower(s), timeAt)
336-
}
337-
}
338-
339340
// DeploymentDescriber generates information about a deployment
340341
// DEPRECATED.
341342
type DeploymentDescriber struct {

pkg/cmd/cli/describe/projectstatus.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,9 @@ func describeDeployments(node *graph.DeploymentConfigNode, count int) []string {
357357
if node.ActiveDeployment == nil {
358358
on, auto := describeDeploymentConfigTriggers(node.DeploymentConfig)
359359
if node.DeploymentConfig.LatestVersion == 0 {
360-
out = append(out, fmt.Sprintf("#1 deployment waiting %s", on))
360+
out = append(out, fmt.Sprintf("#1 deployment waiting %s. Run osc deploy --latest to deploy now.", on))
361361
} else if auto {
362-
out = append(out, fmt.Sprintf("#%d deployment pending %s", node.DeploymentConfig.LatestVersion, on))
362+
out = append(out, fmt.Sprintf("#%d deployment pending %s. Run osc deploy --latest to deploy now.", node.DeploymentConfig.LatestVersion, on))
363363
}
364364
// TODO: detect new image available?
365365
} else {
@@ -380,7 +380,7 @@ func describeDeploymentStatus(deploy *kapi.ReplicationController) string {
380380
switch s := deploy.Annotations[deployapi.DeploymentStatusAnnotation]; deployapi.DeploymentStatus(s) {
381381
case deployapi.DeploymentStatusFailed:
382382
// TODO: encode fail time in the rc
383-
return fmt.Sprintf("#%s deployment failed %s ago", deploy.Annotations[deployapi.DeploymentVersionAnnotation], timeAt)
383+
return fmt.Sprintf("#%s deployment failed %s ago. You can restart this deployment with osc deploy --retry.", deploy.Annotations[deployapi.DeploymentVersionAnnotation], timeAt)
384384
case deployapi.DeploymentStatusComplete:
385385
// TODO: pod status output
386386
return fmt.Sprintf("#%s deployed %s ago", deploy.Annotations[deployapi.DeploymentVersionAnnotation], timeAt)

0 commit comments

Comments
 (0)