commit c8056a9fe92c8e52d14c23ea962ccb2a04d951d1 Author: Thomas Bellembois Date: Fri Sep 30 14:41:18 2022 +0200 First commit. diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..8f43dee --- /dev/null +++ b/.drone.yml @@ -0,0 +1,20 @@ +kind: pipeline +type: docker +name: build + +trigger: + event: + - push + +steps: + - name: docker-build + image: plugins/docker + settings: + dockerfile: Dockerfile + context: . + registry: hub.codefirst.iut.uca.fr + repo: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone + username: + from_secret: SECRET_REGISTRY_USERNAME + password: + from_secret: SECRET_REGISTRY_PASSWORD \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..adf8f72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..7a982dc --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,102 @@ +# options for analysis running +run: + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 1m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 0 + + # include test files or not, default is true + tests: false + + # which dirs to skip: issues from them won't be reported; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but default dirs are skipped independently + # from this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + skip-dirs: + - wasm + - static + - node_modules + - documents + - docker + - bind-* + + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: true + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + modules-download-mode: mod + + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: true + + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions + # default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + + # make issues output unique by line, default is true + uniq-by-line: true + + # add a prefix to the output file references; default is no prefix + path-prefix: "" + + # sorts results by: filepath, line and column + sort-results: false + + +# all available settings of specific linters +linters-settings: + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + staticcheck: + # Select the Go version to target. The default is '1.13'. + go: "1.19" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + stylecheck: + # Select the Go version to target. The default is '1.13'. + go: "1.19" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + errcheck: + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: true + +linters: + enable: + # go install github.com/kisielk/errcheck@latest + # go install github.com/gordonklaus/ineffassign@latest + # go install honnef.co/go/tools/cmd/staticcheck@latest + # go install gitlab.com/opennota/check/cmd/varcheck@latest + # go install github.com/go-critic/go-critic/cmd/gocritic@latest + - errcheck + - staticcheck + - stylecheck + - ineffassign + - varcheck + - gofmt + - gocritic + - wsl + fast: false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..69c343a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.19-bullseye +LABEL author="Thomas Bellembois" + +# Copying sources. +WORKDIR /go/src/codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-dockerproxy-clientdrone/v2/ +COPY . . + +# Installing. +RUN go install -v ./... +RUN chmod +x /go/bin/codefirst-dockerproxy-clientdrone + +# Copying entrypoint. +COPY entrypoint.sh / +RUN chmod +x /entrypoint.sh + +USER root +EXPOSE 8081 +ENTRYPOINT [ "/entrypoint.sh" ] \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..1c5fd0b --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +ProxyScheme="" +ProxyHost="" +ProxyPath="" + +ImageName="" +ContainerName="" +Overwrite="" +Private="" +Env="" +Command="" + +if [ ! -z "$PROXYSCHEME" ] +then + ProxyScheme="-proxyscheme $PROXYSCHEME" +fi + +if [ ! -z "$PROXYHOST" ] +then + ProxyHost="-proxyhost $PROXYHOST" +fi + +if [ ! -z "$PROXYPATH" ] +then + ProxyPath="-proxypath $PROXYPATH" +fi + +if [ ! -z "$IMAGENAME" ] +then + ImageName="-imagename $IMAGENAME" +fi + +if [ ! -z "$CONTAINERNAME" ] +then + ContainerName="-containername $CONTAINERNAME" +fi + +if [ ! -z "$COMMAND" ] +then + Command="-command $COMMAND" +fi + +if [ ! -z "$PRIVATE" ] +then + Private="-private" +fi + +if [ ! -z "$OVERWRITE" ] +then + Overwrite="-overwrite" +fi + +prefix="CODEFIRST_CLIENTDRONE_ENV_" +ENVS=$(env | awk -F "=" '{print $1}' | grep ".*$prefix.*") + +if [ ! -z "$ENVS" ] +then + Env="" + arrayEnv=($ENVS) + + for i in "${arrayEnv[@]}" + do + envVarName=${i#"$prefix"} + Env=$Env" -env $envVarName=${!i}" + done +fi + +echo $ProxyScheme +echo $ProxyHost +echo $ProxyPath + +echo $ImageName +echo $ContainerName +echo $Overwrite +echo $Private +echo $Env +echo $Command + +#/go/bin +sh -c "/go/bin/codefirst-dockerproxy-clientdrone $ProxyScheme $ProxyHost $ProxyPath $ImageName $ContainerName $Private $Overwrite $Env $Command" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b8bdf20 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-dockerproxy-clientdrone + +go 1.19 + +require github.com/go-resty/resty/v2 v2.7.0 + +require golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a5c1a24 --- /dev/null +++ b/go.sum @@ -0,0 +1,9 @@ +github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..beb424f --- /dev/null +++ b/main.go @@ -0,0 +1,236 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/go-resty/resty/v2" +) + +type CodeFirstContainer struct { + ID string `json:"Id"` + Image string `json:"Image"` + Env []string `json:"Env,omitempty"` + Private bool `json:"Private,omitempty"` +} + +type StringSliceFlag struct { + value []string +} + +func (s *StringSliceFlag) String() string { + return fmt.Sprintf("%s", *s) +} + +func (s *StringSliceFlag) Set(v string) error { + s.value = append(s.value, v) + return nil +} + +var ( + authUser string + + command string + proxyScheme, proxyHost, proxyPath string + imageName, containerName string + + private, overwrite, devel bool + + env StringSliceFlag +) + +func main() { + + env = StringSliceFlag{} + + flag.StringVar(&command, "command", "list", "list|logs|create|delete|start") + flag.BoolVar(&devel, "devel", false, "use fake x-forwarded-user") + + flag.StringVar(&proxyScheme, "proxyscheme", "http", "proxy scheme") + flag.StringVar(&proxyHost, "proxyhost", "dockerproxy:8080", "proxy host") + flag.StringVar(&proxyPath, "proxypath", "/", "proxy path") + + flag.StringVar(&imageName, "imagename", "", "image name") + flag.StringVar(&containerName, "containername", "", "container name") + flag.BoolVar(&private, "private", false, "private container") + flag.BoolVar(&overwrite, "overwrite", false, "overwrite existing container") + flag.Var(&env, "env", "environment variables (separated by spaces)") + + flag.Parse() + + fmt.Println("flags:") + fmt.Printf("-imagename: %s\n", imageName) + fmt.Printf("-containername: %s\n", containerName) + fmt.Printf("-private: %t\n", private) + fmt.Printf("-overwrite: %t\n", overwrite) + fmt.Printf("-env: %s\n", env) + + if command != "list" && containerName == "" { + fmt.Println("Missing containername parameter.") + os.Exit(1) + } + + if command == "create" && imageName == "" { + fmt.Println("Missing imagename parameter.") + os.Exit(1) + } + + if devel { + authUser = "thbellem" + } else { + authUser = os.Getenv("CI_COMMIT_AUTHOR") + } + + if len(authUser) == 0 { + fmt.Println("Not authenticated.") + os.Exit(1) + } + + switch command { + case "list": + list() + case "logs": + logs() + case "create": + if overwrite { + delete(true) + } + + if !exist() { + create() + start() + } + case "start": + start() + case "delete": + delete(false) + } + +} + +func exist() bool { + client := resty.New() + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + Get(fmt.Sprintf("%s://%s/containers/%s/json", proxyScheme, proxyHost, containerName)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + return resp.IsSuccess() +} + +func list() { + client := resty.New() + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + Get(fmt.Sprintf("%s://%s/containers/json", proxyScheme, proxyHost)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + if resp.IsError() { + os.Exit(1) + } +} + +func logs() { + client := resty.New() + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + Get(fmt.Sprintf("%s://%s/containers/%s/logs", proxyScheme, proxyHost, containerName)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + if resp.IsError() { + os.Exit(1) + } +} + +func start() { + client := resty.New() + + container := CodeFirstContainer{ + Image: imageName, + Env: env.value, + Private: private, + } + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + SetBody(container). + Post(fmt.Sprintf("%s://%s/containers/%s/start", proxyScheme, proxyHost, containerName)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + if resp.IsError() { + os.Exit(1) + } +} + +func create() { + client := resty.New() + + container := CodeFirstContainer{ + Image: imageName, + Env: env.value, + Private: private, + } + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + SetBody(container). + Post(fmt.Sprintf("%s://%s/containers/create/%s", proxyScheme, proxyHost, containerName)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + if resp.IsError() { + os.Exit(1) + } +} + +func delete(bypassError bool) { + client := resty.New() + + resp, err := client.R(). + SetHeader("x-forwarded-user", authUser). + Delete(fmt.Sprintf("%s://%s/containers/%s", proxyScheme, proxyHost, containerName)) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + fmt.Println(string(resp.Body())) + + if !bypassError && resp.IsError() { + os.Exit(1) + } +}