feat: make podman service start automatically (#140)
This commit is contained in:
parent
e0e954702c
commit
ed06988a06
|
@ -4,6 +4,7 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
_ "embed"
|
||||
|
||||
|
@ -61,6 +62,10 @@ func (s serviceMode) All() []serviceMode {
|
|||
ServiceModePodman, ServiceModeDocker}
|
||||
}
|
||||
|
||||
func (s serviceMode) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (o *serviceOption) preRunE(c *cobra.Command, args []string) (err error) {
|
||||
if o.action == "" && len(args) > 0 {
|
||||
o.action = args[0]
|
||||
|
@ -99,6 +104,7 @@ func (o *serviceOption) runE(c *cobra.Command, args []string) (err error) {
|
|||
err = fmt.Errorf("not support action: '%s'", o.action)
|
||||
}
|
||||
|
||||
output = strings.TrimSpace(output)
|
||||
if output != "" {
|
||||
c.Println(output)
|
||||
}
|
||||
|
@ -124,12 +130,12 @@ func (a Action) All() []Action {
|
|||
|
||||
// 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)
|
||||
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 {
|
||||
|
@ -176,16 +182,20 @@ func (o *serviceOption) getContainerService() (service Service, err error) {
|
|||
var client string
|
||||
switch serviceMode(o.mode) {
|
||||
case ServiceModeDocker:
|
||||
client = "docker"
|
||||
client = ServiceModeDocker.String()
|
||||
case ServiceModePodman, ServiceModeContainer:
|
||||
client = "podman"
|
||||
client = ServiceModePodman.String()
|
||||
default:
|
||||
err = fmt.Errorf("not support mode: '%s'", o.mode)
|
||||
return
|
||||
}
|
||||
|
||||
if client, err = o.LookPath(client); err == nil {
|
||||
service = newContainerService(o.Execer, client, o.image, o.version)
|
||||
var clientPath string
|
||||
if clientPath, err = o.LookPath(client); err == nil {
|
||||
if clientPath == "" {
|
||||
clientPath = client
|
||||
}
|
||||
service = newContainerService(o.Execer, clientPath, o.image, o.version)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -247,35 +257,38 @@ type linuxService struct {
|
|||
commonService
|
||||
}
|
||||
|
||||
const systemCtl = "systemctl"
|
||||
const serviceName = "atest"
|
||||
|
||||
func (s *linuxService) Start() (output string, err error) {
|
||||
output, err = s.Execer.RunCommandAndReturn("systemctl", "", "start", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "start", serviceName)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *linuxService) Stop() (output string, err error) {
|
||||
output, err = s.Execer.RunCommandAndReturn("systemctl", "", "stop", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "stop", serviceName)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *linuxService) Restart() (output string, err error) {
|
||||
output, err = s.Execer.RunCommandAndReturn("systemctl", "", "restart", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "restart", serviceName)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *linuxService) Status() (output string, err error) {
|
||||
output, err = s.Execer.RunCommandAndReturn("systemctl", "", "status", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "status", serviceName)
|
||||
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("systemctl", "", "enable", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "enable", serviceName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *linuxService) Uninstall() (output string, err error) {
|
||||
output, err = s.Execer.RunCommandAndReturn("systemctl", "", "disable", "atest")
|
||||
output, err = s.Execer.RunCommandAndReturn(systemCtl, "", "disable", serviceName)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -296,20 +309,31 @@ func newContainerService(execer fakeruntime.Execer, client, image, tag string) (
|
|||
if image == "" {
|
||||
image = defaultImage
|
||||
}
|
||||
service = &containerService{
|
||||
|
||||
containerServer := &containerService{
|
||||
Execer: execer,
|
||||
client: client,
|
||||
name: "atest",
|
||||
name: serviceName,
|
||||
image: image,
|
||||
tag: tag,
|
||||
}
|
||||
|
||||
if strings.HasSuffix(client, ServiceModePodman.String()) {
|
||||
service = &podmanService{
|
||||
containerService: *containerServer,
|
||||
}
|
||||
} else {
|
||||
service = containerServer
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *containerService) Start() (output string, err error) {
|
||||
err = s.Execer.SystemCall(s.client, []string{s.client, "run", "--name=" + s.name,
|
||||
"--restart=always", "-d", "--pull=always", "--network=host",
|
||||
s.image + ":" + s.tag}, os.Environ())
|
||||
if s.exist() {
|
||||
output, err = s.Execer.RunCommandAndReturn(s.client, "", "start", s.name)
|
||||
} else {
|
||||
err = s.Execer.SystemCall(s.client, append([]string{s.client}, s.getStartArgs()...), os.Environ())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -323,7 +347,8 @@ func (s *containerService) Restart() (output string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *containerService) Status() (output string, err error) {
|
||||
func (s *containerService) Status() (_ string, err error) {
|
||||
err = s.Execer.SystemCall(s.client, []string{s.client, "stats", s.name}, os.Environ())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -336,3 +361,33 @@ func (s *containerService) Uninstall() (output string, err error) {
|
|||
output, err = s.Stop()
|
||||
return
|
||||
}
|
||||
|
||||
func (s *containerService) exist() bool {
|
||||
output, err := s.Execer.RunCommandAndReturn(s.client, "", "ps", "--all", "--filter", fmt.Sprintf("name=%s", s.name))
|
||||
return err == nil && strings.Contains(output, s.name)
|
||||
}
|
||||
|
||||
func (s *containerService) getStartArgs() []string {
|
||||
return []string{"run", "--name=" + s.name,
|
||||
"--restart=always", "-d", "--pull=always", "--network=host",
|
||||
s.image + ":" + s.tag}
|
||||
}
|
||||
|
||||
type podmanService struct {
|
||||
containerService
|
||||
}
|
||||
|
||||
func (s *podmanService) Start() (output string, err error) {
|
||||
if s.exist() {
|
||||
output, err = s.Execer.RunCommandAndReturn(s.client, "", "start", s.name)
|
||||
} else {
|
||||
output, err = s.Execer.RunCommandAndReturn(s.client, "", s.getStartArgs()...)
|
||||
|
||||
if err == nil {
|
||||
var result string
|
||||
result, err = s.Execer.RunCommandAndReturn(s.client, "", "generate", "systemd", "--new", "--files", "--name", s.name)
|
||||
output = fmt.Sprintf("%s\n%s", output, result)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -143,6 +143,12 @@ func TestService(t *testing.T) {
|
|||
targetOS: fakeruntime.OSLinux,
|
||||
mode: string(ServiceModeDocker),
|
||||
expectOutput: "",
|
||||
}, {
|
||||
name: "start in podman",
|
||||
action: "start",
|
||||
targetOS: fakeruntime.OSLinux,
|
||||
mode: ServiceModePodman.String(),
|
||||
expectOutput: "",
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -36,8 +36,6 @@
|
|||
"grpc_tools_node_protoc_ts": "^5.3.3",
|
||||
"grpc-tools": "^1.12.4",
|
||||
"jest": "^29.6.1",
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"jest-mock-fetch": "^2.0.5",
|
||||
"jsdom": "^22.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.8.8",
|
||||
|
@ -4200,15 +4198,6 @@
|
|||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -7459,16 +7448,6 @@
|
|||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-fetch-mock": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz",
|
||||
"integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.0.4",
|
||||
"promise-polyfill": "^8.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-get-type": {
|
||||
"version": "29.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
|
||||
|
@ -7705,21 +7684,6 @@
|
|||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-mock-fetch": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-fetch/-/jest-mock-fetch-2.0.5.tgz",
|
||||
"integrity": "sha512-SqjzvjLgehVvrhweq9r2pLxlz3ZwPC2p14yTZFxy+bejE+jDgpV+0aw/oysP088wlFbzEl3TRy0gWIYY25vVEA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"jest-mock-promise": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-mock-promise": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-promise/-/jest-mock-promise-2.0.2.tgz",
|
||||
"integrity": "sha512-JD5zcuoagmSJ+Gb05iD8o+Ze/viWLzI7QnrVY3Q8FyDVGUH5aXxZON+u7S9ouAt59sLNR97dSMWGezfTkkb5hg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/jest-pnp-resolver": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
|
||||
|
@ -10052,12 +10016,6 @@
|
|||
"asap": "~2.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-polyfill": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz",
|
||||
"integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
|
@ -15343,15 +15301,6 @@
|
|||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -17893,16 +17842,6 @@
|
|||
"jest-util": "^29.6.1"
|
||||
}
|
||||
},
|
||||
"jest-fetch-mock": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz",
|
||||
"integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-fetch": "^3.0.4",
|
||||
"promise-polyfill": "^8.1.3"
|
||||
}
|
||||
},
|
||||
"jest-get-type": {
|
||||
"version": "29.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
|
||||
|
@ -18081,21 +18020,6 @@
|
|||
"jest-util": "^29.6.1"
|
||||
}
|
||||
},
|
||||
"jest-mock-fetch": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-fetch/-/jest-mock-fetch-2.0.5.tgz",
|
||||
"integrity": "sha512-SqjzvjLgehVvrhweq9r2pLxlz3ZwPC2p14yTZFxy+bejE+jDgpV+0aw/oysP088wlFbzEl3TRy0gWIYY25vVEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jest-mock-promise": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"jest-mock-promise": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-mock-promise/-/jest-mock-promise-2.0.2.tgz",
|
||||
"integrity": "sha512-JD5zcuoagmSJ+Gb05iD8o+Ze/viWLzI7QnrVY3Q8FyDVGUH5aXxZON+u7S9ouAt59sLNR97dSMWGezfTkkb5hg==",
|
||||
"dev": true
|
||||
},
|
||||
"jest-pnp-resolver": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
|
||||
|
@ -19919,12 +19843,6 @@
|
|||
"asap": "~2.0.6"
|
||||
}
|
||||
},
|
||||
"promise-polyfill": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz",
|
||||
"integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==",
|
||||
"dev": true
|
||||
},
|
||||
"prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
|
|
Loading…
Reference in New Issue