github.com/chenbh/concourse/v6@v6.4.2/fly/integration/workers_test.go (about)

     1  package integration_test
     2  
     3  import (
     4  	"os/exec"
     5  	"time"
     6  
     7  	"github.com/chenbh/concourse/v6/atc"
     8  	"github.com/chenbh/concourse/v6/fly/ui"
     9  	"github.com/fatih/color"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	"github.com/onsi/gomega/gbytes"
    13  	"github.com/onsi/gomega/gexec"
    14  	"github.com/onsi/gomega/ghttp"
    15  )
    16  
    17  const second = 1
    18  const minute = 60 * second
    19  const hour = minute * 60
    20  const day = hour * 24
    21  
    22  var _ = Describe("Fly CLI", func() {
    23  	Describe("workers", func() {
    24  		var (
    25  			flyCmd           *exec.Cmd
    26  			worker1StartTime int64
    27  			worker2StartTime int64
    28  			worker3StartTime int64
    29  			worker4StartTime int64
    30  			worker5StartTime int64
    31  			worker6StartTime int64
    32  			worker7StartTime int64
    33  		)
    34  
    35  		BeforeEach(func() {
    36  			flyCmd = exec.Command(flyPath, "-t", targetName, "workers")
    37  		})
    38  
    39  		Context("when workers are returned from the API", func() {
    40  			JustBeforeEach(func() {
    41  				atcServer.AppendHandlers(
    42  					ghttp.CombineHandlers(
    43  						ghttp.VerifyRequest("GET", "/api/v1/workers"),
    44  						ghttp.RespondWithJSONEncoded(200, []atc.Worker{
    45  							{
    46  								Name:             "worker-2",
    47  								GardenAddr:       "1.2.3.4:7777",
    48  								ActiveContainers: 0,
    49  								ActiveTasks:      1,
    50  								Platform:         "platform2",
    51  								Tags:             []string{"tag2", "tag3"},
    52  								ResourceTypes: []atc.WorkerResourceType{
    53  									{Type: "resource-1", Image: "/images/resource-1"},
    54  								},
    55  								Team:      "team-1",
    56  								State:     "running",
    57  								Version:   "4.5.6",
    58  								StartTime: worker2StartTime,
    59  							},
    60  							{
    61  								Name:             "worker-6",
    62  								GardenAddr:       "5.5.5.5:7777",
    63  								ActiveContainers: 0,
    64  								ActiveTasks:      1,
    65  								Platform:         "platform2",
    66  								Tags:             []string{"tag1"},
    67  								Team:             "team-1",
    68  								State:            "running",
    69  								Version:          "1.2.3",
    70  								Ephemeral:        true,
    71  								StartTime:        worker6StartTime,
    72  							},
    73  							{
    74  								Name:             "worker-7",
    75  								GardenAddr:       "7.7.7.7:7777",
    76  								ActiveContainers: 0,
    77  								ActiveTasks:      0,
    78  								Platform:         "platform2",
    79  								Tags:             []string{"tag1"},
    80  								Team:             "team-1",
    81  								State:            "running",
    82  								Version:          "",
    83  								StartTime:        worker7StartTime,
    84  							},
    85  							{
    86  								Name:             "worker-1",
    87  								GardenAddr:       "2.2.3.4:7777",
    88  								BaggageclaimURL:  "http://2.2.3.4:7788",
    89  								ActiveContainers: 1,
    90  								ActiveTasks:      1,
    91  								Platform:         "platform1",
    92  								Tags:             []string{"tag1"},
    93  								ResourceTypes: []atc.WorkerResourceType{
    94  									{Type: "resource-1", Image: "/images/resource-1"},
    95  									{Type: "resource-2", Image: "/images/resource-2"},
    96  								},
    97  								Team:      "team-1",
    98  								State:     "landing",
    99  								Version:   "4.5.6",
   100  								StartTime: worker1StartTime,
   101  							},
   102  							{
   103  								Name:             "worker-3",
   104  								GardenAddr:       "3.2.3.4:7777",
   105  								ActiveContainers: 10,
   106  								ActiveTasks:      1,
   107  								Platform:         "platform3",
   108  								Tags:             []string{},
   109  								State:            "landed",
   110  								Version:          "4.5.6",
   111  								StartTime:        worker3StartTime,
   112  							},
   113  							{
   114  								Name:             "worker-4",
   115  								GardenAddr:       "",
   116  								ActiveContainers: 7,
   117  								ActiveTasks:      1,
   118  								Platform:         "platform4",
   119  								Tags:             []string{"tag1"},
   120  								Team:             "team-1",
   121  								State:            "stalled",
   122  								Version:          "4.5.6",
   123  								StartTime:        worker4StartTime,
   124  							},
   125  							{
   126  								Name:             "worker-5",
   127  								GardenAddr:       "3.2.3.4:7777",
   128  								ActiveContainers: 5,
   129  								ActiveTasks:      1,
   130  								Platform:         "platform5",
   131  								Tags:             []string{},
   132  								State:            "retiring",
   133  								Version:          "4.5.6",
   134  								StartTime:        worker5StartTime,
   135  							},
   136  						}),
   137  					),
   138  				)
   139  			})
   140  
   141  			BeforeEach(func() {
   142  				worker1StartTime = time.Now().Unix() - 2*day - 90*second
   143  				worker2StartTime = time.Now().Unix() - 1*day - 90*second
   144  				worker3StartTime = time.Now().Unix() - 10*hour - 3*minute - 50*second
   145  				worker4StartTime = time.Now().Unix() - 8*hour - 30*minute - 50*second
   146  				worker5StartTime = 0
   147  				worker6StartTime = 0
   148  				worker7StartTime = time.Now().Unix() + 700*second
   149  			})
   150  
   151  			It("lists them to the user, ordered by name, with outdated and stalled workers grouped together", func() {
   152  				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
   153  				Expect(err).NotTo(HaveOccurred())
   154  
   155  				Eventually(sess).Should(gexec.Exit(0))
   156  				Expect(sess.Out).To(PrintTable(ui.Table{
   157  					Headers: ui.TableRow{
   158  						{Contents: "name", Color: color.New(color.Bold)},
   159  						{Contents: "containers", Color: color.New(color.Bold)},
   160  						{Contents: "platform", Color: color.New(color.Bold)},
   161  						{Contents: "tags", Color: color.New(color.Bold)},
   162  						{Contents: "team", Color: color.New(color.Bold)},
   163  						{Contents: "state", Color: color.New(color.Bold)},
   164  						{Contents: "version", Color: color.New(color.Bold)},
   165  						{Contents: "age", Color: color.New(color.Bold)},
   166  					},
   167  					Data: []ui.TableRow{
   168  						{{Contents: "worker-1"}, {Contents: "1"}, {Contents: "platform1"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6"}, {Contents: "2d"}},
   169  						{{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag2, tag3"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6"}, {Contents: "1d"}},
   170  						{{Contents: "worker-3"}, {Contents: "10"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "landed"}, {Contents: "4.5.6"}, {Contents: "10h3m"}},
   171  						{{Contents: "worker-5"}, {Contents: "5"}, {Contents: "platform5"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}},
   172  						{{Contents: "worker-6"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "1.2.3", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}},
   173  						{{Contents: "worker-7"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "none", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}},
   174  						{{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "8h30m"}},
   175  					},
   176  				}))
   177  			})
   178  
   179  			Context("when --json is given", func() {
   180  				BeforeEach(func() {
   181  					flyCmd.Args = append(flyCmd.Args, "--json")
   182  					worker1StartTime = 0
   183  					worker2StartTime = 0
   184  					worker3StartTime = 0
   185  					worker4StartTime = 0
   186  					worker5StartTime = 0
   187  					worker6StartTime = 0
   188  					worker7StartTime = 0
   189  				})
   190  
   191  				It("prints response in json as stdout", func() {
   192  					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
   193  					Expect(err).NotTo(HaveOccurred())
   194  
   195  					Eventually(sess).Should(gexec.Exit(0))
   196  					Expect(sess.Out.Contents()).To(MatchJSON(`[
   197                {
   198                  "addr": "1.2.3.4:7777",
   199                  "baggageclaim_url": "",
   200                  "active_containers": 0,
   201  				"active_volumes": 0,
   202  				"active_tasks": 1,
   203                  "resource_types": [
   204                    {
   205                      "type": "resource-1",
   206                      "image": "/images/resource-1",
   207                      "version": "",
   208                      "privileged": false,
   209                      "unique_version_history": false
   210                    }
   211                  ],
   212                  "platform": "platform2",
   213                  "tags": [
   214                    "tag2",
   215                    "tag3"
   216                  ],
   217                  "team": "team-1",
   218                  "name": "worker-2",
   219                  "version": "4.5.6",
   220                  "start_time": 0,
   221                  "state": "running",
   222                  "ephemeral": false
   223                },
   224                {
   225                  "addr": "5.5.5.5:7777",
   226                  "baggageclaim_url": "",
   227                  "active_containers": 0,
   228  				"active_volumes": 0,
   229  				"active_tasks": 1,
   230                  "resource_types": null,
   231                  "platform": "platform2",
   232                  "tags": [
   233                    "tag1"
   234                  ],
   235                  "team": "team-1",
   236                  "name": "worker-6",
   237                  "version": "1.2.3",
   238                  "start_time": 0,
   239                  "state": "running",
   240                  "ephemeral": true
   241                },
   242                {
   243                  "addr": "7.7.7.7:7777",
   244                  "baggageclaim_url": "",
   245                  "active_containers": 0,
   246  				"active_volumes": 0,
   247  				"active_tasks": 0,
   248                  "resource_types": null,
   249                  "platform": "platform2",
   250                  "tags": [
   251                    "tag1"
   252                  ],
   253                  "team": "team-1",
   254                  "name": "worker-7",
   255                  "version": "",
   256                  "start_time": 0,
   257                  "state": "running",
   258                  "ephemeral": false
   259                },
   260                {
   261                  "addr": "2.2.3.4:7777",
   262                  "baggageclaim_url": "http://2.2.3.4:7788",
   263                  "active_containers": 1,
   264  				"active_volumes": 0,
   265  				"active_tasks": 1,
   266                  "resource_types": [
   267                    {
   268                      "type": "resource-1",
   269                      "image": "/images/resource-1",
   270                      "version": "",
   271                      "privileged": false,
   272                      "unique_version_history": false
   273                    },
   274                    {
   275                      "type": "resource-2",
   276                      "image": "/images/resource-2",
   277                      "version": "",
   278                      "privileged": false,
   279                      "unique_version_history": false
   280                    }
   281                  ],
   282                  "platform": "platform1",
   283                  "tags": [
   284                    "tag1"
   285                  ],
   286                  "team": "team-1",
   287                  "name": "worker-1",
   288                  "version": "4.5.6",
   289                  "start_time": 0,
   290                  "state": "landing",
   291                  "ephemeral": false
   292                },
   293                {
   294                  "addr": "3.2.3.4:7777",
   295                  "baggageclaim_url": "",
   296                  "active_containers": 10,
   297  				"active_volumes": 0,
   298  				"active_tasks": 1,
   299                  "resource_types": null,
   300                  "platform": "platform3",
   301                  "tags": [],
   302                  "team": "",
   303                  "name": "worker-3",
   304                  "version": "4.5.6",
   305                  "start_time": 0,
   306                  "state": "landed",
   307                  "ephemeral": false
   308                },
   309                {
   310                  "addr": "",
   311                  "baggageclaim_url": "",
   312                  "active_containers": 7,
   313  				"active_volumes": 0,
   314  				"active_tasks": 1,
   315                  "resource_types": null,
   316                  "platform": "platform4",
   317                  "tags": [
   318                    "tag1"
   319                  ],
   320                  "team": "team-1",
   321                  "name": "worker-4",
   322                  "version": "4.5.6",
   323                  "start_time": 0,
   324                  "state": "stalled",
   325                  "ephemeral": false
   326                },
   327                {
   328                  "addr": "3.2.3.4:7777",
   329                  "baggageclaim_url": "",
   330                  "active_containers": 5,
   331  				"active_volumes": 0,
   332  				"active_tasks": 1,
   333                  "resource_types": null,
   334                  "platform": "platform5",
   335                  "tags": [],
   336                  "team": "",
   337                  "name": "worker-5",
   338                  "version": "4.5.6",
   339                  "start_time": 0,
   340                  "state": "retiring",
   341                  "ephemeral": false
   342                }
   343              ]`))
   344  				})
   345  			})
   346  
   347  			Context("when --details is given", func() {
   348  				BeforeEach(func() {
   349  					flyCmd.Args = append(flyCmd.Args, "--details")
   350  					worker1StartTime = 0
   351  					worker2StartTime = 0
   352  					worker3StartTime = 0
   353  					worker4StartTime = 0
   354  					worker5StartTime = 0
   355  					worker6StartTime = 0
   356  					worker7StartTime = 0
   357  				})
   358  
   359  				It("lists them to the user, ordered by name", func() {
   360  					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
   361  					Expect(err).NotTo(HaveOccurred())
   362  
   363  					Eventually(sess).Should(gexec.Exit(0))
   364  					Expect(sess.Out).To(PrintTable(ui.Table{
   365  						Headers: ui.TableRow{
   366  							{Contents: "name", Color: color.New(color.Bold)},
   367  							{Contents: "containers", Color: color.New(color.Bold)},
   368  							{Contents: "platform", Color: color.New(color.Bold)},
   369  							{Contents: "tags", Color: color.New(color.Bold)},
   370  							{Contents: "team", Color: color.New(color.Bold)},
   371  							{Contents: "state", Color: color.New(color.Bold)},
   372  							{Contents: "version", Color: color.New(color.Bold)},
   373  							{Contents: "age", Color: color.New(color.Bold)},
   374  							{Contents: "garden address", Color: color.New(color.Bold)},
   375  							{Contents: "baggageclaim url", Color: color.New(color.Bold)},
   376  							{Contents: "active tasks", Color: color.New(color.Bold)},
   377  							{Contents: "resource types", Color: color.New(color.Bold)},
   378  						},
   379  						Data: []ui.TableRow{
   380  							{{Contents: "worker-1"}, {Contents: "1"}, {Contents: "platform1"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "2.2.3.4:7777"}, {Contents: "http://2.2.3.4:7788"}, {Contents: "1"}, {Contents: "resource-1, resource-2"}},
   381  							{{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag2, tag3"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "1.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "resource-1"}},
   382  							{{Contents: "worker-3"}, {Contents: "10"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "landed"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "3.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}},
   383  							{{Contents: "worker-5"}, {Contents: "5"}, {Contents: "platform5"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "3.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}},
   384  							{{Contents: "worker-6"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "1.2.3", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "5.5.5.5:7777", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}},
   385  							{{Contents: "worker-7"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "none", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "7.7.7.7:7777", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "0"}, {Contents: "none", Color: color.New(color.Faint)}},
   386  							{{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}},
   387  						},
   388  					}))
   389  				})
   390  			})
   391  		})
   392  
   393  		Context("when API does not return stalled or outdated workers", func() {
   394  			BeforeEach(func() {
   395  				atcServer.AppendHandlers(
   396  					ghttp.CombineHandlers(
   397  						ghttp.VerifyRequest("GET", "/api/v1/workers"),
   398  						ghttp.RespondWithJSONEncoded(200, []atc.Worker{
   399  							{
   400  								Name:             "worker-2",
   401  								GardenAddr:       "1.2.3.4:7777",
   402  								ActiveContainers: 0,
   403  								Platform:         "platform2",
   404  								Tags:             []string{"tag1"},
   405  								Team:             "team-1",
   406  								State:            "running",
   407  								Version:          "4.5.6",
   408  								StartTime:        0,
   409  							},
   410  							{
   411  								Name:             "worker-1",
   412  								GardenAddr:       "3.2.3.4:7777",
   413  								ActiveContainers: 10,
   414  								Platform:         "platform1",
   415  								Tags:             []string{},
   416  								Team:             "team-1",
   417  								State:            "landing",
   418  								Version:          "4.5.6",
   419  								StartTime:        0,
   420  							},
   421  							{
   422  								Name:             "worker-3",
   423  								GardenAddr:       "3.2.3.4:7777",
   424  								ActiveContainers: 5,
   425  								Platform:         "platform3",
   426  								Tags:             []string{},
   427  								State:            "retiring",
   428  								Version:          "4.5.6",
   429  								StartTime:        0,
   430  							},
   431  						}),
   432  					),
   433  				)
   434  			})
   435  
   436  			It("does not print second table", func() {
   437  				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
   438  				Expect(err).NotTo(HaveOccurred())
   439  
   440  				Eventually(sess).Should(gexec.Exit(0))
   441  				Expect(sess.Out).To(PrintTable(ui.Table{
   442  					Headers: ui.TableRow{
   443  						{Contents: "name", Color: color.New(color.Bold)},
   444  						{Contents: "containers", Color: color.New(color.Bold)},
   445  						{Contents: "platform", Color: color.New(color.Bold)},
   446  						{Contents: "tags", Color: color.New(color.Bold)},
   447  						{Contents: "team", Color: color.New(color.Bold)},
   448  						{Contents: "state", Color: color.New(color.Bold)},
   449  						{Contents: "version", Color: color.New(color.Bold)},
   450  						{Contents: "age", Color: color.New(color.Bold)},
   451  					},
   452  					Data: []ui.TableRow{
   453  						{{Contents: "worker-1"}, {Contents: "10"}, {Contents: "platform1"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}},
   454  						{{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}},
   455  						{{Contents: "worker-3"}, {Contents: "5"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}},
   456  					},
   457  				}))
   458  				Expect(sess.Out).NotTo(PrintTable(ui.Table{
   459  					Headers: ui.TableRow{
   460  						{Contents: "name", Color: color.New(color.Bold)},
   461  						{Contents: "containers", Color: color.New(color.Bold)},
   462  						{Contents: "platform", Color: color.New(color.Bold)},
   463  						{Contents: "tags", Color: color.New(color.Bold)},
   464  						{Contents: "team", Color: color.New(color.Bold)},
   465  						{Contents: "state", Color: color.New(color.Bold)},
   466  						{Contents: "version", Color: color.New(color.Bold)},
   467  						{Contents: "age", Color: color.New(color.Bold)},
   468  					},
   469  					Data: []ui.TableRow{
   470  						{{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}},
   471  					},
   472  				}))
   473  			})
   474  		})
   475  
   476  		Context("and the api returns an internal server error", func() {
   477  			BeforeEach(func() {
   478  				atcServer.AppendHandlers(
   479  					ghttp.CombineHandlers(
   480  						ghttp.VerifyRequest("GET", "/api/v1/workers"),
   481  						ghttp.RespondWith(500, ""),
   482  					),
   483  				)
   484  			})
   485  
   486  			It("writes an error message to stderr", func() {
   487  				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
   488  				Expect(err).NotTo(HaveOccurred())
   489  
   490  				Eventually(sess).Should(gexec.Exit(1))
   491  				Eventually(sess.Err).Should(gbytes.Say("Unexpected Response"))
   492  			})
   493  		})
   494  	})
   495  })