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

feat: support to install as a windows service #273

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/pre-commit
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/sh

make test-all
make fmt test-all
15 changes: 9 additions & 6 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
Test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
Expand Down Expand Up @@ -41,7 +41,7 @@ jobs:
pull-requests: write
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
Build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
Expand All @@ -90,14 +90,17 @@ jobs:
BuildImage:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.19.x
- name: Set output
id: vars
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT
- name: Package Helm
run: |
export APP_VERSION=${{ steps.vars.outputs.tag }}
Expand All @@ -123,7 +126,7 @@ jobs:
BuildEmbedUI:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
Expand Down
20 changes: 13 additions & 7 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3.0.0
uses: actions/checkout@v4
- name: Unshallow
run: git fetch --prune --unshallow
- name: Set up Go
Expand All @@ -41,7 +41,7 @@ jobs:
Test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3.0.0
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
Expand All @@ -66,10 +66,13 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3.0.0
uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Set output
id: vars
run: git describe --tags >> $GITHUB_OUTPUT
run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT
- name: Setup Docker buildx
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
- name: Log into registry ${{ env.REGISTRY }}
Expand Down Expand Up @@ -101,7 +104,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3.0.0
uses: actions/checkout@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
- name: Log into registry ${{ env.REGISTRY }}
Expand Down Expand Up @@ -132,10 +135,13 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3.0.0
uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Set output
id: vars
run: git describe --tags >> $GITHUB_OUTPUT
run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT
- name: Setup Docker buildx
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
- name: Log into registry ${{ env.REGISTRY_DOCKERHUB }}
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fmt:
build:
mkdir -p bin
rm -rf bin/atest
go build ${TOOLEXEC} -a ${BUILD_FLAG} -o bin/atest main.go
go build ${TOOLEXEC} -a ${BUILD_FLAG} -o bin/${BINARY} main.go
build-ext: build-ext-git build-ext-orm build-ext-s3 build-ext-etcd
build-ext-git:
CGO_ENABLED=0 go build -ldflags "-w -s" -o bin/atest-store-git extensions/store-git/main.go
Expand All @@ -41,8 +41,12 @@ clean-embed-ui:
build-embed-ui: embed-ui
GOOS=${OS} go build ${TOOLEXEC} -a -ldflags "-w -s -X github.com/linuxsuren/api-testing/pkg/version.version=$(shell git rev-parse --short HEAD)" -o bin/${BINARY} main.go
make clean-embed-ui
build-darwin:
BINARY=atest_darwin GOOS=darwin make build
build-win:
BINARY=atest.exe GOOS=windows make build
build-win-embed-ui:
BINARY=atest.exe OS=windows make build-embed-ui
BINARY=atest.exe GOOS=windows make build-embed-ui
goreleaser:
goreleaser build --rm-dist --snapshot
make clean-embed-ui
Expand Down
1 change: 1 addition & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
debugHandler(mux)
o.httpServer.WithHandler(mux)
log.Printf("HTTP server listening at %v", httplis.Addr())
log.Printf("Server is running.")
err = o.httpServer.Serve(httplis)
err = util.IgnoreErrServerClosed(err)
}
Expand Down
142 changes: 11 additions & 131 deletions cmd/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type serverFeatureOption struct {
type serviceOption struct {
action string
scriptPath string
service Service
service service.Service
image string
version string
fakeruntime.Execer
Expand Down Expand Up @@ -98,7 +98,7 @@ func (o *serviceOption) preRunE(c *cobra.Command, args []string) (err error) {

switch serviceMode(o.mode) {
case ServiceModeOS:
o.service, err = o.getOSService()
o.service = service.NewService(o.Execer, o.scriptPath)
default:
o.service, err = o.getContainerService()
}
Expand Down Expand Up @@ -155,57 +155,24 @@ func (a Action) All() []Action {
ActionRestart, ActionStatus}
}

// Service is the interface of service
type Service interface {
Start() (string, error) // start the service
Stop() (string, error) // stop the service gracefully
Restart() (string, error) // restart the service gracefully
Status() (string, error) // status of the service
Install() (string, error) // install the service
Uninstall() (string, error) // uninstall the service
}

func emptyThenDefault(value, defaultValue string) string {
if value == "" {
value = defaultValue
}
return value
}

func (o *serviceOption) getOSService() (service Service, err error) {
if o.Execer.OS() != fakeruntime.OSLinux && o.Execer.OS() != fakeruntime.OSDarwin {
err = fmt.Errorf("only support on Linux/Darwin instead of %s", o.Execer.OS())
} else {
service = newService(o.Execer, o.scriptPath)
}
return
}

func newService(execer fakeruntime.Execer, scriptPath string) (service Service) {
switch execer.OS() {
case fakeruntime.OSDarwin:
service = &macOSService{
commonService: commonService{
Execer: execer,
scriptPath: emptyThenDefault(scriptPath, "/Library/LaunchDaemons/com.github.linuxsuren.atest.plist"),
script: macOSServiceScript,
},
cli: "launchctl",
id: "com.github.linuxsuren.atest",
}
case fakeruntime.OSLinux:
service = &linuxService{
commonService: commonService{
Execer: execer,
scriptPath: emptyThenDefault(scriptPath, "/lib/systemd/system/atest.service"),
script: linuxServiceScript,
},
}
}
func (o *serviceOption) getOSService() (svc service.Service, err error) {
//if o.Execer.OS() != fakeruntime.OSLinux && o.Execer.OS() != fakeruntime.OSDarwin {
// err = fmt.Errorf("only support on Linux/Darwin instead of %s", o.Execer.OS())
//} else {
// svc = service.NewService(o.Execer, o.scriptPath)
//}
svc = service.NewService(o.Execer, o.scriptPath)
return
}

func (o *serviceOption) getContainerService() (service Service, err error) {
func (o *serviceOption) getContainerService() (service service.Service, err error) {
var client string
switch serviceMode(o.mode) {
case ServiceModeDocker:
Expand Down Expand Up @@ -234,93 +201,6 @@ type commonService struct {
script string
}

type macOSService struct {
commonService
cli string
id string
}

var (
//go:embed data/macos_service.xml
macOSServiceScript string
//go:embed data/linux_service.txt
linuxServiceScript string
)

func (s *macOSService) Start() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn("sudo", "", s.cli, "start", s.id)
return
}

func (s *macOSService) Stop() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn("sudo", "", s.cli, "stop", s.id)
return
}

func (s *macOSService) Restart() (output string, err error) {
if output, err = s.Stop(); err == nil {
output, err = s.Start()
}
return
}

func (s *macOSService) Status() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn("sudo", "", s.cli, "runstats", s.id)
return
}

func (s *macOSService) Install() (output string, err error) {
if err = os.WriteFile(s.scriptPath, []byte(s.script), os.ModeAppend); err == nil {
output, err = s.Execer.RunCommandAndReturn("sudo", "", s.cli, "enable", s.id)
}
return
}

func (s *macOSService) Uninstall() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn("sudo", "", s.cli, "disable", s.id)
return
}

type linuxService struct {
commonService
}

func (s *linuxService) Start() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "start", service.ServiceName)
return
}

func (s *linuxService) Stop() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "stop", service.ServiceName)
return
}

func (s *linuxService) Restart() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "restart", service.ServiceName)
return
}

func (s *linuxService) Status() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "status", service.ServiceName)
if err != nil && err.Error() == "exit status 3" {
// this is normal case
err = nil
}
return
}

func (s *linuxService) Install() (output string, err error) {
if err = os.WriteFile(s.scriptPath, []byte(s.script), os.ModeAppend); err == nil {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "enable", service.ServiceName)
}
return
}

func (s *linuxService) Uninstall() (output string, err error) {
output, err = s.Execer.RunCommandAndReturn(service.SystemCtl, "", "disable", service.ServiceName)
return
}

type containerService struct {
Execer fakeruntime.Execer
name string
Expand All @@ -338,7 +218,7 @@ type containerService struct {
const defaultImage = "linuxsuren.docker.scarf.sh/linuxsuren/api-testing"

func newContainerService(execer fakeruntime.Execer, client, image, tag, pull string,
featureOption serverFeatureOption, writer io.Writer) (svc Service) {
featureOption serverFeatureOption, writer io.Writer) (svc service.Service) {
if tag == "" {
tag = "latest"
}
Expand Down
File renamed without changes.
File renamed without changes.
46 changes: 46 additions & 0 deletions cmd/service/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
MIT License
Copyright (c) 2023 API Testing Authors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package service

import fakeruntime "github.com/linuxsuren/go-fake-runtime"

// Service is the interface of service
type Service interface {
Start() (string, error) // start the service
Stop() (string, error) // stop the service gracefully
Restart() (string, error) // restart the service gracefully
Status() (string, error) // status of the service
Install() (string, error) // install the service
Uninstall() (string, error) // uninstall the service
}

type commonService struct {
fakeruntime.Execer
scriptPath string
script string
}

func emptyThenDefault(value, defaultValue string) string {
if value == "" {
value = defaultValue
}
return value
}
Loading