Skip to content

Commit

Permalink
Merge pull request #18 from funbox/develop
Browse files Browse the repository at this point in the history
Version 0.10.0
  • Loading branch information
andyone authored Apr 4, 2017
2 parents ce08552 + 7357c13 commit e45c3d9
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 114 deletions.
2 changes: 1 addition & 1 deletion cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
// App props
const (
APP = "init-exporter"
VER = "0.9.0"
VER = "0.10.0"
DESC = "Utility for exporting services described by Procfile to init system"
)

Expand Down
9 changes: 7 additions & 2 deletions common/init-exporter.spec
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@

Summary: Utility for exporting services described by Procfile to init system
Name: init-exporter
Version: 0.9.0
Release: 2%{?dist}
Version: 0.10.0
Release: 0%{?dist}
Group: Development/Tools
License: MIT
URL: https://github.com/funbox/init-exporter
Expand Down Expand Up @@ -132,6 +132,11 @@ rm -rf %{buildroot}
###############################################################################

%changelog
* Tue Apr 04 2017 Anton Novojilov <[email protected]> - 0.10.0-0
- Added kill signal definition feature for v2 and all exporters
- Added reload signal definition feature for v2 and all exporters
- Improved parsing commands in v2 Procfile format

* Mon Apr 03 2017 Anton Novojilov <[email protected]> - 0.9.0-2
- [converter] Fixed bug with wrong path to working dir

Expand Down
26 changes: 12 additions & 14 deletions export/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,6 @@ func (s *ExportSuite) TestUpstartExport(c *C) {
service1Helper := strings.Split(string(service1HelperData), "\n")
service2Helper := strings.Split(string(service2HelperData), "\n")

c.Assert(appUnit, HasLen, 16)
c.Assert(service1Unit, HasLen, 21)
c.Assert(service2Unit, HasLen, 21)
c.Assert(service1Helper, HasLen, 8)
c.Assert(service2Helper, HasLen, 8)

c.Assert(appUnit[2:], DeepEquals,
[]string{
"start on runlevel [3]",
Expand All @@ -144,6 +138,8 @@ func (s *ExportSuite) TestUpstartExport(c *C) {
"respawn limit 15 25",
"",
"kill timeout 10",
"kill signal SIGQUIT",
"",
"",
"limit nofile 1024 1024",
"",
Expand All @@ -167,6 +163,8 @@ func (s *ExportSuite) TestUpstartExport(c *C) {
"",
"kill timeout 0",
"",
"reload signal SIGUSR2",
"",
"limit nofile 4096 4096",
"limit nproc 4096 4096",
"",
Expand All @@ -182,7 +180,7 @@ func (s *ExportSuite) TestUpstartExport(c *C) {
c.Assert(service1Helper[4:], DeepEquals,
[]string{
"[[ -r /etc/profile.d/rbenv.sh ]] && source /etc/profile.d/rbenv.sh", "",
"cd /srv/service/service1-dir && exec env STAGING=true /bin/echo 'service1:pre' >>/srv/service/service1-dir/log/service1.log && exec env STAGING=true /bin/echo 'service1' >>/srv/service/service1-dir/log/service1.log && exec env STAGING=true /bin/echo 'service1:post' >>/srv/service/service1-dir/log/service1.log",
"cd /srv/service/service1-dir && exec env STAGING=true /bin/echo 'service1:pre' &>>/srv/service/service1-dir/log/service1.log && exec env STAGING=true /bin/echo 'service1' &>>/srv/service/service1-dir/log/service1.log && exec env STAGING=true /bin/echo 'service1:post' &>>/srv/service/service1-dir/log/service1.log",
""},
)

Expand Down Expand Up @@ -275,12 +273,6 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
service1Helper := strings.Split(string(service1HelperData), "\n")
service2Helper := strings.Split(string(service2HelperData), "\n")

c.Assert(appUnit, HasLen, 22)
c.Assert(service1Unit, HasLen, 29)
c.Assert(service2Unit, HasLen, 29)
c.Assert(service1Helper, HasLen, 8)
c.Assert(service2Helper, HasLen, 8)

c.Assert(appUnit[2:], DeepEquals,
[]string{
"[Unit]",
Expand Down Expand Up @@ -314,6 +306,7 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
"[Service]",
"Type=simple",
"",
"KillSignal=SIGQUIT",
"TimeoutStopSec=10",
"Restart=on-failure",
"StartLimitInterval=25",
Expand All @@ -332,6 +325,7 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
"WorkingDirectory=/srv/service/service1-dir",
"Environment=STAGING=true",
fmt.Sprintf("ExecStart=/bin/bash %s/test_application-service1.sh &>>/var/log/test_application/service1.log", helperDir),
"",
""},
)

Expand All @@ -345,6 +339,7 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
"[Service]",
"Type=simple",
"",
"",
"TimeoutStopSec=0",
"Restart=on-failure",
"",
Expand All @@ -363,13 +358,14 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
"WorkingDirectory=/srv/service/working-dir",
"",
fmt.Sprintf("ExecStart=/bin/bash %s/test_application-service2.sh &>>/var/log/test_application/service2.log", helperDir),
"ExecReload=/bin/kill -SIGUSR2 $MAINPID",
""},
)

c.Assert(service1Helper[4:], DeepEquals,
[]string{
"[[ -r /etc/profile.d/rbenv.sh ]] && source /etc/profile.d/rbenv.sh", "",
"exec /bin/echo 'service1:pre' >>/srv/service/service1-dir/log/service1.log && exec /bin/echo 'service1' >>/srv/service/service1-dir/log/service1.log && exec /bin/echo 'service1:post' >>/srv/service/service1-dir/log/service1.log",
"exec /bin/echo 'service1:pre' &>>/srv/service/service1-dir/log/service1.log && exec /bin/echo 'service1' &>>/srv/service/service1-dir/log/service1.log && exec /bin/echo 'service1:post' &>>/srv/service/service1-dir/log/service1.log",
""},
)

Expand Down Expand Up @@ -416,6 +412,7 @@ func createTestApp(helperDir, targetDir string) *procfile.Application {
WorkingDir: "/srv/service/service1-dir",
LogPath: "log/service1.log",
KillTimeout: 10,
KillSignal: "SIGQUIT",
Count: 2,
RespawnInterval: 25,
RespawnCount: 15,
Expand All @@ -430,6 +427,7 @@ func createTestApp(helperDir, targetDir string) *procfile.Application {
Application: app,
Options: &procfile.ServiceOptions{
WorkingDir: "/srv/service/working-dir",
ReloadSignal: "SIGUSR2",
IsRespawnEnabled: true,
LimitFile: 4096,
LimitProc: 4096,
Expand Down
2 changes: 2 additions & 0 deletions export/systemd.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ PartOf={{.Application.Name}}.service
[Service]
Type=simple
{{ if .Service.Options.IsKillSignalSet }}KillSignal={{.Service.Options.KillSignal}}{{ end }}
TimeoutStopSec={{.Service.Options.KillTimeout}}
{{ if .Service.Options.IsRespawnEnabled }}Restart=on-failure{{ end }}
{{ if .Service.Options.IsRespawnLimitSet }}StartLimitInterval={{.Service.Options.RespawnInterval}}{{ end }}
Expand All @@ -86,6 +87,7 @@ Group={{.Application.Group}}
WorkingDirectory={{.Service.Options.WorkingDir}}
{{ if .Service.Options.IsEnvSet }}Environment={{.Service.Options.EnvString}}{{ end }}
ExecStart=/bin/bash {{.Service.HelperPath}} &>>/var/log/{{.Application.Name}}/{{.Service.Name}}.log
{{ if .Service.Options.IsReloadSignalSet }}ExecReload=/bin/kill -{{.Service.Options.ReloadSignal}} $MAINPID{{ end }}
`

// ////////////////////////////////////////////////////////////////////////////////// //
Expand Down
2 changes: 2 additions & 0 deletions export/upstart.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ stop on {{.StopLevel}}
{{ if .Service.Options.IsRespawnLimitSet }}respawn limit {{.Service.Options.RespawnCount}} {{.Service.Options.RespawnInterval}}{{ end }}
kill timeout {{.Service.Options.KillTimeout}}
{{ if .Service.Options.IsKillSignalSet }}kill signal {{.Service.Options.KillSignal}}{{ end }}
{{ if .Service.Options.IsReloadSignalSet }}reload signal {{.Service.Options.ReloadSignal}}{{ end }}
{{ if .Service.Options.IsFileLimitSet }}limit nofile {{.Service.Options.LimitFile}} {{.Service.Options.LimitFile}}{{ end }}
{{ if .Service.Options.IsProcLimitSet }}limit nproc {{.Service.Options.LimitProc}} {{.Service.Options.LimitProc}}{{ end }}
Expand Down
67 changes: 65 additions & 2 deletions procfile/procfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type ServiceOptions struct {
WorkingDir string // Working directory
LogPath string // Path to log file
KillTimeout int // Kill timeout in seconds
KillSignal string // Kill signal name
ReloadSignal string // Reload signal name
Count int // Exec count
RespawnInterval int // Respawn interval in seconds
RespawnCount int // Respawn count
Expand Down Expand Up @@ -186,7 +188,7 @@ func (s *Service) GetCommandExecWithEnv(command string) string {
}

if s.Options.IsCustomLogEnabled() {
result += " >>" + s.Options.FullLogPath()
result += " &>>" + s.Options.FullLogPath()
}

return result
Expand All @@ -206,7 +208,7 @@ func (s *Service) GetCommandExec(command string) string {
}

if s.Options.IsCustomLogEnabled() {
result += " >>" + s.Options.FullLogPath()
result += " &>>" + s.Options.FullLogPath()
}

return result
Expand Down Expand Up @@ -237,6 +239,16 @@ func (so *ServiceOptions) IsProcLimitSet() bool {
return so.LimitProc != 0
}

// IsKillSignalSet return true if custom kill signal set
func (so *ServiceOptions) IsKillSignalSet() bool {
return so.KillSignal != ""
}

// IsReloadSignalSet return true if custom reload signal set
func (so *ServiceOptions) IsReloadSignalSet() bool {
return so.ReloadSignal != ""
}

// EnvString return environment variables as string
func (so *ServiceOptions) EnvString() string {
if len(so.Env) == 0 {
Expand Down Expand Up @@ -265,6 +277,57 @@ func (so *ServiceOptions) FullLogPath() string {

// ////////////////////////////////////////////////////////////////////////////////// //

// parseCommand parse shell command and extract command body, output redirection
// and environment variables
func parseCommand(command string) (string, string, map[string]string) {
var (
env map[string]string
cmd []string
log string

isEnv bool
isLog bool
)

cmdSlice := strings.Fields(command)

for _, cmdPart := range cmdSlice {
if strings.TrimSpace(cmdPart) == "" {
continue
}

if strings.HasPrefix(cmdPart, "env") {
env = make(map[string]string)
isEnv = true
continue
}

if isEnv {
if strings.Contains(cmdPart, "=") {
envSlice := strings.Split(cmdPart, "=")
env[envSlice[0]] = envSlice[1]
continue
} else {
isEnv = false
}
}

if strings.Contains(cmdPart, ">>") {
isLog = true
continue
}

if isLog {
log = cmdPart
break
}

cmd = append(cmd, cmdPart)
}

return strings.Join(cmd, " "), log, env
}

// determineProcVersion process procfile data and return procfile version
func determineProcVersion(data []byte) int {
if regexp.MustCompile(REGEXP_V2_VERSION).Match(data) {
Expand Down
5 changes: 4 additions & 1 deletion procfile/procfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func (s *ProcfileSuite) TestProcV2Parsing(c *C) {
c.Assert(service.Cmd, Equals, "/usr/bin/tail -F /var/log/messages")
c.Assert(service.Options, NotNil)
c.Assert(service.Options.WorkingDir, Equals, "/var/...")
c.Assert(service.Options.IsCustomLogEnabled(), Equals, false)
c.Assert(service.Options.LogPath, Equals, "log/my_tail_cmd.log")
c.Assert(service.Options.IsCustomLogEnabled(), Equals, true)
c.Assert(service.Options.RespawnCount, Equals, 5)
c.Assert(service.Options.RespawnInterval, Equals, 10)
c.Assert(service.Options.IsRespawnEnabled, Equals, true)
Expand All @@ -96,6 +97,8 @@ func (s *ProcfileSuite) TestProcV2Parsing(c *C) {
c.Assert(service.Options.WorkingDir, Equals, "/srv/projects/my_website/current")
c.Assert(service.Options.IsCustomLogEnabled(), Equals, false)
c.Assert(service.Options.KillTimeout, Equals, 60)
c.Assert(service.Options.KillSignal, Equals, "SIGQUIT")
c.Assert(service.Options.ReloadSignal, Equals, "SIGUSR2")
c.Assert(service.Options.RespawnCount, Equals, 7)
c.Assert(service.Options.RespawnInterval, Equals, 22)
c.Assert(service.Options.IsRespawnEnabled, Equals, false)
Expand Down
62 changes: 6 additions & 56 deletions procfile/procfile_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ func parseV1Command(name, command string) *Service {

switch len(cmdSlice) {
case 3:
pre, _, _ = extractV1Data(cmdSlice[0])
cmd, log, env = extractV1Data(cmdSlice[1])
post, _, _ = extractV1Data(cmdSlice[2])
pre, _, _ = parseCommand(cmdSlice[0])
cmd, log, env = parseCommand(cmdSlice[1])
post, _, _ = parseCommand(cmdSlice[2])
case 2:
pre, _, _ = extractV1Data(cmdSlice[0])
cmd, log, env = extractV1Data(cmdSlice[1])
pre, _, _ = parseCommand(cmdSlice[0])
cmd, log, env = parseCommand(cmdSlice[1])
default:
cmd, log, env = extractV1Data(cmdSlice[0])
cmd, log, env = parseCommand(cmdSlice[0])
}

service.Cmd = cmd
Expand All @@ -132,56 +132,6 @@ func parseV1Command(name, command string) *Service {
return service
}

// extractV1Data extract data from command
func extractV1Data(command string) (string, string, map[string]string) {
var (
env map[string]string
cmd []string
log string

isEnv bool
isLog bool
)

cmdSlice := strings.Fields(command)

for _, cmdPart := range cmdSlice {
if strings.TrimSpace(cmdPart) == "" {
continue
}

if strings.HasPrefix(cmdPart, "env") {
env = make(map[string]string)
isEnv = true
continue
}

if isEnv {
if strings.Contains(cmdPart, "=") {
envSlice := strings.Split(cmdPart, "=")
env[envSlice[0]] = envSlice[1]
continue
} else {
isEnv = false
}
}

if strings.Contains(cmdPart, ">>") {
isLog = true
continue
}

if isLog {
log = cmdPart
break
}

cmd = append(cmd, cmdPart)
}

return strings.Join(cmd, " "), log, env
}

// splitV1Cmd split command and format command
func splitV1Command(cmd string) []string {
var result []string
Expand Down
Loading

0 comments on commit e45c3d9

Please sign in to comment.