Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a command structure to Go driver #73

Merged
merged 5 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions runner/cf-driver-go/cmd/drive/cleanup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package drive

import (
"log"

"github.com/spf13/cobra"
)

var cleanupCmd = &cobra.Command{
Use: "cleanup",
Short: "Cleans up resources, containers, etc. at job completion",
Long: `The Cleanup stage is executed by "cleanup_exec".

This final stage is executed even if one of the previous stages failed.
The main goal for this stage is to clean up any of the environments that
might have been set up. For example, turning off VMs or deleting
containers.

The result of cleanup_exec does not affect job statuses. For example, a
job will be marked as successful even if the following occurs:

Both prepare_exec and run_exec are successful.
cleanup_exec fails.

The user can set cleanup_exec_timeout if they want to set some kind of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooooh - we should replace the current CUSTOM_ENV_PRESERVE_* behavior with a long (1 hour?) timeout instead of just skipping

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm yeah that would be good. An hour feels long to me, but I'm supposing it must not to you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I misunderstood you when I first read this and thought you were just talking about adding a timeout to make sure broken jobs get cleaned up.

How are you thinking this would work? We could put something like a long sleep in the run step? It does seem like an easy way to take care of at least half of #34.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally it'd be something like what circleCI does, which is 10 minutes + whatever time you're ssh'd in to the runner to do your debugging. 1 hour was assuming that we wouldn't be able to have a dynamic timeout like that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you thinking this would work?

🤷🏻 this might also be a misinterpretation of the cleanup_exec_timeout docs that triggered this whole thread. I was thinking that we could set that config and gitlab would take care of not calling cleanup right away, but that's probably wrong.

In any case, it was a thought for 34 or similar, not this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I misunderstood it… I was thinking it was a timeout on how long it would wait to kill run, but it's a timeout on how long it will wait to kill cleanup. Every stage but run has one of the timeouts, and run's time is managed in GitLab's settings globally and per runner.

But I do think we could use it to do the debugging PRESERVE's better:

  • set a long timeout on cleanup, just to override a shorter default if there is one
  • set a sleep that's a bit shorter than the timeout
  • do the regular cleanup after the sleep

deadline of how long GitLab Runner should wait to clean up the
environment before terminating the process.

The STDOUT of this executable will be printed to GitLab Runner logs at a
DEBUG level. The STDERR will be printed to the logs at a WARN level.

Read more in GitLab's documentation:
https://docs.gitlab.com/runner/executors/custom.html#cleanup`,
Run: func(cmd *cobra.Command, args []string) {
log.Println("cleaning up...")
},
}
22 changes: 22 additions & 0 deletions runner/cf-driver-go/cmd/drive/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package drive

import (
"log"

"github.com/spf13/cobra"
)

var configCmd = &cobra.Command{
Use: "config",
Short: "Configure various jobs settings before they run",
Long: `The Config stage is executed by "config_exec".

Sometimes you might want to set some settings during execution time. For
example, setting a build directory depending on the project ID.

For a detailed list of settings that can be configured, read more at:
https://docs.gitlab.com/runner/executors/custom.html#config.`,
Run: func(cmd *cobra.Command, args []string) {
log.Println("configuring...")
},
}
50 changes: 50 additions & 0 deletions runner/cf-driver-go/cmd/drive/drive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package drive

import (
"github.com/spf13/cobra"
)

func init() {
cobra.EnableCommandSorting = false
DriveCmd.AddCommand(configCmd, prepareCmd, runCmd, cleanupCmd)
}

var DriveCmd = &cobra.Command{
Use: "drive",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] is there a planned use for calling drive by itself ever? Feels like we could attach its subcommands directly to root.go instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was to segregate the gitlab-runner stage commands so that there was room in the future to add other stuff to the executable. I'm not sure that would necessarily happen—I was imagining some kind of administrative / configurative command could come in, a doctor or who knows. It could be that that never happens, but given that nobody is actually going to type these often, it seemed pretty low-cost?

I'm not super attached to the idea though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, and yeah, since these are basically never typed I'm not opposed to the extra characters.

Short: "Drive stages requested by gitlab-runner's executor",
Long: `Drive holds subcommands to run each of executor's stages.

The Custom executor provides the stages for you to configure some
details of the job, prepare and clean up the environment and run the job
script within it. Each stage is responsible for specific things and has
different things to keep in mind.

Each stage executed by the Custom executor is executed at the time a
builtin GitLab Runner executor would execute them.

For each step that will be executed, specific environment variables are
exposed to the executable, which can be used to get information about the
specific Job that is running. All stages will have the following
environment variables available to them:

- Standard CI/CD environment variables, including predefined variables.
- All environment variables provided by the Custom executor Runner host
system.
- All services and their available settings. Exposed in JSON format as
CUSTOM_ENV_CI_JOB_SERVICES.

Both CI/CD environment variables and predefined variables are prefixed
with CUSTOM_ENV_ to prevent conflicts with system environment variables.
For example, CI_BUILDS_DIR will be available as CUSTOM_ENV_CI_BUILDS_DIR.

The stages run in the following sequence:

1. config_exec
2. prepare_exec
3. run_exec
4. cleanup_exec

Read more in GitLab's documentation:
https://docs.gitlab.com/runner/executors/custom.html#stages
`,
}
34 changes: 34 additions & 0 deletions runner/cf-driver-go/cmd/drive/prepare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package drive

import (
"log"

"github.com/spf13/cobra"
)

var prepareCmd = &cobra.Command{
Use: "prepare",
Short: "Prepare for jobs by starting containers, services, etc.",
Long: `The Prepare stage is executed by "prepare_exec".

At this point, GitLab Runner knows everything about the job (where and
how it’s going to run). The only thing left is for the environment to be
set up so the job can run. Prepare will execute the steps necessary to
create that environment.

This is responsible for setting up the environment (for example,
creating the virtual machine or container, services or anything else).
After this is done, we expect that the environment is ready to run the
job.

This stage is executed only once in a job execution.

The STDOUT and STDERR returned from this executable will print to the
job log.

Read more in GitLab's documentation:
https://docs.gitlab.com/runner/executors/custom.html#prepare`,
Run: func(cmd *cobra.Command, args []string) {
log.Println("preparing...")
},
}
61 changes: 61 additions & 0 deletions runner/cf-driver-go/cmd/drive/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package drive

import (
"log"

"github.com/spf13/cobra"
)

var runCmd = &cobra.Command{
Use: "run",
Short: "Executes substages (e.g., cache download) and job steps",
Long: `The Run stage is executed by "run_exec".

The STDOUT and STDERR returned from this executable will print to the job
log.

Unlike the other stages, the run_exec stage is executed multiple times,
since it’s split into sub stages listed below in sequential order:

prepare_script
get_sources
restore_cache
download_artifacts
step_*
build_script
step_*
after_script
archive_cache OR archive_cache_on_failure
upload_artifacts_on_success OR upload_artifacts_on_failure
cleanup_file_variables

In GitLab Runner 14.0 and later, build_script will be replaced with
step_script. For more information, see this issue.

For each stage mentioned above, the run_exec executable will be executed
with (1) the path to the script that GitLab Runner creates for the Custom
executor to run, and (2) the name of the stage.

This executable should be responsible for executing the scripts that are
specified in the first argument. They contain all the scripts any GitLab
Runner executor would run normally to clone, download artifacts, run
user scripts and all the other steps described below. The scripts can be
of the following shells:

Bash
PowerShell Desktop
PowerShell Core
Batch (deprecated)

We generate the script using the shell configured by shell inside of
[[runners]]. If none is provided the defaults for the OS platform are used.

The table below is a detailed explanation of what each script does and
what the main goal of that script is.

Read more in GitLab's documentation:
https://docs.gitlab.com/runner/executors/custom.html#run`,
Run: func(cmd *cobra.Command, args []string) {
log.Println("running...")
},
}
30 changes: 30 additions & 0 deletions runner/cf-driver-go/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cmd

import (
"fmt"
"os"

"github.com/GSA-TTS/gitlab-runner-cloudgov/runner/cf-driver/cmd/drive"

"github.com/spf13/cobra"
)

func init() {
rootCmd.AddCommand(drive.DriveCmd)
}

var rootCmd = &cobra.Command{
Use: "cfd",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[question] - the docs mention cfd but when I run make build I get a cf-driver executable. Should those be consistent? If something needs to change I do like the shorter version more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I haven't been using the actual executable much & didn't think of it.

Short: "CloudFoundry Driver",
Long: `This is CloudFoundry Driver for the GitLab Custom executor.

The gitlab-runner service should run cfd with it's "drive" subcommands,
e.g., "cfd drive prepare".`,
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
14 changes: 11 additions & 3 deletions runner/cf-driver-go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ go 1.23
require (
github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9
github.com/google/go-cmp v0.6.0
github.com/joho/godotenv v1.5.1
github.com/spf13/cobra v1.8.1
)

require (
github.com/kr/pretty v0.3.1 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
)

require (
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/joho/godotenv v1.5.1
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
26 changes: 22 additions & 4 deletions runner/cf-driver-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,38 @@ github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9 h1:HK3+nJEPgwlhc5H74aw/V4m
github.com/cloudfoundry/go-cfclient/v3 v3.0.0-alpha.9/go.mod h1:eUjFfpsU3lRv388wKlXMmkQfsJ9pveUHZEia7AoBCPY=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11 h1:YFh+sjyJTMQSYjKwM4dFKhJPJC/wfo98tPUc17HdoYw=
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
Expand All @@ -25,7 +42,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
16 changes: 2 additions & 14 deletions runner/cf-driver-go/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"log"

"github.com/GSA-TTS/gitlab-runner-cloudgov/runner/cf-driver/cg"
"github.com/GSA-TTS/gitlab-runner-cloudgov/runner/cf-driver/cmd"
"github.com/joho/godotenv"
)

Expand All @@ -25,17 +25,5 @@ func main() {
panic("error loading .env file")
}

cgClient, err := cg.New(&cg.GoCFClientAdapter{}, nil)
if err != nil {
panic(err)
}

apps, err := cgClient.GetApps()
if err != nil {
panic(err)
}

for _, app := range apps {
log.Printf("Application %s is %s\n", app.Name, app.State)
}
cmd.Execute()
}
21 changes: 0 additions & 21 deletions runner/cf-driver-go/main_test.go

This file was deleted.

Loading