Skip to content

Commit 76c212c

Browse files
authoredJul 30, 2020
Merge pull request #59 from funbox/develop
Version 0.23.0
2 parents 3e9c055 + 29e5bde commit 76c212c

17 files changed

+362
-285
lines changed
 

‎.travis.yml

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
dist: xenial
2-
31
language: go
42

53
go:
6-
- 1.10.x
7-
- 1.11.x
8-
- 1.12.x
4+
- 1.13.x
5+
- 1.14.x
96
- tip
107

118
os:

‎Makefile

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
################################################################################
22

3-
# This Makefile generated by GoMakeGen 1.1.2 using next command:
3+
# This Makefile generated by GoMakeGen 1.3.1 using next command:
44
# gomakegen .
55
#
66
# More info: https://kaos.sh/gomakegen
77

88
################################################################################
99

1010
.DEFAULT_GOAL := help
11-
.PHONY = fmt all clean git-config deps deps-test test gen-fuzz help
11+
.PHONY = fmt vet all clean git-config deps deps-test test gen-fuzz help
1212

1313
################################################################################
1414

@@ -27,12 +27,12 @@ git-config: ## Configure git redirects for stable import path services
2727
git config --global http.https://pkg.re.followRedirects true
2828

2929
deps: git-config ## Download dependencies
30-
go get -d -v pkg.re/essentialkaos/ek.v10
31-
go get -d -v pkg.re/essentialkaos/go-simpleyaml.v1
30+
go get -d -v pkg.re/essentialkaos/ek.v12
31+
go get -d -v pkg.re/essentialkaos/go-simpleyaml.v2
3232

3333
deps-test: git-config ## Download dependencies for tests
3434
go get -d -v pkg.re/check.v1
35-
go get -d -v pkg.re/essentialkaos/ek.v10
35+
go get -d -v pkg.re/essentialkaos/ek.v12
3636

3737
test: ## Run tests
3838
go test -covermode=count ./export ./procfile
@@ -44,6 +44,9 @@ gen-fuzz: ## Generate archives for fuzz testing
4444
fmt: ## Format source code with gofmt
4545
find . -name "*.go" -exec gofmt -s -w {} \;
4646

47+
vet: ## Runs go vet over sources
48+
go vet -composites=false -printfuncs=LPrintf,TLPrintf,TPrintf,log.Debug,log.Info,log.Warn,log.Error,log.Critical,log.Print ./...
49+
4750
clean: ## Remove generated files
4851
rm -f init-exporter
4952

@@ -52,6 +55,6 @@ help: ## Show this info
5255
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
5356
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[33m%-15s\033[0m %s\n", $$1, $$2}'
5457
@echo -e ''
55-
@echo -e '\033[90mGenerated by GoMakeGen 1.1.2\033[0m\n'
58+
@echo -e '\033[90mGenerated by GoMakeGen 1.3.1\033[0m\n'
5659

5760
################################################################################

‎README.md

+5-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Before the initial install allows git to use redirects for [pkg.re](https://gith
2323
git config --global http.https://pkg.re.followRedirects true
2424
```
2525

26-
To build the init-exporter from scratch, make sure you have a working Go 1.10+ workspace ([instructions](https://golang.org/doc/install)), then:
26+
To build the init-exporter from scratch, make sure you have a working Go 1.13+ workspace ([instructions](https://golang.org/doc/install)), then:
2727

2828
```bash
2929
go get -d github.com/funbox/init-exporter
@@ -33,18 +33,11 @@ make all
3333
[sudo] make install
3434
```
3535

36-
#### From ESSENTIAL KAOS Public repo for RHEL6/CentOS6
36+
#### From [ESSENTIAL KAOS Public Repository](https://yum.kaos.st)
3737

38-
```
39-
[sudo] yum install -y https://yum.kaos.st/kaos-repo-latest.el6.noarch.rpm
40-
[sudo] yum install init-exporter
41-
```
42-
43-
#### From ESSENTIAL KAOS Public repo for RHEL7/CentOS7
44-
45-
```
46-
[sudo] yum install -y https://yum.kaos.st/kaos-repo-latest.el7.noarch.rpm
47-
[sudo] yum install init-exporter
38+
```bash
39+
sudo yum install -y https://yum.kaos.st/get/$(uname -r).rpm
40+
sudo yum install init-exporter
4841
```
4942

5043
### Configuration

‎cli/cli.go

+41-70
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package cli
44

55
// ////////////////////////////////////////////////////////////////////////////////// //
66
// //
7-
// Copyright (c) 2006-2019 FB GROUP LLC //
7+
// Copyright (c) 2006-2020 FB GROUP LLC //
88
// //
99
// ////////////////////////////////////////////////////////////////////////////////// //
1010

@@ -13,15 +13,19 @@ import (
1313
"os"
1414
"runtime"
1515

16-
"pkg.re/essentialkaos/ek.v10/env"
17-
"pkg.re/essentialkaos/ek.v10/fmtc"
18-
"pkg.re/essentialkaos/ek.v10/fsutil"
19-
"pkg.re/essentialkaos/ek.v10/knf"
20-
"pkg.re/essentialkaos/ek.v10/log"
21-
"pkg.re/essentialkaos/ek.v10/options"
22-
"pkg.re/essentialkaos/ek.v10/system"
23-
"pkg.re/essentialkaos/ek.v10/usage"
24-
"pkg.re/essentialkaos/ek.v10/usage/update"
16+
"pkg.re/essentialkaos/ek.v12/env"
17+
"pkg.re/essentialkaos/ek.v12/fmtc"
18+
"pkg.re/essentialkaos/ek.v12/fsutil"
19+
"pkg.re/essentialkaos/ek.v12/knf"
20+
"pkg.re/essentialkaos/ek.v12/log"
21+
"pkg.re/essentialkaos/ek.v12/options"
22+
"pkg.re/essentialkaos/ek.v12/system"
23+
"pkg.re/essentialkaos/ek.v12/usage"
24+
"pkg.re/essentialkaos/ek.v12/usage/update"
25+
26+
knfv "pkg.re/essentialkaos/ek.v12/knf/validators"
27+
knff "pkg.re/essentialkaos/ek.v12/knf/validators/fs"
28+
knfs "pkg.re/essentialkaos/ek.v12/knf/validators/system"
2529

2630
"github.com/funbox/init-exporter/export"
2731
"github.com/funbox/init-exporter/procfile"
@@ -32,7 +36,7 @@ import (
3236
// App props
3337
const (
3438
APP = "init-exporter"
35-
VER = "0.22.0"
39+
VER = "0.23.0"
3640
DESC = "Utility for exporting services described by Procfile to init system"
3741
)
3842

@@ -209,70 +213,37 @@ func loadConfig() {
209213

210214
// validateConfig validate config values
211215
func validateConfig() {
212-
var permsChecker = func(config *knf.Config, prop string, value interface{}) error {
213-
if !fsutil.CheckPerms(value.(string), config.GetS(prop)) {
214-
switch value.(string) {
215-
case "DRX":
216-
return fmt.Errorf("Property %s must be path to readable directory", prop)
217-
case "DWX":
218-
return fmt.Errorf("Property %s must be path to writable directory", prop)
219-
case "DRWX":
220-
return fmt.Errorf("Property %s must be path to writable/readable directory", prop)
221-
case "FR":
222-
return fmt.Errorf("Property %s must be path to readable file", prop)
223-
}
224-
}
225-
226-
return nil
227-
}
228-
229-
var userChecker = func(config *knf.Config, prop string, value interface{}) error {
230-
if !system.IsUserExist(knf.GetS(prop)) {
231-
return fmt.Errorf("Property %s contains user which not exist on this system", prop)
232-
}
233-
234-
return nil
235-
}
236-
237-
var groupChecker = func(config *knf.Config, prop string, value interface{}) error {
238-
if !system.IsGroupExist(knf.GetS(prop)) {
239-
return fmt.Errorf("Property %s contains group which not exist on this system", prop)
240-
}
241-
242-
return nil
243-
}
244-
245216
validators := []*knf.Validator{
246-
{MAIN_RUN_USER, knf.Empty, nil},
247-
{MAIN_RUN_GROUP, knf.Empty, nil},
248-
{PATHS_WORKING_DIR, knf.Empty, nil},
249-
{PATHS_HELPER_DIR, knf.Empty, nil},
250-
{PATHS_SYSTEMD_DIR, knf.Empty, nil},
251-
{PATHS_UPSTART_DIR, knf.Empty, nil},
252-
{DEFAULTS_NPROC, knf.Empty, nil},
253-
{DEFAULTS_NOFILE, knf.Empty, nil},
254-
{DEFAULTS_RESPAWN_COUNT, knf.Empty, nil},
255-
{DEFAULTS_RESPAWN_INTERVAL, knf.Empty, nil},
256-
{DEFAULTS_KILL_TIMEOUT, knf.Empty, nil},
257-
258-
{DEFAULTS_NPROC, knf.Less, 0},
259-
{DEFAULTS_NOFILE, knf.Less, 0},
260-
{DEFAULTS_RESPAWN_COUNT, knf.Less, 0},
261-
{DEFAULTS_RESPAWN_INTERVAL, knf.Less, 0},
262-
{DEFAULTS_KILL_TIMEOUT, knf.Less, 0},
263-
264-
{MAIN_RUN_USER, userChecker, nil},
265-
{MAIN_RUN_GROUP, groupChecker, nil},
266-
267-
{PATHS_WORKING_DIR, permsChecker, "DRWX"},
268-
{PATHS_HELPER_DIR, permsChecker, "DRWX"},
217+
{MAIN_RUN_USER, knfv.Empty, nil},
218+
{MAIN_RUN_GROUP, knfv.Empty, nil},
219+
{PATHS_WORKING_DIR, knfv.Empty, nil},
220+
{PATHS_HELPER_DIR, knfv.Empty, nil},
221+
{PATHS_SYSTEMD_DIR, knfv.Empty, nil},
222+
{PATHS_UPSTART_DIR, knfv.Empty, nil},
223+
{DEFAULTS_NPROC, knfv.Empty, nil},
224+
{DEFAULTS_NOFILE, knfv.Empty, nil},
225+
{DEFAULTS_RESPAWN_COUNT, knfv.Empty, nil},
226+
{DEFAULTS_RESPAWN_INTERVAL, knfv.Empty, nil},
227+
{DEFAULTS_KILL_TIMEOUT, knfv.Empty, nil},
228+
229+
{DEFAULTS_NPROC, knfv.Less, 0},
230+
{DEFAULTS_NOFILE, knfv.Less, 0},
231+
{DEFAULTS_RESPAWN_COUNT, knfv.Less, 0},
232+
{DEFAULTS_RESPAWN_INTERVAL, knfv.Less, 0},
233+
{DEFAULTS_KILL_TIMEOUT, knfv.Less, 0},
234+
235+
{MAIN_RUN_USER, knfs.User, nil},
236+
{MAIN_RUN_GROUP, knfs.Group, nil},
237+
238+
{PATHS_WORKING_DIR, knff.Perms, "DRWX"},
239+
{PATHS_HELPER_DIR, knff.Perms, "DRWX"},
269240
}
270241

271242
if knf.GetB(LOG_ENABLED, true) {
272243
validators = append(validators,
273-
&knf.Validator{LOG_DIR, knf.Empty, nil},
274-
&knf.Validator{LOG_FILE, knf.Empty, nil},
275-
&knf.Validator{LOG_DIR, permsChecker, "DWX"},
244+
&knf.Validator{LOG_DIR, knfv.Empty, nil},
245+
&knf.Validator{LOG_FILE, knfv.Empty, nil},
246+
&knf.Validator{LOG_DIR, knff.Perms, "DWX"},
276247
)
277248
}
278249

‎common/init-exporter.spec

+11-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242

4343
Summary: Utility for exporting services described by Procfile to init system
4444
Name: init-exporter
45-
Version: 0.22.0
45+
Version: 0.23.0
4646
Release: 0%{?dist}
4747
Group: Development/Tools
4848
License: MIT
@@ -52,7 +52,7 @@ Source0: %{name}-%{version}.tar.gz
5252

5353
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
5454

55-
BuildRequires: golang >= 1.12
55+
BuildRequires: golang >= 1.14
5656

5757
Provides: upstart-exporter = %{version}-%{release}
5858
Provides: systemd-exporter = %{version}-%{release}
@@ -111,7 +111,15 @@ rm -rf %{buildroot}
111111
################################################################################
112112

113113
%changelog
114-
* Fri Jul 12 2019 Anton Novojilov <andy@essentialkaos.com> - 0.22.0-0
114+
* Fri Jan 24 2020 Anton Novojilov <andyone@fun-box.ru> - 0.23.0-0
115+
- Migrated to ek.v12
116+
- Migrated to go-simpleyaml.v12
117+
- Added support of required dependencies definition
118+
- Added option 'strong_dependencies' for strong dependencies configuration (for
119+
using 'Requires' instead of 'Wants' for systemd units)
120+
- Added option 'resources:cpu_affinity' for CPU affinity configuration
121+
122+
* Fri Jul 12 2019 Anton Novojilov <andyone@fun-box.ru> - 0.22.0-0
115123
- Added 'start_on_device' option for v2 procfile format
116124
- Dropped 'reload_signal' support for Upstart ≤ 1.10.0
117125
- Fixed 'reload_signal' support for Systemd

‎export/export_test.go

+95-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package export
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -16,9 +16,9 @@ import (
1616

1717
"github.com/funbox/init-exporter/procfile"
1818

19-
"pkg.re/essentialkaos/ek.v10/fsutil"
20-
"pkg.re/essentialkaos/ek.v10/log"
21-
"pkg.re/essentialkaos/ek.v10/version"
19+
"pkg.re/essentialkaos/ek.v12/fsutil"
20+
"pkg.re/essentialkaos/ek.v12/log"
21+
"pkg.re/essentialkaos/ek.v12/version"
2222

2323
. "pkg.re/check.v1"
2424
)
@@ -282,6 +282,42 @@ func (s *ExportSuite) TestUpstartExportWithNet(c *C) {
282282
)
283283
}
284284

285+
func (s *ExportSuite) TestUpstartExportWithDependencies(c *C) {
286+
helperDir := c.MkDir()
287+
targetDir := c.MkDir()
288+
289+
config := &Config{
290+
HelperDir: helperDir,
291+
TargetDir: targetDir,
292+
DisableAutoStart: true,
293+
}
294+
295+
exporter := NewExporter(config, NewUpstart())
296+
297+
c.Assert(exporter, NotNil)
298+
299+
app := createTestApp(targetDir, helperDir)
300+
301+
app.Depends = []string{"postgresql-11", "redis"}
302+
303+
err := exporter.Install(app)
304+
c.Assert(err, IsNil)
305+
306+
appUnitData, err := ioutil.ReadFile(targetDir + "/test_application.conf")
307+
308+
c.Assert(err, IsNil)
309+
c.Assert(appUnitData, NotNil)
310+
311+
appUnit := strings.Split(string(appUnitData), "\n")
312+
313+
c.Assert(appUnit[2:4], DeepEquals,
314+
[]string{
315+
"start on started postgresql-11 and started redis",
316+
"stop on stopped postgresql-11 and stopped redis",
317+
},
318+
)
319+
}
320+
285321
func (s *ExportSuite) TestUpstartExportWithOldUpstart(c *C) {
286322
upstartVersionCache, _ = version.Parse("0.6.5")
287323

@@ -518,6 +554,7 @@ func (s *ExportSuite) TestSystemdExport(c *C) {
518554
"CPUWeight=50",
519555
"StartupCPUWeight=50",
520556
"CPUQuota=35%",
557+
"CPUAffinity=4-8",
521558
"MemoryLow=1G",
522559
"MemoryHigh=4G",
523560
"MemoryMax=8G",
@@ -605,12 +642,53 @@ func (s *ExportSuite) TestSystemdExportWithNet(c *C) {
605642
"[Unit]",
606643
"",
607644
"Description=Unit for test_application application",
608-
"After=sys-subsystem-net-devices-bond0.device",
645+
"After=multi-user.target sys-subsystem-net-devices-bond0.device",
609646
"Wants=test_application-serviceA1.service test_application-serviceA2.service test_application-serviceB.service",
610647
},
611648
)
612649
}
613650

651+
func (s *ExportSuite) TestSystemdExportWithDependencies(c *C) {
652+
helperDir := c.MkDir()
653+
targetDir := c.MkDir()
654+
655+
config := &Config{
656+
HelperDir: helperDir,
657+
TargetDir: targetDir,
658+
DisableAutoStart: true,
659+
DisableReload: true,
660+
}
661+
662+
exporter := NewExporter(config, NewSystemd())
663+
664+
c.Assert(exporter, NotNil)
665+
666+
app := createTestApp(targetDir, helperDir)
667+
668+
app.Depends = []string{"postgresql-11", "redis"}
669+
670+
err := exporter.Install(app)
671+
672+
c.Assert(err, IsNil)
673+
674+
appUnitData, err := ioutil.ReadFile(targetDir + "/test_application.service")
675+
676+
c.Assert(err, IsNil)
677+
c.Assert(appUnitData, NotNil)
678+
679+
appUnit := strings.Split(string(appUnitData), "\n")
680+
681+
c.Assert(appUnit[2:7], DeepEquals,
682+
[]string{
683+
"[Unit]",
684+
"",
685+
"Description=Unit for test_application application",
686+
"After=multi-user.target postgresql-11.service redis.service",
687+
"Wants=postgresql-11.service redis.service test_application-serviceA1.service test_application-serviceA2.service test_application-serviceB.service",
688+
},
689+
)
690+
}
691+
614692
func (s *ExportSuite) TestUpstartVersionParser(c *C) {
615693
data := `init (upstart 0.6.5)
616694
Copyright (C) 2010 Canonical Ltd.
@@ -633,7 +711,7 @@ func (s *ExportSuite) TestWantsClauseGeneration(c *C) {
633711
}
634712

635713
p := NewSystemd()
636-
wants := p.renderWantsClause(services)
714+
wants := p.renderWantsClause(services, nil, false)
637715

638716
c.Assert(strings.Count(wants, "\n"), Not(Equals), 1)
639717

@@ -642,6 +720,16 @@ func (s *ExportSuite) TestWantsClauseGeneration(c *C) {
642720
for _, clause := range wantsSlice {
643721
c.Assert(strings.HasPrefix(clause, "Wants="), Equals, true)
644722
}
723+
724+
wants = p.renderWantsClause(services, nil, true)
725+
726+
c.Assert(strings.Count(wants, "\n"), Not(Equals), 1)
727+
728+
wantsSlice = strings.Split(wants, "\n")
729+
730+
for _, clause := range wantsSlice {
731+
c.Assert(strings.HasPrefix(clause, "Requires="), Equals, true)
732+
}
645733
}
646734

647735
// ////////////////////////////////////////////////////////////////////////////////// //
@@ -695,6 +783,7 @@ func createTestApp(helperDir, targetDir string) *procfile.Application {
695783
CPUWeight: 50,
696784
StartupCPUWeight: 15,
697785
CPUQuota: 35,
786+
CPUAffinity: "4-8",
698787
MemoryLow: "1G",
699788
MemoryHigh: "4G",
700789
MemoryMax: "8G",

‎export/exporter.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package export
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -12,9 +12,9 @@ import (
1212
"os"
1313
"strconv"
1414

15-
"pkg.re/essentialkaos/ek.v10/fsutil"
16-
"pkg.re/essentialkaos/ek.v10/log"
17-
"pkg.re/essentialkaos/ek.v10/path"
15+
"pkg.re/essentialkaos/ek.v12/fsutil"
16+
"pkg.re/essentialkaos/ek.v12/log"
17+
"pkg.re/essentialkaos/ek.v12/path"
1818

1919
"github.com/funbox/init-exporter/procfile"
2020
)

‎export/provider.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package export
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -11,7 +11,7 @@ import (
1111
"fmt"
1212
"text/template"
1313

14-
"pkg.re/essentialkaos/ek.v10/log"
14+
"pkg.re/essentialkaos/ek.v12/log"
1515

1616
"github.com/funbox/init-exporter/procfile"
1717
)

‎export/systemd.go

+53-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package export
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -13,8 +13,8 @@ import (
1313
"strings"
1414
"time"
1515

16-
"pkg.re/essentialkaos/ek.v10/system/exec"
17-
"pkg.re/essentialkaos/ek.v10/timeutil"
16+
"pkg.re/essentialkaos/ek.v12/system/exec"
17+
"pkg.re/essentialkaos/ek.v12/timeutil"
1818

1919
"github.com/funbox/init-exporter/procfile"
2020
)
@@ -151,6 +151,10 @@ func (sd *systemdServiceData) ResourcesAsString() string {
151151
result += fmt.Sprintf("CPUQuota=%d%%\n", resources.CPUQuota)
152152
}
153153

154+
if resources.CPUAffinity != "" {
155+
result += fmt.Sprintf("CPUAffinity=%s\n", resources.CPUAffinity)
156+
}
157+
154158
if resources.MemoryLow != "" {
155159
result += fmt.Sprintf("MemoryLow=%s\n", resources.MemoryLow)
156160
}
@@ -257,10 +261,10 @@ func (sp *SystemdProvider) RenderAppTemplate(app *procfile.Application) (string,
257261
data := &systemdAppData{
258262
Application: app,
259263
ReloadHelper: app.ReloadHelperPath,
260-
Wants: sp.renderWantsClause(sp.getServiceList(app)),
261-
After: sp.renderLevel(app.StartLevel, app.StartDevice),
262-
StartLevel: sp.renderLevel(app.StartLevel, ""),
263-
StopLevel: sp.renderLevel(app.StopLevel, ""),
264+
Wants: sp.renderWantsClause(sp.getServiceList(app), app.Depends, app.StrongDependencies),
265+
After: sp.renderAfterClause(app.StartLevel, app.StartDevice, app.Depends),
266+
StartLevel: sp.renderLevel(app.StartLevel),
267+
StopLevel: sp.renderLevel(app.StopLevel),
264268
ExportDate: timeutil.Format(time.Now(), "%Y/%m/%d %H:%M:%S"),
265269
}
266270

@@ -316,11 +320,7 @@ func (sd *systemdServiceData) GetMemlockLimit() string {
316320
// ////////////////////////////////////////////////////////////////////////////////// //
317321

318322
// renderLevel converts level number to systemd level name
319-
func (sp *SystemdProvider) renderLevel(level int, device string) string {
320-
if device != "" {
321-
return fmt.Sprintf("sys-subsystem-net-devices-%s.device", device)
322-
}
323-
323+
func (sp *SystemdProvider) renderLevel(level int) string {
324324
switch level {
325325
case 1:
326326
return "rescue.target"
@@ -334,24 +334,40 @@ func (sp *SystemdProvider) renderLevel(level int, device string) string {
334334
}
335335

336336
// renderWantsClause renders list of services in application for systemd config
337-
func (sp *SystemdProvider) renderWantsClause(services []string) string {
337+
func (sp *SystemdProvider) renderWantsClause(services []string, deps []string, strongDeps bool) string {
338338
var wants []string
339339
var buffer string
340340

341+
depOption := getDepOption(strongDeps)
342+
services = append(sp.depsToServiceList(deps), services...)
343+
341344
for _, service := range services {
342345
if len(buffer)+len(service) >= 1536 {
343-
wants = append(wants, "Wants="+strings.TrimSpace(buffer))
346+
wants = append(wants, depOption+strings.TrimSpace(buffer))
344347
buffer = ""
345348
}
346349

347350
buffer += service + " "
348351
}
349352

350-
wants = append(wants, "Wants="+strings.TrimSpace(buffer))
353+
wants = append(wants, depOption+strings.TrimSpace(buffer))
351354

352355
return strings.Join(wants, "\n")
353356
}
354357

358+
// renderAfterClause renders dependencies
359+
func (sp *SystemdProvider) renderAfterClause(level int, device string, deps []string) string {
360+
after := []string{sp.renderLevel(level)}
361+
362+
if device != "" {
363+
after = append(after, fmt.Sprintf("sys-subsystem-net-devices-%s.device", device))
364+
}
365+
366+
after = append(after, sp.depsToServiceList(deps)...)
367+
368+
return strings.Join(after, " ")
369+
}
370+
355371
// getServiceList return slice with all child services
356372
func (sp *SystemdProvider) getServiceList(app *procfile.Application) []string {
357373
var result []string
@@ -368,3 +384,25 @@ func (sp *SystemdProvider) getServiceList(app *procfile.Application) []string {
368384

369385
return result
370386
}
387+
388+
// depsToServiceList converts dependencies to services list
389+
func (sp *SystemdProvider) depsToServiceList(deps []string) []string {
390+
var result []string
391+
392+
for _, dep := range deps {
393+
result = append(result, dep+".service")
394+
}
395+
396+
return result
397+
}
398+
399+
// getDepOption returns option for dependencies requirement based on
400+
// application settings
401+
func getDepOption(strongDeps bool) string {
402+
switch strongDeps {
403+
case true:
404+
return "Requires="
405+
default:
406+
return "Wants="
407+
}
408+
}

‎export/upstart.go

+35-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package export
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -12,9 +12,9 @@ import (
1212
"strings"
1313
"time"
1414

15-
"pkg.re/essentialkaos/ek.v10/strutil"
16-
"pkg.re/essentialkaos/ek.v10/timeutil"
17-
"pkg.re/essentialkaos/ek.v10/version"
15+
"pkg.re/essentialkaos/ek.v12/strutil"
16+
"pkg.re/essentialkaos/ek.v12/timeutil"
17+
"pkg.re/essentialkaos/ek.v12/version"
1818

1919
"github.com/funbox/init-exporter/procfile"
2020
)
@@ -141,8 +141,8 @@ func (up *UpstartProvider) Reload() error {
141141
func (up *UpstartProvider) RenderAppTemplate(app *procfile.Application) (string, error) {
142142
data := &upstartAppData{
143143
Application: app,
144-
StartLevel: up.renderLevel(app.StartLevel, app.StartDevice),
145-
StopLevel: up.renderLevel(app.StopLevel, ""),
144+
StartLevel: up.renderStartLevel(app.StartLevel, app.StartDevice, app.Depends),
145+
StopLevel: up.renderStopLevel(app.StopLevel, app.Depends),
146146
ExportDate: timeutil.Format(time.Now(), "%Y/%m/%d %H:%M:%S"),
147147
}
148148

@@ -182,13 +182,38 @@ func (up *UpstartProvider) RenderReloadHelperTemplate(app *procfile.Application)
182182

183183
// ////////////////////////////////////////////////////////////////////////////////// //
184184

185-
// renderLevel converts level number to upstart level name
186-
func (up *UpstartProvider) renderLevel(level int, device string) string {
185+
// renderStartLevel converts level number to upstart start level name
186+
func (up *UpstartProvider) renderStartLevel(level int, device string, deps []string) string {
187+
if device == "" && len(deps) == 0 {
188+
return fmt.Sprintf("runlevel [%d]", level)
189+
}
190+
191+
var depsList []string
192+
187193
if device != "" {
188-
return fmt.Sprintf("net-device-up IFACE=%s", device)
194+
depsList = append(depsList, "net-device-up IFACE="+device)
195+
}
196+
197+
for _, dep := range deps {
198+
depsList = append(depsList, "started "+dep)
199+
}
200+
201+
return strings.Join(depsList, " and ")
202+
}
203+
204+
// renderStopLevel converts level number to upstart stop level name
205+
func (up *UpstartProvider) renderStopLevel(level int, deps []string) string {
206+
if len(deps) == 0 {
207+
return fmt.Sprintf("runlevel [%d]", level)
208+
}
209+
210+
var depsList []string
211+
212+
for _, dep := range deps {
213+
depsList = append(depsList, "stopped "+dep)
189214
}
190215

191-
return fmt.Sprintf("runlevel [%d]", level)
216+
return strings.Join(depsList, " and ")
192217
}
193218

194219
// ////////////////////////////////////////////////////////////////////////////////// //

‎init-exporter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package main
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

‎procfile/fuzz.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package procfile
44

55
// ////////////////////////////////////////////////////////////////////////////////// //
66
// //
7-
// Copyright (c) 2006-2019 FB GROUP LLC //
7+
// Copyright (c) 2006-2020 FB GROUP LLC //
88
// //
99
// ////////////////////////////////////////////////////////////////////////////////// //
1010

‎procfile/procfile.go

+53-27
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package procfile
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -13,22 +13,23 @@ import (
1313
"sort"
1414
"strings"
1515

16-
"pkg.re/essentialkaos/ek.v10/errutil"
17-
"pkg.re/essentialkaos/ek.v10/fsutil"
18-
"pkg.re/essentialkaos/ek.v10/log"
19-
"pkg.re/essentialkaos/ek.v10/path"
20-
"pkg.re/essentialkaos/ek.v10/sliceutil"
21-
"pkg.re/essentialkaos/ek.v10/strutil"
16+
"pkg.re/essentialkaos/ek.v12/errutil"
17+
"pkg.re/essentialkaos/ek.v12/fsutil"
18+
"pkg.re/essentialkaos/ek.v12/log"
19+
"pkg.re/essentialkaos/ek.v12/path"
20+
"pkg.re/essentialkaos/ek.v12/sliceutil"
21+
"pkg.re/essentialkaos/ek.v12/strutil"
2222
)
2323

2424
// ////////////////////////////////////////////////////////////////////////////////// //
2525

2626
const (
27-
REGEXP_V1_LINE = `^([A-z\d_]+):\s*(.+)`
28-
REGEXP_V2_VERSION = `(?m)^\s*version:\s*2\s*$`
29-
REGEXP_PATH_CHECK = `\A[A-Za-z0-9_\-./]+\z`
30-
REGEXP_NAME_CHECK = `\A[A-Za-z0-9_\-]+\z`
31-
REGEXP_NET_DEVICE_CHECK = `eth[0-9]|e[nm][0-9]|p[0-9][ps][0-9]|wlan|wl[0-9]|wlp[0-9]|bond[0-9]`
27+
REGEXP_V1_LINE = `^([A-z\d_]+):\s*(.+)`
28+
REGEXP_V2_VERSION = `(?m)^\s*version:\s*2\s*$`
29+
REGEXP_PATH_CHECK = `\A[A-Za-z0-9_\-./]+\z`
30+
REGEXP_NAME_CHECK = `\A[A-Za-z0-9_\-]+\z`
31+
REGEXP_NET_DEVICE_CHECK = `eth[0-9]|e[nm][0-9]|p[0-9][ps][0-9]|wlan|wl[0-9]|wlp[0-9]|bond[0-9]`
32+
REGEXP_CPU_AFFINITY_CHECK = `^[\d\-, ]+$`
3233
)
3334

3435
// ////////////////////////////////////////////////////////////////////////////////// //
@@ -80,6 +81,7 @@ type Resources struct {
8081
CPUWeight int
8182
StartupCPUWeight int
8283
CPUQuota int
84+
CPUAffinity string
8385
MemoryLow string
8486
MemoryHigh string
8587
MemoryMax string
@@ -97,16 +99,18 @@ type Resources struct {
9799
}
98100

99101
type Application struct {
100-
Name string // Name of application
101-
Services []*Service // List of services in application
102-
User string // Working user
103-
Group string // Working group
104-
StartLevel int // Start level
105-
StopLevel int // Stop level
106-
StartDevice string // Start on device activation
107-
WorkingDir string // Working directory
108-
ReloadHelperPath string // Path to reload helper (will be set by exporter)
109-
ProcVersion int // Proc version 1/2
102+
Name string // Name of application
103+
Services []*Service // List of services in application
104+
User string // Working user
105+
Group string // Working group
106+
StartLevel int // Start level
107+
StopLevel int // Stop level
108+
StartDevice string // Start on device activation
109+
Depends []string // Dependencies
110+
WorkingDir string // Working directory
111+
ReloadHelperPath string // Path to reload helper (will be set by exporter)
112+
ProcVersion int // Proc version 1/2
113+
StrongDependencies bool // Use strong dependencies
110114
}
111115

112116
// ////////////////////////////////////////////////////////////////////////////////// //
@@ -158,6 +162,7 @@ func (a *Application) Validate() []error {
158162

159163
errs.Add(checkRunLevel(a.StartLevel))
160164
errs.Add(checkRunLevel(a.StopLevel))
165+
errs.Add(checkDependencies(a.Depends))
161166

162167
if a.WorkingDir == "" {
163168
errs.Add(fmt.Errorf("Application working dir can't be empty"))
@@ -249,6 +254,10 @@ func (so *ServiceOptions) Validate() *errutil.Errors {
249254
errs.Add(fmt.Errorf("Property \"resources:cpu_weight\" must be greater or equal 0 and less or equal 10000"))
250255
}
251256

257+
if so.Resources.CPUAffinity != "" && !regexp.MustCompile(REGEXP_CPU_AFFINITY_CHECK).MatchString(so.Resources.CPUAffinity) {
258+
errs.Add(fmt.Errorf("Property \"resources:cpu_affinity\" contains misformatted value"))
259+
}
260+
252261
if so.Resources.StartupCPUWeight < 0 || so.Resources.StartupCPUWeight > 10000 {
253262
errs.Add(fmt.Errorf("Property \"resources:startup_cpu_weight\" must be greater or equal 0 and less or equal 10000"))
254263
}
@@ -564,7 +573,7 @@ func mergeStringMaps(dest, src map[string]string) {
564573
}
565574
}
566575

567-
// checkPath check path value and return error if value is insecure
576+
// checkPath checks path value and return error if value is insecure
568577
func checkPath(value string) error {
569578
if value == "" {
570579
return nil
@@ -581,7 +590,7 @@ func checkPath(value string) error {
581590
return nil
582591
}
583592

584-
// checkEnv check given env variable and return error if name or value is insecure
593+
// checkEnv checks given env variable and return error if name or value is insecure
585594
func checkEnv(name, value string) error {
586595
if name == "" {
587596
return nil
@@ -610,7 +619,7 @@ func checkEnv(name, value string) error {
610619
return nil
611620
}
612621

613-
// checkRunLevel check run level value and return error if value is insecure
622+
// checkRunLevel checks run level value and return error if value is insecure
614623
func checkRunLevel(value int) error {
615624
if value < 1 {
616625
return fmt.Errorf("Run level can't be less than 1")
@@ -623,15 +632,32 @@ func checkRunLevel(value int) error {
623632
return nil
624633
}
625634

626-
// addCrossLink add to all service structs pointer
635+
// checkDependencies checks dependencies
636+
func checkDependencies(deps []string) *errutil.Errors {
637+
if len(deps) == 0 {
638+
return nil
639+
}
640+
641+
errs := errutil.NewErrors()
642+
643+
for _, dep := range deps {
644+
if !regexp.MustCompile(REGEXP_NAME_CHECK).MatchString(dep) {
645+
errs.Add(fmt.Errorf("Dependency name %s is misformatted and can't be accepted", dep))
646+
}
647+
}
648+
649+
return nil
650+
}
651+
652+
// addCrossLink adds to all service structs pointer
627653
// to parent application struct
628654
func addCrossLink(app *Application) {
629655
for _, service := range app.Services {
630656
service.Application = app
631657
}
632658
}
633659

634-
// isUnquotedValue return true if given value is unquoted
660+
// isUnquotedValue returns true if given value is unquoted
635661
func isUnquotedValue(value string) bool {
636662
if !strings.Contains(value, "\"") && !strings.Contains(value, "'") {
637663
return true

‎procfile/procfile_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package procfile
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -86,6 +86,7 @@ func (s *ProcfileSuite) TestProcV2Parsing(c *C) {
8686
c.Assert(app.StartLevel, Equals, 2)
8787
c.Assert(app.StopLevel, Equals, 5)
8888
c.Assert(app.StartDevice, Equals, "bond0")
89+
c.Assert(app.Depends, DeepEquals, []string{"postgresql-11", "redis"})
8990

9091
errs := app.Validate()
9192

@@ -163,6 +164,7 @@ func (s *ProcfileSuite) TestProcV2Parsing(c *C) {
163164
c.Assert(service.Options.Resources.CPUWeight, Equals, 50)
164165
c.Assert(service.Options.Resources.StartupCPUWeight, Equals, 15)
165166
c.Assert(service.Options.Resources.CPUQuota, Equals, 40)
167+
c.Assert(service.Options.Resources.CPUAffinity, Equals, "1,3,5-7")
166168
c.Assert(service.Options.Resources.MemoryLow, Equals, "1G")
167169
c.Assert(service.Options.Resources.MemoryHigh, Equals, "4G")
168170
c.Assert(service.Options.Resources.MemoryMax, Equals, "8G")

‎procfile/procfile_v1.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package procfile
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

@@ -13,7 +13,7 @@ import (
1313
"regexp"
1414
"strings"
1515

16-
"pkg.re/essentialkaos/ek.v10/log"
16+
"pkg.re/essentialkaos/ek.v12/log"
1717
)
1818

1919
// ////////////////////////////////////////////////////////////////////////////////// //

‎procfile/procfile_v2.go

+42-120
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ package procfile
22

33
// ////////////////////////////////////////////////////////////////////////////////// //
44
// //
5-
// Copyright (c) 2006-2019 FB GROUP LLC //
5+
// Copyright (c) 2006-2020 FB GROUP LLC //
66
// //
77
// ////////////////////////////////////////////////////////////////////////////////// //
88

99
import (
1010
"fmt"
1111
"strings"
1212

13-
"pkg.re/essentialkaos/ek.v10/log"
13+
"pkg.re/essentialkaos/ek.v12/log"
14+
"pkg.re/essentialkaos/ek.v12/strutil"
1415

15-
"pkg.re/essentialkaos/go-simpleyaml.v1"
16+
"pkg.re/essentialkaos/go-simpleyaml.v2"
1617
)
1718

1819
// ////////////////////////////////////////////////////////////////////////////////// //
@@ -53,11 +54,7 @@ func parseV2Procfile(data []byte, config *Config) (*Application, error) {
5354
}
5455

5556
if yaml.IsExist("working_directory") {
56-
app.WorkingDir, err = yamlGetSafe(yaml, "working_directory")
57-
58-
if err != nil {
59-
return nil, fmt.Errorf("Can't parse working_directory value: %v", err)
60-
}
57+
app.WorkingDir = yamlGetSafe(yaml, "working_directory")
6158
}
6259

6360
if yaml.IsExist("start_on_runlevel") {
@@ -77,13 +74,22 @@ func parseV2Procfile(data []byte, config *Config) (*Application, error) {
7774
}
7875

7976
if yaml.IsExist("start_on_device") {
80-
app.StartDevice, err = yamlGetSafe(yaml, "start_on_device")
77+
app.StartDevice = yamlGetSafe(yaml, "start_on_device")
78+
}
79+
80+
if yaml.IsExist("strong_dependencies") {
81+
app.StrongDependencies, err = yaml.Get("strong_dependencies").Bool()
8182

8283
if err != nil {
83-
return nil, fmt.Errorf("Can't parse start_on_device value: %v", err)
84+
return nil, fmt.Errorf("Can't parse strong_dependencies value: %v", err)
8485
}
8586
}
8687

88+
if yaml.IsExist("depends") {
89+
deps := yamlGetSafe(yaml, "depends")
90+
app.Depends = strutil.Fields(deps)
91+
}
92+
8793
addCrossLink(app)
8894

8995
return app, nil
@@ -131,15 +137,9 @@ func parseV2Services(yaml *simpleyaml.Yaml, commands map[interface{}]interface{}
131137

132138
// parseV2Commands parse service commands
133139
func parseV2Commands(service *Service, yaml *simpleyaml.Yaml) error {
134-
var err error
135140
var cmd, log string
136141

137-
cmd, err = yamlGetSafe(yaml, "command")
138-
139-
if err != nil {
140-
return fmt.Errorf("Can't parse \"command\" value: %v", err)
141-
}
142-
142+
cmd = yamlGetSafe(yaml, "command")
143143
cmd, log, _ = parseCommand(cmd)
144144

145145
if log != "" {
@@ -149,19 +149,11 @@ func parseV2Commands(service *Service, yaml *simpleyaml.Yaml) error {
149149
service.Cmd = cmd
150150

151151
if yaml.IsExist("pre") {
152-
service.PreCmd, err = yamlGetSafe(yaml, "pre")
153-
154-
if err != nil {
155-
return fmt.Errorf("Can't parse \"pre\" value: %v", err)
156-
}
152+
service.PreCmd = yamlGetSafe(yaml, "pre")
157153
}
158154

159155
if yaml.IsExist("post") {
160-
service.PostCmd, err = yamlGetSafe(yaml, "post")
161-
162-
if err != nil {
163-
return fmt.Errorf("Can't parse \"post\" value: %v", err)
164-
}
156+
service.PostCmd = yamlGetSafe(yaml, "post")
165157
}
166158

167159
return nil
@@ -175,19 +167,11 @@ func parseV2Options(options *ServiceOptions, yaml *simpleyaml.Yaml) error {
175167
options.IsRespawnEnabled = true
176168

177169
if yaml.IsExist("working_directory") {
178-
options.WorkingDir, err = yamlGetSafe(yaml, "working_directory")
179-
180-
if err != nil {
181-
return formatPropError("working_directory", err)
182-
}
170+
options.WorkingDir = yamlGetSafe(yaml, "working_directory")
183171
}
184172

185173
if yaml.IsExist("log") {
186-
options.LogFile, err = yamlGetSafe(yaml, "log")
187-
188-
if err != nil {
189-
return formatPropError("log", err)
190-
}
174+
options.LogFile = yamlGetSafe(yaml, "log")
191175
}
192176

193177
if yaml.IsExist("kill_timeout") {
@@ -199,27 +183,15 @@ func parseV2Options(options *ServiceOptions, yaml *simpleyaml.Yaml) error {
199183
}
200184

201185
if yaml.IsExist("kill_signal") {
202-
options.KillSignal, err = yamlGetSafe(yaml, "kill_signal")
203-
204-
if err != nil {
205-
return formatPropError("kill_signal", err)
206-
}
186+
options.KillSignal = yamlGetSafe(yaml, "kill_signal")
207187
}
208188

209189
if yaml.IsExist("kill_mode") {
210-
options.KillMode, err = yamlGetSafe(yaml, "kill_mode")
211-
212-
if err != nil {
213-
return formatPropError("kill_mode", err)
214-
}
190+
options.KillMode = yamlGetSafe(yaml, "kill_mode")
215191
}
216192

217193
if yaml.IsExist("reload_signal") {
218-
options.ReloadSignal, err = yamlGetSafe(yaml, "reload_signal")
219-
220-
if err != nil {
221-
return formatPropError("reload_signal", err)
222-
}
194+
options.ReloadSignal = yamlGetSafe(yaml, "reload_signal")
223195
}
224196

225197
if yaml.IsExist("count") {
@@ -241,11 +213,7 @@ func parseV2Options(options *ServiceOptions, yaml *simpleyaml.Yaml) error {
241213
}
242214

243215
if yaml.IsExist("env_file") {
244-
options.EnvFile, err = yamlGetSafe(yaml, "env_file")
245-
246-
if err != nil {
247-
return formatPropError("env_file", err)
248-
}
216+
options.EnvFile = yamlGetSafe(yaml, "env_file")
249217
}
250218

251219
if yaml.IsPathExist("respawn", "count") || yaml.IsPathExist("respawn", "interval") {
@@ -340,36 +308,24 @@ func parseV2Resources(yaml *simpleyaml.Yaml) (*Resources, error) {
340308
}
341309
}
342310

343-
if yaml.IsExist("memory_low") {
344-
resources.MemoryLow, err = yamlGetSafe(yaml, "memory_low")
311+
if yaml.IsExist("cpu_affinity") {
312+
resources.CPUAffinity = yamlGetSafe(yaml, "cpu_affinity")
313+
}
345314

346-
if err != nil {
347-
return nil, formatPropError("resources:memory_low", err)
348-
}
315+
if yaml.IsExist("memory_low") {
316+
resources.MemoryLow = yamlGetSafe(yaml, "memory_low")
349317
}
350318

351319
if yaml.IsExist("memory_high") {
352-
resources.MemoryHigh, err = yamlGetSafe(yaml, "memory_high")
353-
354-
if err != nil {
355-
return nil, formatPropError("resources:memory_high", err)
356-
}
320+
resources.MemoryHigh = yamlGetSafe(yaml, "memory_high")
357321
}
358322

359323
if yaml.IsExist("memory_max") {
360-
resources.MemoryMax, err = yamlGetSafe(yaml, "memory_max")
361-
362-
if err != nil {
363-
return nil, formatPropError("resources:memory_max", err)
364-
}
324+
resources.MemoryMax = yamlGetSafe(yaml, "memory_max")
365325
}
366326

367327
if yaml.IsExist("memory_swap_max") {
368-
resources.MemorySwapMax, err = yamlGetSafe(yaml, "memory_swap_max")
369-
370-
if err != nil {
371-
return nil, formatPropError("resources:memory_swap_max", err)
372-
}
328+
resources.MemorySwapMax = yamlGetSafe(yaml, "memory_swap_max")
373329
}
374330

375331
if yaml.IsExist("task_max") {
@@ -397,73 +353,39 @@ func parseV2Resources(yaml *simpleyaml.Yaml) (*Resources, error) {
397353
}
398354

399355
if yaml.IsExist("io_device_weight") {
400-
resources.IODeviceWeight, err = yamlGetSafe(yaml, "io_device_weight")
401-
402-
if err != nil {
403-
return nil, formatPropError("resources:io_device_weight", err)
404-
}
356+
resources.IODeviceWeight = yamlGetSafe(yaml, "io_device_weight")
405357
}
406358

407359
if yaml.IsExist("io_read_bandwidth_max") {
408-
resources.IOReadBandwidthMax, err = yamlGetSafe(yaml, "io_read_bandwidth_max")
409-
410-
if err != nil {
411-
return nil, formatPropError("resources:io_read_bandwidth_max", err)
412-
}
360+
resources.IOReadBandwidthMax = yamlGetSafe(yaml, "io_read_bandwidth_max")
413361
}
414362

415363
if yaml.IsExist("io_write_bandwidth_max") {
416-
resources.IOWriteBandwidthMax, err = yamlGetSafe(yaml, "io_write_bandwidth_max")
417-
418-
if err != nil {
419-
return nil, formatPropError("resources:io_write_bandwidth_max", err)
420-
}
364+
resources.IOWriteBandwidthMax = yamlGetSafe(yaml, "io_write_bandwidth_max")
421365
}
422366

423367
if yaml.IsExist("io_read_iops_max") {
424-
resources.IOReadIOPSMax, err = yamlGetSafe(yaml, "io_read_iops_max")
425-
426-
if err != nil {
427-
return nil, formatPropError("resources:io_read_iops_max", err)
428-
}
368+
resources.IOReadIOPSMax = yamlGetSafe(yaml, "io_read_iops_max")
429369
}
430370

431371
if yaml.IsExist("io_write_iops_max") {
432-
resources.IOWriteIOPSMax, err = yamlGetSafe(yaml, "io_write_iops_max")
433-
434-
if err != nil {
435-
return nil, formatPropError("resources:io_write_iops_max", err)
436-
}
372+
resources.IOWriteIOPSMax = yamlGetSafe(yaml, "io_write_iops_max")
437373
}
438374

439375
if yaml.IsExist("ip_address_allow") {
440-
resources.IPAddressAllow, err = yamlGetSafe(yaml, "ip_address_allow")
441-
442-
if err != nil {
443-
return nil, formatPropError("resources:ip_address_allow", err)
444-
}
376+
resources.IPAddressAllow = yamlGetSafe(yaml, "ip_address_allow")
445377
}
446378

447379
if yaml.IsExist("ip_address_deny") {
448-
resources.IPAddressDeny, err = yamlGetSafe(yaml, "ip_address_deny")
449-
450-
if err != nil {
451-
return nil, formatPropError("resources:ip_address_deny", err)
452-
}
380+
resources.IPAddressDeny = yamlGetSafe(yaml, "ip_address_deny")
453381
}
454382

455383
return resources, nil
456384
}
457385

458386
// yamlGetSafe returns string from YAML without potentially unsafe symbols
459-
func yamlGetSafe(yaml *simpleyaml.Yaml, propName string) (string, error) {
460-
value, err := yaml.Get(propName).String()
461-
462-
if err != nil {
463-
return "", err
464-
}
465-
466-
return strings.Trim(value, "\n\r"), nil
387+
func yamlGetSafe(yaml *simpleyaml.Yaml, propName string) string {
388+
return strings.Trim(yaml.Get(propName).Dump(), "\n\r")
467389
}
468390

469391
// formatPropError format property parsing error

‎testdata/procfile_v2

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ version: 2
33
start_on_runlevel: 2
44
stop_on_runlevel: 5
55
start_on_device: bond0
6+
strong_dependencies: true
7+
depends: postgresql-11 redis
68

79
env:
810
RAILS_ENV: production
@@ -56,6 +58,7 @@ commands:
5658
cpu_weight: 50
5759
startup_cpu_weight: 15
5860
cpu_quota: 40
61+
cpu_affinity: 1,3,5-7
5962
memory_low: 1G
6063
memory_high: 4G
6164
memory_max: 8G

0 commit comments

Comments
 (0)
Please sign in to comment.