Merge pull request #389 from jzelinskie/revendor
Regenerate vendor redirectory
This commit is contained in:
commit
d07183ee74
database
glide.lockglide.yamlvendor/github.com
beorn7/perks
codegangsta/negroni
README.mddoc.gologger.gologger_test.gonegroni.gonegroni_test.gorecovery.gorecovery_test.goresponse_writer.goresponse_writer_test.gostatic.gostatic_test.go
translations
coreos
go-systemd
.travis.ymlCONTRIBUTING.mdDCOLICENSEREADME.md
activation
daemon
dbus
dbus.godbus_test.gomethods.gomethods_test.goproperties.goset.goset_test.gosubscription.gosubscription_set.gosubscription_set_test.gosubscription_test.go
examples/activation
fixtures
journal
login1
machine1
sdjournal
testunit
deserialize.godeserialize_test.goend_to_end_test.goescape.goescape_test.gooption.gooption_test.goserialize.goserialize_test.go
util
pkg
davecgh/go-spew
fatih/color
@ -83,11 +83,16 @@ type Vulnerability struct {
|
||||
type MetadataMap map[string]interface{}
|
||||
|
||||
func (mm *MetadataMap) Scan(value interface{}) error {
|
||||
val, ok := value.([]byte)
|
||||
if !ok {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(val, mm)
|
||||
|
||||
// github.com/lib/pq decodes TEXT/VARCHAR fields into strings.
|
||||
val, ok := value.(string)
|
||||
if !ok {
|
||||
panic("got type other than []byte from database")
|
||||
}
|
||||
return json.Unmarshal([]byte(val), mm)
|
||||
}
|
||||
|
||||
func (mm *MetadataMap) Value() (driver.Value, error) {
|
||||
|
69
glide.lock
generated
69
glide.lock
generated
@ -1,107 +1,80 @@
|
||||
hash: 3244008146f5de85e444b1e7e9b2ec760ad143127b4b193968a6d5e293039d1c
|
||||
updated: 2017-05-02T15:32:01.996561192-04:00
|
||||
hash: 74b5b23a00a6db4941521bf3adc5ca49a1ab15c857534177654bacc9fc74cdfe
|
||||
updated: 2017-05-05T11:40:41.533307281-04:00
|
||||
imports:
|
||||
- name: github.com/beorn7/perks
|
||||
version: b965b613227fddccbfffe13eae360ed3fa822f8d
|
||||
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
subpackages:
|
||||
- quantile
|
||||
- name: github.com/codegangsta/negroni
|
||||
version: c7477ad8e330bef55bf1ebe300cf8aa67c492d1b
|
||||
- name: github.com/coreos/go-systemd
|
||||
version: 4f14f6deef2da87e4aa59e6c1c1f3e02ba44c5e1
|
||||
subpackages:
|
||||
- journal
|
||||
- name: github.com/coreos/pkg
|
||||
version: 2c77715c4df99b5420ffcae14ead08f52104065d
|
||||
version: 3ac0863d7acf3bc44daf49afef8919af12f704ef
|
||||
subpackages:
|
||||
- capnslog
|
||||
- timeutil
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/fatih/color
|
||||
version: 87d4004f2ab62d0d255e0a38f1680aa534549fe3
|
||||
- name: github.com/fernet/fernet-go
|
||||
version: 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
|
||||
- name: github.com/go-sql-driver/mysql
|
||||
version: d512f204a577a4ab037a1816604c48c9c13210be
|
||||
- name: github.com/golang/protobuf
|
||||
version: 5fc2294e655b78ed8a02082d37808d46c17d7e64
|
||||
version: 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8
|
||||
subpackages:
|
||||
- proto
|
||||
- name: github.com/guregu/null
|
||||
version: 79c5bd36b615db4c06132321189f579c8a5fca98
|
||||
version: 41961cea0328defc5f95c1c473f89ebf0d1813f6
|
||||
subpackages:
|
||||
- zero
|
||||
- name: github.com/hashicorp/golang-lru
|
||||
version: 5c7531c003d8bf158b0fe5063649a2f41a822146
|
||||
version: 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
|
||||
subpackages:
|
||||
- simplelru
|
||||
- name: github.com/julienschmidt/httprouter
|
||||
version: 21439ef4d70ba4f3e2a5ed9249e7b03af4019b40
|
||||
- name: github.com/kr/text
|
||||
version: 7cafcd837844e784b526369c9bce262804aebc60
|
||||
- name: github.com/kylelemons/go-gypsy
|
||||
version: 42fc2c7ee9b8bd0ff636cd2d7a8c0a49491044c5
|
||||
subpackages:
|
||||
- yaml
|
||||
version: 8c199fb6259ffc1af525cc3ad52ee60ba8359669
|
||||
- name: github.com/lib/pq
|
||||
version: 11fc39a580a008f1f39bb3d11d984fb34ed778d9
|
||||
version: 2704adc878c21e1329f46f6e56a1c387d788ff94
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/mattn/go-sqlite3
|
||||
version: 5510da399572b4962c020184bb291120c0a412e2
|
||||
- name: github.com/matttproud/golang_protobuf_extensions
|
||||
version: d0c3fe89de86839aecf2e0579c40ba3bb336a453
|
||||
version: c12348ce28de40eed0136aa2b644d0ee0650e56c
|
||||
subpackages:
|
||||
- pbutil
|
||||
- name: github.com/pborman/uuid
|
||||
version: dee7705ef7b324f27ceb85a121c61f2c2e8ce988
|
||||
version: a97ce2ca70fa5a848076093f05e639a89ca34d06
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: e8554b8641db39598be7f6342874b958f12ae1d4
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/prometheus/client_golang
|
||||
version: 67994f177195311c3ea3d4407ed0175e34a4256f
|
||||
version: c5b7fccd204277076155f10851dad72b76a49317
|
||||
subpackages:
|
||||
- prometheus
|
||||
- name: github.com/prometheus/client_model
|
||||
version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6
|
||||
version: 6f3806018612930941127f2a7c6c453ba2c527d2
|
||||
subpackages:
|
||||
- go
|
||||
- name: github.com/prometheus/common
|
||||
version: dba5e39d4516169e840def50e507ef5f21b985f9
|
||||
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
|
||||
subpackages:
|
||||
- expfmt
|
||||
- internal/bitbucket.org/ww/goautoneg
|
||||
- model
|
||||
- name: github.com/prometheus/procfs
|
||||
version: 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8
|
||||
version: d098ca18df8bc825079013daf7bacefbb1ee877e
|
||||
subpackages:
|
||||
- xfs
|
||||
- name: github.com/remind101/migrate
|
||||
version: d22d647232c20dbea6d2aa1dda7f2737cccce614
|
||||
- name: github.com/sirupsen/logrus
|
||||
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f
|
||||
- name: github.com/stretchr/testify
|
||||
version: 5b9da39b66e8e994455c2525c4421c8cc00a7f93
|
||||
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
|
||||
subpackages:
|
||||
- assert
|
||||
- name: github.com/tylerb/graceful
|
||||
version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
|
||||
- name: github.com/ziutek/mymysql
|
||||
version: 75ce5fbba34b1912a3641adbd58cf317d7315821
|
||||
subpackages:
|
||||
- godrv
|
||||
- mysql
|
||||
- native
|
||||
- name: golang.org/x/net
|
||||
version: 1d7a0b2100da090d8b02afcfb42f97e2c77e71a4
|
||||
subpackages:
|
||||
- netutil
|
||||
- name: golang.org/x/sys
|
||||
version: 9ccfe848b9db8435a24c424abbc07a921adf1df5
|
||||
subpackages:
|
||||
- unix
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: f7716cbe52baa25d2e9b0d0da546fcf909fc16b4
|
||||
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
|
||||
testImports: []
|
||||
|
84
glide.yaml
84
glide.yaml
@ -1,95 +1,31 @@
|
||||
package: github.com/coreos/clair
|
||||
import:
|
||||
- package: github.com/beorn7/perks
|
||||
version: b965b613227fddccbfffe13eae360ed3fa822f8d
|
||||
subpackages:
|
||||
- quantile
|
||||
- package: github.com/codegangsta/negroni
|
||||
version: c7477ad8e330bef55bf1ebe300cf8aa67c492d1b
|
||||
- package: github.com/coreos/go-systemd
|
||||
version: 4f14f6deef2da87e4aa59e6c1c1f3e02ba44c5e1
|
||||
subpackages:
|
||||
- journal
|
||||
- package: github.com/coreos/pkg
|
||||
version: 2c77715c4df99b5420ffcae14ead08f52104065d
|
||||
version: ^3.0.0
|
||||
subpackages:
|
||||
- capnslog
|
||||
- timeutil
|
||||
- package: github.com/davecgh/go-spew
|
||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||
subpackages:
|
||||
- spew
|
||||
- package: github.com/fernet/fernet-go
|
||||
version: 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
|
||||
- package: github.com/go-sql-driver/mysql
|
||||
version: d512f204a577a4ab037a1816604c48c9c13210be
|
||||
- package: github.com/golang/protobuf
|
||||
version: 5fc2294e655b78ed8a02082d37808d46c17d7e64
|
||||
subpackages:
|
||||
- proto
|
||||
- package: github.com/guregu/null
|
||||
version: 79c5bd36b615db4c06132321189f579c8a5fca98
|
||||
version: ^3.1.0
|
||||
subpackages:
|
||||
- zero
|
||||
- package: github.com/hashicorp/golang-lru
|
||||
version: 5c7531c003d8bf158b0fe5063649a2f41a822146
|
||||
- package: github.com/julienschmidt/httprouter
|
||||
version: 21439ef4d70ba4f3e2a5ed9249e7b03af4019b40
|
||||
- package: github.com/kylelemons/go-gypsy
|
||||
version: 42fc2c7ee9b8bd0ff636cd2d7a8c0a49491044c5
|
||||
subpackages:
|
||||
- yaml
|
||||
version: ^1.1.0
|
||||
- package: github.com/lib/pq
|
||||
version: 11fc39a580a008f1f39bb3d11d984fb34ed778d9
|
||||
- package: github.com/mattn/go-sqlite3
|
||||
version: 5510da399572b4962c020184bb291120c0a412e2
|
||||
- package: github.com/matttproud/golang_protobuf_extensions
|
||||
version: d0c3fe89de86839aecf2e0579c40ba3bb336a453
|
||||
subpackages:
|
||||
- pbutil
|
||||
- package: github.com/pborman/uuid
|
||||
version: dee7705ef7b324f27ceb85a121c61f2c2e8ce988
|
||||
- package: github.com/pmezard/go-difflib
|
||||
version: e8554b8641db39598be7f6342874b958f12ae1d4
|
||||
subpackages:
|
||||
- difflib
|
||||
version: ^1.0.0
|
||||
- package: github.com/prometheus/client_golang
|
||||
version: 67994f177195311c3ea3d4407ed0175e34a4256f
|
||||
version: ^0.8.0
|
||||
subpackages:
|
||||
- prometheus
|
||||
- package: github.com/prometheus/client_model
|
||||
version: fa8ad6fec33561be4280a8f0514318c79d7f6cb6
|
||||
subpackages:
|
||||
- go
|
||||
- package: github.com/prometheus/common
|
||||
version: dba5e39d4516169e840def50e507ef5f21b985f9
|
||||
subpackages:
|
||||
- expfmt
|
||||
- internal/bitbucket.org/ww/goautoneg
|
||||
- model
|
||||
- package: github.com/prometheus/procfs
|
||||
version: 406e5b7bfd8201a36e2bb5f7bdae0b03380c2ce8
|
||||
- package: github.com/remind101/migrate
|
||||
- package: github.com/sirupsen/logrus
|
||||
version: ^0.11.5
|
||||
- package: github.com/stretchr/testify
|
||||
version: 5b9da39b66e8e994455c2525c4421c8cc00a7f93
|
||||
version: ^1.1.4
|
||||
subpackages:
|
||||
- assert
|
||||
- package: github.com/tylerb/graceful
|
||||
version: ^1.2.3
|
||||
- package: github.com/ziutek/mymysql
|
||||
version: 75ce5fbba34b1912a3641adbd58cf317d7315821
|
||||
subpackages:
|
||||
- godrv
|
||||
- mysql
|
||||
- native
|
||||
- package: golang.org/x/net
|
||||
version: 1d7a0b2100da090d8b02afcfb42f97e2c77e71a4
|
||||
subpackages:
|
||||
- netutil
|
||||
version: ^1.2.15
|
||||
- package: gopkg.in/yaml.v2
|
||||
version: f7716cbe52baa25d2e9b0d0da546fcf909fc16b4
|
||||
- package: github.com/fatih/color
|
||||
version: ^0.1.0
|
||||
- package: github.com/kr/text
|
||||
- package: github.com/remind101/migrate
|
||||
- package: github.com/sirupsen/logrus
|
||||
version: ^0.11.5
|
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (C) 2013 Blake Mizerany
|
||||
|
||||
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.
|
2
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
2
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
@ -133,7 +133,7 @@ func (s *Stream) Query(q float64) float64 {
|
||||
if l == 0 {
|
||||
return 0
|
||||
}
|
||||
i := int(float64(l) * q)
|
||||
i := int(math.Ceil(float64(l) * q))
|
||||
if i > 0 {
|
||||
i -= 1
|
||||
}
|
||||
|
27
vendor/github.com/beorn7/perks/quantile/stream_test.go
generated
vendored
27
vendor/github.com/beorn7/perks/quantile/stream_test.go
generated
vendored
@ -33,6 +33,9 @@ func verifyPercsWithAbsoluteEpsilon(t *testing.T, a []float64, s *Stream) {
|
||||
for quantile, epsilon := range Targets {
|
||||
n := float64(len(a))
|
||||
k := int(quantile * n)
|
||||
if k < 1 {
|
||||
k = 1
|
||||
}
|
||||
lower := int((quantile - epsilon) * n)
|
||||
if lower < 1 {
|
||||
lower = 1
|
||||
@ -99,6 +102,30 @@ func TestTargetedQuery(t *testing.T) {
|
||||
verifyPercsWithAbsoluteEpsilon(t, a, s)
|
||||
}
|
||||
|
||||
func TestTargetedQuerySmallSampleSize(t *testing.T) {
|
||||
rand.Seed(42)
|
||||
s := NewTargeted(TargetsSmallEpsilon)
|
||||
a := []float64{1, 2, 3, 4, 5}
|
||||
for _, v := range a {
|
||||
s.Insert(v)
|
||||
}
|
||||
verifyPercsWithAbsoluteEpsilon(t, a, s)
|
||||
// If not yet flushed, results should be precise:
|
||||
if !s.flushed() {
|
||||
for φ, want := range map[float64]float64{
|
||||
0.01: 1,
|
||||
0.10: 1,
|
||||
0.50: 3,
|
||||
0.90: 5,
|
||||
0.99: 5,
|
||||
} {
|
||||
if got := s.Query(φ); got != want {
|
||||
t.Errorf("want %f for φ=%f, got %f", want, φ, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowBiasedQuery(t *testing.T) {
|
||||
rand.Seed(42)
|
||||
s := NewLowBiased(RelativeEpsilon)
|
||||
|
181
vendor/github.com/codegangsta/negroni/README.md
generated
vendored
181
vendor/github.com/codegangsta/negroni/README.md
generated
vendored
@ -1,181 +0,0 @@
|
||||
# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
|
||||
|
||||
Negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of `net/http` Handlers.
|
||||
|
||||
If you like the idea of [Martini](http://github.com/go-martini/martini), but you think it contains too much magic, then Negroni is a great fit.
|
||||
|
||||
|
||||
Language Translations:
|
||||
* [Português Brasileiro (pt_BR)](translations/README_pt_br.md)
|
||||
|
||||
## Getting Started
|
||||
|
||||
After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`.
|
||||
|
||||
~~~ go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/codegangsta/negroni"
|
||||
"net/http"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "Welcome to the home page!")
|
||||
})
|
||||
|
||||
n := negroni.Classic()
|
||||
n.UseHandler(mux)
|
||||
n.Run(":3000")
|
||||
}
|
||||
~~~
|
||||
|
||||
Then install the Negroni package (**go 1.1** and greater is required):
|
||||
~~~
|
||||
go get github.com/codegangsta/negroni
|
||||
~~~
|
||||
|
||||
Then run your server:
|
||||
~~~
|
||||
go run server.go
|
||||
~~~
|
||||
|
||||
You will now have a Go net/http webserver running on `localhost:3000`.
|
||||
|
||||
## Need Help?
|
||||
If you have a question or feature request, [go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). The GitHub issues for Negroni will be used exclusively for bug reports and pull requests.
|
||||
|
||||
## Is Negroni a Framework?
|
||||
Negroni is **not** a framework. It is a library that is designed to work directly with net/http.
|
||||
|
||||
## Routing?
|
||||
Negroni is BYOR (Bring your own Router). The Go community already has a number of great http routers available, Negroni tries to play well with all of them by fully supporting `net/http`. For instance, integrating with [Gorilla Mux](http://github.com/gorilla/mux) looks like so:
|
||||
|
||||
~~~ go
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/", HomeHandler)
|
||||
|
||||
n := negroni.New(Middleware1, Middleware2)
|
||||
// Or use a middleware with the Use() function
|
||||
n.Use(Middleware3)
|
||||
// router goes last
|
||||
n.UseHandler(router)
|
||||
|
||||
n.Run(":3000")
|
||||
~~~
|
||||
|
||||
## `negroni.Classic()`
|
||||
`negroni.Classic()` provides some default middleware that is useful for most applications:
|
||||
|
||||
* `negroni.Recovery` - Panic Recovery Middleware.
|
||||
* `negroni.Logging` - Request/Response Logging Middleware.
|
||||
* `negroni.Static` - Static File serving under the "public" directory.
|
||||
|
||||
This makes it really easy to get started with some useful features from Negroni.
|
||||
|
||||
## Handlers
|
||||
Negroni provides a bidirectional middleware flow. This is done through the `negroni.Handler` interface:
|
||||
|
||||
~~~ go
|
||||
type Handler interface {
|
||||
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||
}
|
||||
~~~
|
||||
|
||||
If a middleware hasn't already written to the ResponseWriter, it should call the next `http.HandlerFunc` in the chain to yield to the next middleware handler. This can be used for great good:
|
||||
|
||||
~~~ go
|
||||
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
// do some stuff before
|
||||
next(rw, r)
|
||||
// do some stuff after
|
||||
}
|
||||
~~~
|
||||
|
||||
And you can map it to the handler chain with the `Use` function:
|
||||
|
||||
~~~ go
|
||||
n := negroni.New()
|
||||
n.Use(negroni.HandlerFunc(MyMiddleware))
|
||||
~~~
|
||||
|
||||
You can also map plain old `http.Handler`s:
|
||||
|
||||
~~~ go
|
||||
n := negroni.New()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
// map your routes
|
||||
|
||||
n.UseHandler(mux)
|
||||
|
||||
n.Run(":3000")
|
||||
~~~
|
||||
|
||||
## `Run()`
|
||||
Negroni has a convenience function called `Run`. `Run` takes an addr string identical to [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe).
|
||||
|
||||
~~~ go
|
||||
n := negroni.Classic()
|
||||
// ...
|
||||
log.Fatal(http.ListenAndServe(":8080", n))
|
||||
~~~
|
||||
|
||||
## Route Specific Middleware
|
||||
If you have a route group of routes that need specific middleware to be executed, you can simply create a new Negroni instance and use it as your route handler.
|
||||
|
||||
~~~ go
|
||||
router := mux.NewRouter()
|
||||
adminRoutes := mux.NewRouter()
|
||||
// add admin routes here
|
||||
|
||||
// Create a new negroni for the admin middleware
|
||||
router.Handle("/admin", negroni.New(
|
||||
Middleware1,
|
||||
Middleware2,
|
||||
negroni.Wrap(adminRoutes),
|
||||
))
|
||||
~~~
|
||||
|
||||
## Third Party Middleware
|
||||
|
||||
Here is a current list of Negroni compatible middlware. Feel free to put up a PR linking your middleware if you have built one:
|
||||
|
||||
|
||||
| Middleware | Author | Description |
|
||||
| -----------|--------|-------------|
|
||||
| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints |
|
||||
| [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
|
||||
| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |
|
||||
| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it|
|
||||
| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs |
|
||||
| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
|
||||
| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates |
|
||||
| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
|
||||
| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression |
|
||||
| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware |
|
||||
| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management |
|
||||
| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions |
|
||||
| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly |
|
||||
| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support |
|
||||
| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request |
|
||||
| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
|
||||
| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) |
|
||||
|
||||
## Examples
|
||||
[Alexander Rødseth](https://github.com/xyproto) created [mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a Negroni middleware handler.
|
||||
|
||||
## Live code reload?
|
||||
[gin](https://github.com/codegangsta/gin) and [fresh](https://github.com/pilu/fresh) both live reload negroni apps.
|
||||
|
||||
## Essential Reading for Beginners of Go & Negroni
|
||||
|
||||
* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/)
|
||||
* [Understanding middleware](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
|
||||
|
||||
## About
|
||||
|
||||
Negroni is obsessively designed by none other than the [Code Gangsta](http://codegangsta.io/)
|
25
vendor/github.com/codegangsta/negroni/doc.go
generated
vendored
25
vendor/github.com/codegangsta/negroni/doc.go
generated
vendored
@ -1,25 +0,0 @@
|
||||
// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.
|
||||
//
|
||||
// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
|
||||
//
|
||||
// For a full guide visit http://github.com/codegangsta/negroni
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "github.com/codegangsta/negroni"
|
||||
// "net/http"
|
||||
// "fmt"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// mux := http.NewServeMux()
|
||||
// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
// fmt.Fprintf(w, "Welcome to the home page!")
|
||||
// })
|
||||
//
|
||||
// n := negroni.Classic()
|
||||
// n.UseHandler(mux)
|
||||
// n.Run(":3000")
|
||||
// }
|
||||
package negroni
|
29
vendor/github.com/codegangsta/negroni/logger.go
generated
vendored
29
vendor/github.com/codegangsta/negroni/logger.go
generated
vendored
@ -1,29 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
|
||||
type Logger struct {
|
||||
// Logger inherits from log.Logger used to log messages with the Logger middleware
|
||||
*log.Logger
|
||||
}
|
||||
|
||||
// NewLogger returns a new Logger instance
|
||||
func NewLogger() *Logger {
|
||||
return &Logger{log.New(os.Stdout, "[negroni] ", 0)}
|
||||
}
|
||||
|
||||
func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
start := time.Now()
|
||||
l.Printf("Started %s %s", r.Method, r.URL.Path)
|
||||
|
||||
next(rw, r)
|
||||
|
||||
res := rw.(ResponseWriter)
|
||||
l.Printf("Completed %v %s in %v", res.Status(), http.StatusText(res.Status()), time.Since(start))
|
||||
}
|
33
vendor/github.com/codegangsta/negroni/logger_test.go
generated
vendored
33
vendor/github.com/codegangsta/negroni/logger_test.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Logger(t *testing.T) {
|
||||
buff := bytes.NewBufferString("")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
l := NewLogger()
|
||||
l.Logger = log.New(buff, "[negroni] ", 0)
|
||||
|
||||
n := New()
|
||||
// replace log for testing
|
||||
n.Use(l)
|
||||
n.UseHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
|
||||
req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(recorder, req)
|
||||
expect(t, recorder.Code, http.StatusNotFound)
|
||||
refute(t, len(buff.String()), 0)
|
||||
}
|
129
vendor/github.com/codegangsta/negroni/negroni.go
generated
vendored
129
vendor/github.com/codegangsta/negroni/negroni.go
generated
vendored
@ -1,129 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Handler handler is an interface that objects can implement to be registered to serve as middleware
|
||||
// in the Negroni middleware stack.
|
||||
// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
|
||||
// passed in.
|
||||
//
|
||||
// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
|
||||
type Handler interface {
|
||||
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||
}
|
||||
|
||||
// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
|
||||
// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
|
||||
type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||
|
||||
func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
h(rw, r, next)
|
||||
}
|
||||
|
||||
type middleware struct {
|
||||
handler Handler
|
||||
next *middleware
|
||||
}
|
||||
|
||||
func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
|
||||
}
|
||||
|
||||
// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
|
||||
// middleware. The next http.HandlerFunc is automatically called after the Handler
|
||||
// is executed.
|
||||
func Wrap(handler http.Handler) Handler {
|
||||
return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
handler.ServeHTTP(rw, r)
|
||||
next(rw, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
|
||||
// Negroni middleware is evaluated in the order that they are added to the stack using
|
||||
// the Use and UseHandler methods.
|
||||
type Negroni struct {
|
||||
middleware middleware
|
||||
handlers []Handler
|
||||
}
|
||||
|
||||
// New returns a new Negroni instance with no middleware preconfigured.
|
||||
func New(handlers ...Handler) *Negroni {
|
||||
return &Negroni{
|
||||
handlers: handlers,
|
||||
middleware: build(handlers),
|
||||
}
|
||||
}
|
||||
|
||||
// Classic returns a new Negroni instance with the default middleware already
|
||||
// in the stack.
|
||||
//
|
||||
// Recovery - Panic Recovery Middleware
|
||||
// Logger - Request/Response Logging
|
||||
// Static - Static File Serving
|
||||
func Classic() *Negroni {
|
||||
return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
|
||||
}
|
||||
|
||||
func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
n.middleware.ServeHTTP(NewResponseWriter(rw), r)
|
||||
}
|
||||
|
||||
// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
||||
func (n *Negroni) Use(handler Handler) {
|
||||
n.handlers = append(n.handlers, handler)
|
||||
n.middleware = build(n.handlers)
|
||||
}
|
||||
|
||||
// UseFunc adds a Negroni-style handler function onto the middleware stack.
|
||||
func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
|
||||
n.Use(HandlerFunc(handlerFunc))
|
||||
}
|
||||
|
||||
// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
|
||||
func (n *Negroni) UseHandler(handler http.Handler) {
|
||||
n.Use(Wrap(handler))
|
||||
}
|
||||
|
||||
// UseHandler adds a http.HandlerFunc-style handler function onto the middleware stack.
|
||||
func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
|
||||
n.UseHandler(http.HandlerFunc(handlerFunc))
|
||||
}
|
||||
|
||||
// Run is a convenience function that runs the negroni stack as an HTTP
|
||||
// server. The addr string takes the same format as http.ListenAndServe.
|
||||
func (n *Negroni) Run(addr string) {
|
||||
l := log.New(os.Stdout, "[negroni] ", 0)
|
||||
l.Printf("listening on %s", addr)
|
||||
l.Fatal(http.ListenAndServe(addr, n))
|
||||
}
|
||||
|
||||
// Returns a list of all the handlers in the current Negroni middleware chain.
|
||||
func (n *Negroni) Handlers() []Handler {
|
||||
return n.handlers
|
||||
}
|
||||
|
||||
func build(handlers []Handler) middleware {
|
||||
var next middleware
|
||||
|
||||
if len(handlers) == 0 {
|
||||
return voidMiddleware()
|
||||
} else if len(handlers) > 1 {
|
||||
next = build(handlers[1:])
|
||||
} else {
|
||||
next = voidMiddleware()
|
||||
}
|
||||
|
||||
return middleware{handlers[0], &next}
|
||||
}
|
||||
|
||||
func voidMiddleware() middleware {
|
||||
return middleware{
|
||||
HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
|
||||
&middleware{},
|
||||
}
|
||||
}
|
75
vendor/github.com/codegangsta/negroni/negroni_test.go
generated
vendored
75
vendor/github.com/codegangsta/negroni/negroni_test.go
generated
vendored
@ -1,75 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/* Test Helpers */
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
if a != b {
|
||||
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
if a == b {
|
||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegroniRun(t *testing.T) {
|
||||
// just test that Run doesn't bomb
|
||||
go New().Run(":3000")
|
||||
}
|
||||
|
||||
func TestNegroniServeHTTP(t *testing.T) {
|
||||
result := ""
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
n := New()
|
||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
result += "foo"
|
||||
next(rw, r)
|
||||
result += "ban"
|
||||
}))
|
||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
result += "bar"
|
||||
next(rw, r)
|
||||
result += "baz"
|
||||
}))
|
||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
result += "bat"
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
}))
|
||||
|
||||
n.ServeHTTP(response, (*http.Request)(nil))
|
||||
|
||||
expect(t, result, "foobarbatbazban")
|
||||
expect(t, response.Code, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// Ensures that a Negroni middleware chain
|
||||
// can correctly return all of its handlers.
|
||||
func TestHandlers(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
n := New()
|
||||
handlers := n.Handlers()
|
||||
expect(t, 0, len(handlers))
|
||||
|
||||
n.Use(HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
// Expects the length of handlers to be exactly 1
|
||||
// after adding exactly one handler to the middleware chain
|
||||
handlers = n.Handlers()
|
||||
expect(t, 1, len(handlers))
|
||||
|
||||
// Ensures that the first handler that is in sequence behaves
|
||||
// exactly the same as the one that was registered earlier
|
||||
handlers[0].ServeHTTP(response, (*http.Request)(nil), nil)
|
||||
expect(t, response.Code, http.StatusOK)
|
||||
}
|
46
vendor/github.com/codegangsta/negroni/recovery.go
generated
vendored
46
vendor/github.com/codegangsta/negroni/recovery.go
generated
vendored
@ -1,46 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
|
||||
type Recovery struct {
|
||||
Logger *log.Logger
|
||||
PrintStack bool
|
||||
StackAll bool
|
||||
StackSize int
|
||||
}
|
||||
|
||||
// NewRecovery returns a new instance of Recovery
|
||||
func NewRecovery() *Recovery {
|
||||
return &Recovery{
|
||||
Logger: log.New(os.Stdout, "[negroni] ", 0),
|
||||
PrintStack: true,
|
||||
StackAll: false,
|
||||
StackSize: 1024 * 8,
|
||||
}
|
||||
}
|
||||
|
||||
func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
stack := make([]byte, rec.StackSize)
|
||||
stack = stack[:runtime.Stack(stack, rec.StackAll)]
|
||||
|
||||
f := "PANIC: %s\n%s"
|
||||
rec.Logger.Printf(f, err, stack)
|
||||
|
||||
if rec.PrintStack {
|
||||
fmt.Fprintf(rw, f, err, stack)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
next(rw, r)
|
||||
}
|
28
vendor/github.com/codegangsta/negroni/recovery_test.go
generated
vendored
28
vendor/github.com/codegangsta/negroni/recovery_test.go
generated
vendored
@ -1,28 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRecovery(t *testing.T) {
|
||||
buff := bytes.NewBufferString("")
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
rec := NewRecovery()
|
||||
rec.Logger = log.New(buff, "[negroni] ", 0)
|
||||
|
||||
n := New()
|
||||
// replace log for testing
|
||||
n.Use(rec)
|
||||
n.UseHandler(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||
panic("here is a panic!")
|
||||
}))
|
||||
n.ServeHTTP(recorder, (*http.Request)(nil))
|
||||
expect(t, recorder.Code, http.StatusInternalServerError)
|
||||
refute(t, recorder.Body.Len(), 0)
|
||||
refute(t, len(buff.String()), 0)
|
||||
}
|
96
vendor/github.com/codegangsta/negroni/response_writer.go
generated
vendored
96
vendor/github.com/codegangsta/negroni/response_writer.go
generated
vendored
@ -1,96 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
|
||||
// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
|
||||
// if the functionality calls for it.
|
||||
type ResponseWriter interface {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
// Status returns the status code of the response or 0 if the response has not been written.
|
||||
Status() int
|
||||
// Written returns whether or not the ResponseWriter has been written.
|
||||
Written() bool
|
||||
// Size returns the size of the response body.
|
||||
Size() int
|
||||
// Before allows for a function to be called before the ResponseWriter has been written to. This is
|
||||
// useful for setting headers or any other operations that must happen before a response has been written.
|
||||
Before(func(ResponseWriter))
|
||||
}
|
||||
|
||||
type beforeFunc func(ResponseWriter)
|
||||
|
||||
// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
|
||||
func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
|
||||
return &responseWriter{rw, 0, 0, nil}
|
||||
}
|
||||
|
||||
type responseWriter struct {
|
||||
http.ResponseWriter
|
||||
status int
|
||||
size int
|
||||
beforeFuncs []beforeFunc
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(s int) {
|
||||
rw.status = s
|
||||
rw.callBefore()
|
||||
rw.ResponseWriter.WriteHeader(s)
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Write(b []byte) (int, error) {
|
||||
if !rw.Written() {
|
||||
// The status will be StatusOK if WriteHeader has not been called yet
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
size, err := rw.ResponseWriter.Write(b)
|
||||
rw.size += size
|
||||
return size, err
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Status() int {
|
||||
return rw.status
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Size() int {
|
||||
return rw.size
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Written() bool {
|
||||
return rw.status != 0
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Before(before func(ResponseWriter)) {
|
||||
rw.beforeFuncs = append(rw.beforeFuncs, before)
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
|
||||
}
|
||||
return hijacker.Hijack()
|
||||
}
|
||||
|
||||
func (rw *responseWriter) CloseNotify() <-chan bool {
|
||||
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (rw *responseWriter) callBefore() {
|
||||
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
|
||||
rw.beforeFuncs[i](rw)
|
||||
}
|
||||
}
|
||||
|
||||
func (rw *responseWriter) Flush() {
|
||||
flusher, ok := rw.ResponseWriter.(http.Flusher)
|
||||
if ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
150
vendor/github.com/codegangsta/negroni/response_writer_test.go
generated
vendored
150
vendor/github.com/codegangsta/negroni/response_writer_test.go
generated
vendored
@ -1,150 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type closeNotifyingRecorder struct {
|
||||
*httptest.ResponseRecorder
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
||||
return &closeNotifyingRecorder{
|
||||
httptest.NewRecorder(),
|
||||
make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *closeNotifyingRecorder) close() {
|
||||
c.closed <- true
|
||||
}
|
||||
|
||||
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
||||
return c.closed
|
||||
}
|
||||
|
||||
type hijackableResponse struct {
|
||||
Hijacked bool
|
||||
}
|
||||
|
||||
func newHijackableResponse() *hijackableResponse {
|
||||
return &hijackableResponse{}
|
||||
}
|
||||
|
||||
func (h *hijackableResponse) Header() http.Header { return nil }
|
||||
func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil }
|
||||
func (h *hijackableResponse) WriteHeader(code int) {}
|
||||
func (h *hijackableResponse) Flush() {}
|
||||
func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
h.Hijacked = true
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func TestResponseWriterWritingString(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
|
||||
rw.Write([]byte("Hello world"))
|
||||
|
||||
expect(t, rec.Code, rw.Status())
|
||||
expect(t, rec.Body.String(), "Hello world")
|
||||
expect(t, rw.Status(), http.StatusOK)
|
||||
expect(t, rw.Size(), 11)
|
||||
expect(t, rw.Written(), true)
|
||||
}
|
||||
|
||||
func TestResponseWriterWritingStrings(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
|
||||
rw.Write([]byte("Hello world"))
|
||||
rw.Write([]byte("foo bar bat baz"))
|
||||
|
||||
expect(t, rec.Code, rw.Status())
|
||||
expect(t, rec.Body.String(), "Hello worldfoo bar bat baz")
|
||||
expect(t, rw.Status(), http.StatusOK)
|
||||
expect(t, rw.Size(), 26)
|
||||
}
|
||||
|
||||
func TestResponseWriterWritingHeader(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
|
||||
expect(t, rec.Code, rw.Status())
|
||||
expect(t, rec.Body.String(), "")
|
||||
expect(t, rw.Status(), http.StatusNotFound)
|
||||
expect(t, rw.Size(), 0)
|
||||
}
|
||||
|
||||
func TestResponseWriterBefore(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
result := ""
|
||||
|
||||
rw.Before(func(ResponseWriter) {
|
||||
result += "foo"
|
||||
})
|
||||
rw.Before(func(ResponseWriter) {
|
||||
result += "bar"
|
||||
})
|
||||
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
|
||||
expect(t, rec.Code, rw.Status())
|
||||
expect(t, rec.Body.String(), "")
|
||||
expect(t, rw.Status(), http.StatusNotFound)
|
||||
expect(t, rw.Size(), 0)
|
||||
expect(t, result, "barfoo")
|
||||
}
|
||||
|
||||
func TestResponseWriterHijack(t *testing.T) {
|
||||
hijackable := newHijackableResponse()
|
||||
rw := NewResponseWriter(hijackable)
|
||||
hijacker, ok := rw.(http.Hijacker)
|
||||
expect(t, ok, true)
|
||||
_, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
expect(t, hijackable.Hijacked, true)
|
||||
}
|
||||
|
||||
func TestResponseWriteHijackNotOK(t *testing.T) {
|
||||
hijackable := new(http.ResponseWriter)
|
||||
rw := NewResponseWriter(*hijackable)
|
||||
hijacker, ok := rw.(http.Hijacker)
|
||||
expect(t, ok, true)
|
||||
_, _, err := hijacker.Hijack()
|
||||
|
||||
refute(t, err, nil)
|
||||
}
|
||||
|
||||
func TestResponseWriterCloseNotify(t *testing.T) {
|
||||
rec := newCloseNotifyingRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
closed := false
|
||||
notifier := rw.(http.CloseNotifier).CloseNotify()
|
||||
rec.close()
|
||||
select {
|
||||
case <-notifier:
|
||||
closed = true
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
expect(t, closed, true)
|
||||
}
|
||||
|
||||
func TestResponseWriterFlusher(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
rw := NewResponseWriter(rec)
|
||||
|
||||
_, ok := rw.(http.Flusher)
|
||||
expect(t, ok, true)
|
||||
}
|
84
vendor/github.com/codegangsta/negroni/static.go
generated
vendored
84
vendor/github.com/codegangsta/negroni/static.go
generated
vendored
@ -1,84 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Static is a middleware handler that serves static files in the given directory/filesystem.
|
||||
type Static struct {
|
||||
// Dir is the directory to serve static files from
|
||||
Dir http.FileSystem
|
||||
// Prefix is the optional prefix used to serve the static directory content
|
||||
Prefix string
|
||||
// IndexFile defines which file to serve as index if it exists.
|
||||
IndexFile string
|
||||
}
|
||||
|
||||
// NewStatic returns a new instance of Static
|
||||
func NewStatic(directory http.FileSystem) *Static {
|
||||
return &Static{
|
||||
Dir: directory,
|
||||
Prefix: "",
|
||||
IndexFile: "index.html",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
if r.Method != "GET" && r.Method != "HEAD" {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
file := r.URL.Path
|
||||
// if we have a prefix, filter requests by stripping the prefix
|
||||
if s.Prefix != "" {
|
||||
if !strings.HasPrefix(file, s.Prefix) {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
file = file[len(s.Prefix):]
|
||||
if file != "" && file[0] != '/' {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
f, err := s.Dir.Open(file)
|
||||
if err != nil {
|
||||
// discard the error?
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
|
||||
// try to serve index file
|
||||
if fi.IsDir() {
|
||||
// redirect if missing trailing slash
|
||||
if !strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
file = path.Join(file, s.IndexFile)
|
||||
f, err = s.Dir.Open(file)
|
||||
if err != nil {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err = f.Stat()
|
||||
if err != nil || fi.IsDir() {
|
||||
next(rw, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
http.ServeContent(rw, r, file, fi.ModTime(), f)
|
||||
}
|
113
vendor/github.com/codegangsta/negroni/static_test.go
generated
vendored
113
vendor/github.com/codegangsta/negroni/static_test.go
generated
vendored
@ -1,113 +0,0 @@
|
||||
package negroni
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStatic(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
response.Body = new(bytes.Buffer)
|
||||
|
||||
n := New()
|
||||
n.Use(NewStatic(http.Dir(".")))
|
||||
|
||||
req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
n.ServeHTTP(response, req)
|
||||
expect(t, response.Code, http.StatusOK)
|
||||
expect(t, response.Header().Get("Expires"), "")
|
||||
if response.Body.Len() == 0 {
|
||||
t.Errorf("Got empty body for GET request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticHead(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
response.Body = new(bytes.Buffer)
|
||||
|
||||
n := New()
|
||||
n.Use(NewStatic(http.Dir(".")))
|
||||
n.UseHandler(http.NotFoundHandler())
|
||||
|
||||
req, err := http.NewRequest("HEAD", "http://localhost:3000/negroni.go", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(response, req)
|
||||
expect(t, response.Code, http.StatusOK)
|
||||
if response.Body.Len() != 0 {
|
||||
t.Errorf("Got non-empty body for HEAD request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticAsPost(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
n := New()
|
||||
n.Use(NewStatic(http.Dir(".")))
|
||||
n.UseHandler(http.NotFoundHandler())
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost:3000/negroni.go", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(response, req)
|
||||
expect(t, response.Code, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestStaticBadDir(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
n := Classic()
|
||||
n.UseHandler(http.NotFoundHandler())
|
||||
|
||||
req, err := http.NewRequest("GET", "http://localhost:3000/negroni.go", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(response, req)
|
||||
refute(t, response.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestStaticOptionsServeIndex(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
n := New()
|
||||
s := NewStatic(http.Dir("."))
|
||||
s.IndexFile = "negroni.go"
|
||||
n.Use(s)
|
||||
|
||||
req, err := http.NewRequest("GET", "http://localhost:3000/", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(response, req)
|
||||
expect(t, response.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
func TestStaticOptionsPrefix(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
n := New()
|
||||
s := NewStatic(http.Dir("."))
|
||||
s.Prefix = "/public"
|
||||
n.Use(s)
|
||||
|
||||
// Check file content behaviour
|
||||
req, err := http.NewRequest("GET", "http://localhost:3000/public/negroni.go", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
n.ServeHTTP(response, req)
|
||||
expect(t, response.Code, http.StatusOK)
|
||||
}
|
170
vendor/github.com/codegangsta/negroni/translations/README_pt_br.md
generated
vendored
170
vendor/github.com/codegangsta/negroni/translations/README_pt_br.md
generated
vendored
@ -1,170 +0,0 @@
|
||||
# Negroni [![GoDoc](https://godoc.org/github.com/codegangsta/negroni?status.svg)](http://godoc.org/github.com/codegangsta/negroni) [![wercker status](https://app.wercker.com/status/13688a4a94b82d84a0b8d038c4965b61/s "wercker status")](https://app.wercker.com/project/bykey/13688a4a94b82d84a0b8d038c4965b61)
|
||||
|
||||
Negroni é uma abordagem idiomática para middleware web em Go. É pequeno, não intrusivo, e incentiva uso da biblioteca `net/http`.
|
||||
|
||||
Se gosta da idéia do [Martini](http://github.com/go-martini/martini), mas acha que contém muita mágica, então Negroni é ideal.
|
||||
|
||||
## Começando
|
||||
|
||||
Depois de instalar Go e definir seu [GOPATH](http://golang.org/doc/code.html#GOPATH), criar seu primeirto arquivo `.go`. Iremos chamá-lo `server.go`.
|
||||
|
||||
~~~ go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/codegangsta/negroni"
|
||||
"net/http"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "Welcome to the home page!")
|
||||
})
|
||||
|
||||
n := negroni.Classic()
|
||||
n.UseHandler(mux)
|
||||
n.Run(":3000")
|
||||
}
|
||||
~~~
|
||||
|
||||
Depois instale o pacote Negroni (**go 1.1** ou superior)
|
||||
~~~
|
||||
go get github.com/codegangsta/negroni
|
||||
~~~
|
||||
|
||||
Depois execute seu servidor:
|
||||
~~~
|
||||
go run server.go
|
||||
~~~
|
||||
|
||||
Agora terá um servidor web Go net/http rodando em `localhost:3000`.
|
||||
|
||||
## Precisa de Ajuda?
|
||||
Se você tem uma pergunta ou pedido de recurso,[go ask the mailing list](https://groups.google.com/forum/#!forum/negroni-users). O Github issues para o Negroni será usado exclusivamente para Reportar bugs e pull requests.
|
||||
|
||||
## Negroni é um Framework?
|
||||
Negroni **não** é a framework. É uma biblioteca que é desenhada para trabalhar diretamente com net/http.
|
||||
|
||||
## Roteamento?
|
||||
Negroni é TSPR(Traga seu próprio Roteamento). A comunidade Go já tem um grande número de roteadores http disponíveis, Negroni tenta rodar bem com todos eles pelo suporte total `net/http`/ Por exemplo, a integração com [Gorilla Mux](http://github.com/gorilla/mux) se parece com isso:
|
||||
|
||||
~~~ go
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/", HomeHandler)
|
||||
|
||||
n := negroni.New(Middleware1, Middleware2)
|
||||
// Or use a middleware with the Use() function
|
||||
n.Use(Middleware3)
|
||||
// router goes last
|
||||
n.UseHandler(router)
|
||||
|
||||
n.Run(":3000")
|
||||
~~~
|
||||
|
||||
## `negroni.Classic()`
|
||||
`negroni.Classic()` fornece alguns middlewares padrão que são úteis para maioria das aplicações:
|
||||
|
||||
* `negroni.Recovery` - Panic Recovery Middleware.
|
||||
* `negroni.Logging` - Request/Response Logging Middleware.
|
||||
* `negroni.Static` - Static File serving under the "public" directory.
|
||||
|
||||
Isso torna muito fácil começar com alguns recursos úteis do Negroni.
|
||||
|
||||
## Handlers
|
||||
Negroni fornece um middleware de fluxo bidirecional. Isso é feito através da interface `negroni.Handler`:
|
||||
|
||||
~~~ go
|
||||
type Handler interface {
|
||||
ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||
}
|
||||
~~~
|
||||
|
||||
Se um middleware não tenha escrito o ResponseWriter, ele deve chamar a próxima `http.HandlerFunc` na cadeia para produzir o próximo handler middleware. Isso pode ser usado muito bem:
|
||||
|
||||
~~~ go
|
||||
func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
// do some stuff before
|
||||
next(rw, r)
|
||||
// do some stuff after
|
||||
}
|
||||
~~~
|
||||
|
||||
E pode mapear isso para a cadeia de handler com a função `Use`:
|
||||
|
||||
~~~ go
|
||||
n := negroni.New()
|
||||
n.Use(negroni.HandlerFunc(MyMiddleware))
|
||||
~~~
|
||||
|
||||
Você também pode mapear `http.Handler` antigos:
|
||||
|
||||
~~~ go
|
||||
n := negroni.New()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
// map your routes
|
||||
|
||||
n.UseHandler(mux)
|
||||
|
||||
n.Run(":3000")
|
||||
~~~
|
||||
|
||||
## `Run()`
|
||||
Negroni tem uma função de conveniência chamada `Run`. `Run` pega um endereço de string idêntico para [http.ListenAndServe](http://golang.org/pkg/net/http#ListenAndServe).
|
||||
|
||||
~~~ go
|
||||
n := negroni.Classic()
|
||||
// ...
|
||||
log.Fatal(http.ListenAndServe(":8080", n))
|
||||
~~~
|
||||
|
||||
## Middleware para Rotas Específicas
|
||||
Se você tem um grupo de rota com rotas que precisam ser executadas por um middleware específico, pode simplesmente criar uma nova instância de Negroni e usar no seu Manipulador de rota.
|
||||
|
||||
~~~ go
|
||||
router := mux.NewRouter()
|
||||
adminRoutes := mux.NewRouter()
|
||||
// add admin routes here
|
||||
|
||||
// Criar um middleware negroni para admin
|
||||
router.Handle("/admin", negroni.New(
|
||||
Middleware1,
|
||||
Middleware2,
|
||||
negroni.Wrap(adminRoutes),
|
||||
))
|
||||
~~~
|
||||
|
||||
## Middleware de Terceiros
|
||||
|
||||
Aqui está uma lista atual de Middleware Compatíveis com Negroni. Sinta se livre para mandar um PR vinculando seu middleware se construiu um:
|
||||
|
||||
|
||||
| Middleware | Autor | Descrição |
|
||||
| -----------|--------|-------------|
|
||||
| [Graceful](https://github.com/stretchr/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
|
||||
| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Implementa rapidamente itens de segurança.|
|
||||
| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Handler para mapeamento/validação de um request a estrutura. |
|
||||
| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
|
||||
| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Pacote para renderizar JSON, XML, e templates HTML. |
|
||||
| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
|
||||
| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | Handler para adicionar compreção gzip para as requisições |
|
||||
| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | Handler que prove sistema de login OAuth 2.0 para aplicações Martini. Google Sign-in, Facebook Connect e Github login são suportados. |
|
||||
| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Handler que provê o serviço de sessão. |
|
||||
| [permissions](https://github.com/xyproto/permissions) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, usuários e permissões. |
|
||||
| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Pacote para gerar TinySVG, HTML e CSS em tempo real. |
|
||||
|
||||
## Exemplos
|
||||
[Alexander Rødseth](https://github.com/xyproto) criou [mooseware](https://github.com/xyproto/mooseware), uma estrutura para escrever um handler middleware Negroni.
|
||||
|
||||
## Servidor com autoreload?
|
||||
[gin](https://github.com/codegangsta/gin) e [fresh](https://github.com/pilu/fresh) são aplicativos para autoreload do Negroni.
|
||||
|
||||
## Leitura Essencial para Iniciantes em Go & Negroni
|
||||
* [Usando um contexto para passar informação de um middleware para o manipulador final](http://elithrar.github.io/article/map-string-interface/)
|
||||
* [Entendendo middleware](http://mattstauffer.co/blog/laravel-5.0-middleware-replacing-filters)
|
||||
|
||||
|
||||
## Sobre
|
||||
Negroni é obsessivamente desenhado por ninguém menos que [Code Gangsta](http://codegangsta.io/)
|
8
vendor/github.com/coreos/go-systemd/.travis.yml
generated
vendored
8
vendor/github.com/coreos/go-systemd/.travis.yml
generated
vendored
@ -1,8 +0,0 @@
|
||||
language: go
|
||||
go: 1.4
|
||||
|
||||
install:
|
||||
- go get github.com/godbus/dbus
|
||||
|
||||
script:
|
||||
- ./test
|
77
vendor/github.com/coreos/go-systemd/CONTRIBUTING.md
generated
vendored
77
vendor/github.com/coreos/go-systemd/CONTRIBUTING.md
generated
vendored
@ -1,77 +0,0 @@
|
||||
# How to Contribute
|
||||
|
||||
CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via
|
||||
GitHub pull requests. This document outlines some of the conventions on
|
||||
development workflow, commit message formatting, contact points and other
|
||||
resources to make it easier to get your contribution accepted.
|
||||
|
||||
# Certificate of Origin
|
||||
|
||||
By contributing to this project you agree to the Developer Certificate of
|
||||
Origin (DCO). This document was created by the Linux Kernel community and is a
|
||||
simple statement that you, as a contributor, have the legal right to make the
|
||||
contribution. See the [DCO](DCO) file for details.
|
||||
|
||||
# Email and Chat
|
||||
|
||||
The project currently uses the general CoreOS email list and IRC channel:
|
||||
- Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev)
|
||||
- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
|
||||
|
||||
Please avoid emailing maintainers found in the MAINTAINERS file directly. They
|
||||
are very busy and read the mailing lists.
|
||||
|
||||
## Getting Started
|
||||
|
||||
- Fork the repository on GitHub
|
||||
- Read the [README](README.md) for build and test instructions
|
||||
- Play with the project, submit bugs, submit patches!
|
||||
|
||||
## Contribution Flow
|
||||
|
||||
This is a rough outline of what a contributor's workflow looks like:
|
||||
|
||||
- Create a topic branch from where you want to base your work (usually master).
|
||||
- Make commits of logical units.
|
||||
- Make sure your commit messages are in the proper format (see below).
|
||||
- Push your changes to a topic branch in your fork of the repository.
|
||||
- Make sure the tests pass, and add any new tests as appropriate.
|
||||
- Submit a pull request to the original repository.
|
||||
|
||||
Thanks for your contributions!
|
||||
|
||||
### Coding Style
|
||||
|
||||
CoreOS projects written in Go follow a set of style guidelines that we've documented
|
||||
[here](https://github.com/coreos/docs/tree/master/golang). Please follow them when
|
||||
working on your contributions.
|
||||
|
||||
### Format of the Commit Message
|
||||
|
||||
We follow a rough convention for commit messages that is designed to answer two
|
||||
questions: what changed and why. The subject line should feature the what and
|
||||
the body of the commit should describe the why.
|
||||
|
||||
```
|
||||
scripts: add the test-cluster command
|
||||
|
||||
this uses tmux to setup a test cluster that you can easily kill and
|
||||
start for debugging.
|
||||
|
||||
Fixes #38
|
||||
```
|
||||
|
||||
The format can be described more formally as follows:
|
||||
|
||||
```
|
||||
<subsystem>: <what changed>
|
||||
<BLANK LINE>
|
||||
<why this change was made>
|
||||
<BLANK LINE>
|
||||
<footer>
|
||||
```
|
||||
|
||||
The first line is the subject and should be no longer than 70 characters, the
|
||||
second line is always blank, and other lines should be wrapped at 80 characters.
|
||||
This allows the message to be easier to read on GitHub as well as in various
|
||||
git tools.
|
36
vendor/github.com/coreos/go-systemd/DCO
generated
vendored
36
vendor/github.com/coreos/go-systemd/DCO
generated
vendored
@ -1,36 +0,0 @@
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
191
vendor/github.com/coreos/go-systemd/LICENSE
generated
vendored
191
vendor/github.com/coreos/go-systemd/LICENSE
generated
vendored
@ -1,191 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
54
vendor/github.com/coreos/go-systemd/README.md
generated
vendored
54
vendor/github.com/coreos/go-systemd/README.md
generated
vendored
@ -1,54 +0,0 @@
|
||||
# go-systemd
|
||||
|
||||
[![Build Status](https://travis-ci.org/coreos/go-systemd.png?branch=master)](https://travis-ci.org/coreos/go-systemd)
|
||||
[![godoc](https://godoc.org/github.com/coreos/go-systemd?status.svg)](http://godoc.org/github.com/coreos/go-systemd)
|
||||
|
||||
Go bindings to systemd. The project has several packages:
|
||||
|
||||
- `activation` - for writing and using socket activation from Go
|
||||
- `dbus` - for starting/stopping/inspecting running services and units
|
||||
- `journal` - for writing to systemd's logging service, journald
|
||||
- `sdjournal` - for reading from journald by wrapping its C API
|
||||
- `machine1` - for registering machines/containers with systemd
|
||||
- `unit` - for (de)serialization and comparison of unit files
|
||||
|
||||
## Socket Activation
|
||||
|
||||
An example HTTP server using socket activation can be quickly set up by following this README on a Linux machine running systemd:
|
||||
|
||||
https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver
|
||||
|
||||
## Journal
|
||||
|
||||
Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry.
|
||||
The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available.
|
||||
|
||||
## D-Bus
|
||||
|
||||
The `dbus` package connects to the [systemd D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/dbus/) and lets you start, stop and introspect systemd units. The API docs are here:
|
||||
|
||||
http://godoc.org/github.com/coreos/go-systemd/dbus
|
||||
|
||||
### Debugging
|
||||
|
||||
Create `/etc/dbus-1/system-local.conf` that looks like this:
|
||||
|
||||
```
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow eavesdrop="true"/>
|
||||
<allow eavesdrop="true" send_destination="*"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
```
|
||||
|
||||
## machined
|
||||
|
||||
The `machine1` package allows interaction with the [systemd machined D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/machined/).
|
||||
|
||||
## Units
|
||||
|
||||
The `unit` package provides various functions for working with [systemd unit files](http://www.freedesktop.org/software/systemd/man/systemd.unit.html).
|
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
52
vendor/github.com/coreos/go-systemd/activation/files.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package activation implements primitives for systemd socket activation.
|
||||
package activation
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// based on: https://gist.github.com/alberts/4640792
|
||||
const (
|
||||
listenFdsStart = 3
|
||||
)
|
||||
|
||||
func Files(unsetEnv bool) []*os.File {
|
||||
if unsetEnv {
|
||||
defer os.Unsetenv("LISTEN_PID")
|
||||
defer os.Unsetenv("LISTEN_FDS")
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
|
||||
if err != nil || pid != os.Getpid() {
|
||||
return nil
|
||||
}
|
||||
|
||||
nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
|
||||
if err != nil || nfds == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
files := make([]*os.File, 0, nfds)
|
||||
for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
|
||||
syscall.CloseOnExec(fd)
|
||||
files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
82
vendor/github.com/coreos/go-systemd/activation/files_test.go
generated
vendored
82
vendor/github.com/coreos/go-systemd/activation/files_test.go
generated
vendored
@ -1,82 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// correctStringWritten fails the text if the correct string wasn't written
|
||||
// to the other side of the pipe.
|
||||
func correctStringWritten(t *testing.T, r *os.File, expected string) bool {
|
||||
bytes := make([]byte, len(expected))
|
||||
io.ReadAtLeast(r, bytes, len(expected))
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Unexpected string %s", string(bytes))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// TestActivation forks out a copy of activation.go example and reads back two
|
||||
// strings from the pipes that are passed in.
|
||||
func TestActivation(t *testing.T) {
|
||||
cmd := exec.Command("go", "run", "../examples/activation/activation.go")
|
||||
|
||||
r1, w1, _ := os.Pipe()
|
||||
r2, w2, _ := os.Pipe()
|
||||
cmd.ExtraFiles = []*os.File{
|
||||
w1,
|
||||
w2,
|
||||
}
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
correctStringWritten(t, r1, "Hello world")
|
||||
correctStringWritten(t, r2, "Goodbye world")
|
||||
}
|
||||
|
||||
func TestActivationNoFix(t *testing.T) {
|
||||
cmd := exec.Command("go", "run", "../examples/activation/activation.go")
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2")
|
||||
|
||||
out, _ := cmd.CombinedOutput()
|
||||
if bytes.Contains(out, []byte("No files")) == false {
|
||||
t.Fatalf("Child didn't error out as expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestActivationNoFiles(t *testing.T) {
|
||||
cmd := exec.Command("go", "run", "../examples/activation/activation.go")
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=0", "FIX_LISTEN_PID=1")
|
||||
|
||||
out, _ := cmd.CombinedOutput()
|
||||
if bytes.Contains(out, []byte("No files")) == false {
|
||||
t.Fatalf("Child didn't error out as expected")
|
||||
}
|
||||
}
|
62
vendor/github.com/coreos/go-systemd/activation/listeners.go
generated
vendored
62
vendor/github.com/coreos/go-systemd/activation/listeners.go
generated
vendored
@ -1,62 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Listeners returns a slice containing a net.Listener for each matching socket type
|
||||
// passed to this process.
|
||||
//
|
||||
// The order of the file descriptors is preserved in the returned slice.
|
||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||
// corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener}
|
||||
func Listeners(unsetEnv bool) ([]net.Listener, error) {
|
||||
files := Files(unsetEnv)
|
||||
listeners := make([]net.Listener, len(files))
|
||||
|
||||
for i, f := range files {
|
||||
if pc, err := net.FileListener(f); err == nil {
|
||||
listeners[i] = pc
|
||||
}
|
||||
}
|
||||
return listeners, nil
|
||||
}
|
||||
|
||||
// TLSListeners returns a slice containing a net.listener for each matching TCP socket type
|
||||
// passed to this process.
|
||||
// It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig.
|
||||
func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) {
|
||||
listeners, err := Listeners(unsetEnv)
|
||||
|
||||
if listeners == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tlsConfig != nil && err == nil {
|
||||
tlsConfig.NextProtos = []string{"http/1.1"}
|
||||
|
||||
for i, l := range listeners {
|
||||
// Activate TLS only for TCP sockets
|
||||
if l.Addr().Network() == "tcp" {
|
||||
listeners[i] = tls.NewListener(l, tlsConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listeners, err
|
||||
}
|
86
vendor/github.com/coreos/go-systemd/activation/listeners_test.go
generated
vendored
86
vendor/github.com/coreos/go-systemd/activation/listeners_test.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// correctStringWritten fails the text if the correct string wasn't written
|
||||
// to the other side of the pipe.
|
||||
func correctStringWrittenNet(t *testing.T, r net.Conn, expected string) bool {
|
||||
bytes := make([]byte, len(expected))
|
||||
io.ReadAtLeast(r, bytes, len(expected))
|
||||
|
||||
if string(bytes) != expected {
|
||||
t.Fatalf("Unexpected string %s", string(bytes))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// TestActivation forks out a copy of activation.go example and reads back two
|
||||
// strings from the pipes that are passed in.
|
||||
func TestListeners(t *testing.T) {
|
||||
cmd := exec.Command("go", "run", "../examples/activation/listen.go")
|
||||
|
||||
l1, err := net.Listen("tcp", ":9999")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
l2, err := net.Listen("tcp", ":1234")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
t1 := l1.(*net.TCPListener)
|
||||
t2 := l2.(*net.TCPListener)
|
||||
|
||||
f1, _ := t1.File()
|
||||
f2, _ := t2.File()
|
||||
|
||||
cmd.ExtraFiles = []*os.File{
|
||||
f1,
|
||||
f2,
|
||||
}
|
||||
|
||||
r1, err := net.Dial("tcp", "127.0.0.1:9999")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
r1.Write([]byte("Hi"))
|
||||
|
||||
r2, err := net.Dial("tcp", "127.0.0.1:1234")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
r2.Write([]byte("Hi"))
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
println(string(out))
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
correctStringWrittenNet(t, r1, "Hello world")
|
||||
correctStringWrittenNet(t, r2, "Goodbye world")
|
||||
}
|
37
vendor/github.com/coreos/go-systemd/activation/packetconns.go
generated
vendored
37
vendor/github.com/coreos/go-systemd/activation/packetconns.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// PacketConns returns a slice containing a net.PacketConn for each matching socket type
|
||||
// passed to this process.
|
||||
//
|
||||
// The order of the file descriptors is preserved in the returned slice.
|
||||
// Nil values are used to fill any gaps. For example if systemd were to return file descriptors
|
||||
// corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn}
|
||||
func PacketConns(unsetEnv bool) ([]net.PacketConn, error) {
|
||||
files := Files(unsetEnv)
|
||||
conns := make([]net.PacketConn, len(files))
|
||||
|
||||
for i, f := range files {
|
||||
if pc, err := net.FilePacketConn(f); err == nil {
|
||||
conns[i] = pc
|
||||
}
|
||||
}
|
||||
return conns, nil
|
||||
}
|
68
vendor/github.com/coreos/go-systemd/activation/packetconns_test.go
generated
vendored
68
vendor/github.com/coreos/go-systemd/activation/packetconns_test.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package activation
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestActivation forks out a copy of activation.go example and reads back two
|
||||
// strings from the pipes that are passed in.
|
||||
func TestPacketConns(t *testing.T) {
|
||||
cmd := exec.Command("go", "run", "../examples/activation/udpconn.go")
|
||||
|
||||
u1, err := net.ListenUDP("udp", &net.UDPAddr{Port: 9999})
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
u2, err := net.ListenUDP("udp", &net.UDPAddr{Port: 1234})
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
f1, _ := u1.File()
|
||||
f2, _ := u2.File()
|
||||
|
||||
cmd.ExtraFiles = []*os.File{
|
||||
f1,
|
||||
f2,
|
||||
}
|
||||
|
||||
r1, err := net.Dial("udp", "127.0.0.1:9999")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
r1.Write([]byte("Hi"))
|
||||
|
||||
r2, err := net.Dial("udp", "127.0.0.1:1234")
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
r2.Write([]byte("Hi"))
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
|
||||
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("Cmd output '%s', err: '%s'\n", out, err)
|
||||
}
|
||||
|
||||
correctStringWrittenNet(t, r1, "Hello world")
|
||||
correctStringWrittenNet(t, r2, "Goodbye world")
|
||||
}
|
31
vendor/github.com/coreos/go-systemd/daemon/sdnotify.go
generated
vendored
31
vendor/github.com/coreos/go-systemd/daemon/sdnotify.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
// Code forked from Docker project
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
var SdNotifyNoSocket = errors.New("No socket")
|
||||
|
||||
// SdNotify sends a message to the init daemon. It is common to ignore the error.
|
||||
func SdNotify(state string) error {
|
||||
socketAddr := &net.UnixAddr{
|
||||
Name: os.Getenv("NOTIFY_SOCKET"),
|
||||
Net: "unixgram",
|
||||
}
|
||||
|
||||
if socketAddr.Name == "" {
|
||||
return SdNotifyNoSocket
|
||||
}
|
||||
|
||||
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Write([]byte(state))
|
||||
return err
|
||||
}
|
198
vendor/github.com/coreos/go-systemd/dbus/dbus.go
generated
vendored
198
vendor/github.com/coreos/go-systemd/dbus/dbus.go
generated
vendored
@ -1,198 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Integration with the systemd D-Bus API. See http://www.freedesktop.org/wiki/Software/systemd/dbus/
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
const (
|
||||
alpha = `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
num = `0123456789`
|
||||
alphanum = alpha + num
|
||||
signalBuffer = 100
|
||||
)
|
||||
|
||||
// needsEscape checks whether a byte in a potential dbus ObjectPath needs to be escaped
|
||||
func needsEscape(i int, b byte) bool {
|
||||
// Escape everything that is not a-z-A-Z-0-9
|
||||
// Also escape 0-9 if it's the first character
|
||||
return strings.IndexByte(alphanum, b) == -1 ||
|
||||
(i == 0 && strings.IndexByte(num, b) != -1)
|
||||
}
|
||||
|
||||
// PathBusEscape sanitizes a constituent string of a dbus ObjectPath using the
|
||||
// rules that systemd uses for serializing special characters.
|
||||
func PathBusEscape(path string) string {
|
||||
// Special case the empty string
|
||||
if len(path) == 0 {
|
||||
return "_"
|
||||
}
|
||||
n := []byte{}
|
||||
for i := 0; i < len(path); i++ {
|
||||
c := path[i]
|
||||
if needsEscape(i, c) {
|
||||
e := fmt.Sprintf("_%x", c)
|
||||
n = append(n, []byte(e)...)
|
||||
} else {
|
||||
n = append(n, c)
|
||||
}
|
||||
}
|
||||
return string(n)
|
||||
}
|
||||
|
||||
// Conn is a connection to systemd's dbus endpoint.
|
||||
type Conn struct {
|
||||
// sysconn/sysobj are only used to call dbus methods
|
||||
sysconn *dbus.Conn
|
||||
sysobj dbus.BusObject
|
||||
|
||||
// sigconn/sigobj are only used to receive dbus signals
|
||||
sigconn *dbus.Conn
|
||||
sigobj dbus.BusObject
|
||||
|
||||
jobListener struct {
|
||||
jobs map[dbus.ObjectPath]chan<- string
|
||||
sync.Mutex
|
||||
}
|
||||
subscriber struct {
|
||||
updateCh chan<- *SubStateUpdate
|
||||
errCh chan<- error
|
||||
sync.Mutex
|
||||
ignore map[dbus.ObjectPath]int64
|
||||
cleanIgnore int64
|
||||
}
|
||||
}
|
||||
|
||||
// New establishes a connection to the system bus and authenticates.
|
||||
// Callers should call Close() when done with the connection.
|
||||
func New() (*Conn, error) {
|
||||
return newConnection(func() (*dbus.Conn, error) {
|
||||
return dbusAuthHelloConnection(dbus.SystemBusPrivate)
|
||||
})
|
||||
}
|
||||
|
||||
// NewUserConnection establishes a connection to the session bus and
|
||||
// authenticates. This can be used to connect to systemd user instances.
|
||||
// Callers should call Close() when done with the connection.
|
||||
func NewUserConnection() (*Conn, error) {
|
||||
return newConnection(func() (*dbus.Conn, error) {
|
||||
return dbusAuthHelloConnection(dbus.SessionBusPrivate)
|
||||
})
|
||||
}
|
||||
|
||||
// NewSystemdConnection establishes a private, direct connection to systemd.
|
||||
// This can be used for communicating with systemd without a dbus daemon.
|
||||
// Callers should call Close() when done with the connection.
|
||||
func NewSystemdConnection() (*Conn, error) {
|
||||
return newConnection(func() (*dbus.Conn, error) {
|
||||
// We skip Hello when talking directly to systemd.
|
||||
return dbusAuthConnection(func() (*dbus.Conn, error) {
|
||||
return dbus.Dial("unix:path=/run/systemd/private")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Close closes an established connection
|
||||
func (c *Conn) Close() {
|
||||
c.sysconn.Close()
|
||||
c.sigconn.Close()
|
||||
}
|
||||
|
||||
func newConnection(createBus func() (*dbus.Conn, error)) (*Conn, error) {
|
||||
sysconn, err := createBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigconn, err := createBus()
|
||||
if err != nil {
|
||||
sysconn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Conn{
|
||||
sysconn: sysconn,
|
||||
sysobj: systemdObject(sysconn),
|
||||
sigconn: sigconn,
|
||||
sigobj: systemdObject(sigconn),
|
||||
}
|
||||
|
||||
c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
|
||||
c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string)
|
||||
|
||||
// Setup the listeners on jobs so that we can get completions
|
||||
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
|
||||
|
||||
c.dispatch()
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetManagerProperty returns the value of a property on the org.freedesktop.systemd1.Manager
|
||||
// interface. The value is returned in its string representation, as defined at
|
||||
// https://developer.gnome.org/glib/unstable/gvariant-text.html
|
||||
func (c *Conn) GetManagerProperty(prop string) (string, error) {
|
||||
variant, err := c.sysobj.GetProperty("org.freedesktop.systemd1.Manager." + prop)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return variant.String(), nil
|
||||
}
|
||||
|
||||
func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
|
||||
conn, err := createBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Only use EXTERNAL method, and hardcode the uid (not username)
|
||||
// to avoid a username lookup (which requires a dynamically linked
|
||||
// libc)
|
||||
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
||||
|
||||
err = conn.Auth(methods)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) {
|
||||
conn, err := dbusAuthConnection(createBus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = conn.Hello(); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func systemdObject(conn *dbus.Conn) dbus.BusObject {
|
||||
return conn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
|
||||
}
|
77
vendor/github.com/coreos/go-systemd/dbus/dbus_test.go
generated
vendored
77
vendor/github.com/coreos/go-systemd/dbus/dbus_test.go
generated
vendored
@ -1,77 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNeedsEscape(t *testing.T) {
|
||||
// Anything not 0-9a-zA-Z should always be escaped
|
||||
for want, vals := range map[bool][]byte{
|
||||
false: []byte{'a', 'b', 'z', 'A', 'Q', '1', '4', '9'},
|
||||
true: []byte{'#', '%', '$', '!', '.', '_', '-', '%', '\\'},
|
||||
} {
|
||||
for i := 1; i < 10; i++ {
|
||||
for _, b := range vals {
|
||||
got := needsEscape(i, b)
|
||||
if got != want {
|
||||
t.Errorf("needsEscape(%d, %c) returned %t, want %t", i, b, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0-9 in position 0 should be escaped
|
||||
for want, vals := range map[bool][]byte{
|
||||
false: []byte{'A', 'a', 'e', 'x', 'Q', 'Z'},
|
||||
true: []byte{'0', '4', '5', '9'},
|
||||
} {
|
||||
for _, b := range vals {
|
||||
got := needsEscape(0, b)
|
||||
if got != want {
|
||||
t.Errorf("needsEscape(0, %c) returned %t, want %t", b, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPathBusEscape(t *testing.T) {
|
||||
for in, want := range map[string]string{
|
||||
"": "_",
|
||||
"foo.service": "foo_2eservice",
|
||||
"foobar": "foobar",
|
||||
"woof@woof.service": "woof_40woof_2eservice",
|
||||
"0123456": "_30123456",
|
||||
"account_db.service": "account_5fdb_2eservice",
|
||||
"got-dashes": "got_2ddashes",
|
||||
} {
|
||||
got := PathBusEscape(in)
|
||||
if got != want {
|
||||
t.Errorf("bad result for PathBusEscape(%s): got %q, want %q", in, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TestNew ensures that New() works without errors.
|
||||
func TestNew(t *testing.T) {
|
||||
_, err := New()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
442
vendor/github.com/coreos/go-systemd/dbus/methods.go
generated
vendored
442
vendor/github.com/coreos/go-systemd/dbus/methods.go
generated
vendored
@ -1,442 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
func (c *Conn) jobComplete(signal *dbus.Signal) {
|
||||
var id uint32
|
||||
var job dbus.ObjectPath
|
||||
var unit string
|
||||
var result string
|
||||
dbus.Store(signal.Body, &id, &job, &unit, &result)
|
||||
c.jobListener.Lock()
|
||||
out, ok := c.jobListener.jobs[job]
|
||||
if ok {
|
||||
out <- result
|
||||
delete(c.jobListener.jobs, job)
|
||||
}
|
||||
c.jobListener.Unlock()
|
||||
}
|
||||
|
||||
func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) {
|
||||
if ch != nil {
|
||||
c.jobListener.Lock()
|
||||
defer c.jobListener.Unlock()
|
||||
}
|
||||
|
||||
var p dbus.ObjectPath
|
||||
err := c.sysobj.Call(job, 0, args...).Store(&p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if ch != nil {
|
||||
c.jobListener.jobs[p] = ch
|
||||
}
|
||||
|
||||
// ignore error since 0 is fine if conversion fails
|
||||
jobID, _ := strconv.Atoi(path.Base(string(p)))
|
||||
|
||||
return jobID, nil
|
||||
}
|
||||
|
||||
// StartUnit enqueues a start job and depending jobs, if any (unless otherwise
|
||||
// specified by the mode string).
|
||||
//
|
||||
// Takes the unit to activate, plus a mode string. The mode needs to be one of
|
||||
// replace, fail, isolate, ignore-dependencies, ignore-requirements. If
|
||||
// "replace" the call will start the unit and its dependencies, possibly
|
||||
// replacing already queued jobs that conflict with this. If "fail" the call
|
||||
// will start the unit and its dependencies, but will fail if this would change
|
||||
// an already queued job. If "isolate" the call will start the unit in question
|
||||
// and terminate all units that aren't dependencies of it. If
|
||||
// "ignore-dependencies" it will start a unit but ignore all its dependencies.
|
||||
// If "ignore-requirements" it will start a unit but only ignore the
|
||||
// requirement dependencies. It is not recommended to make use of the latter
|
||||
// two options.
|
||||
//
|
||||
// If the provided channel is non-nil, a result string will be sent to it upon
|
||||
// job completion: one of done, canceled, timeout, failed, dependency, skipped.
|
||||
// done indicates successful execution of a job. canceled indicates that a job
|
||||
// has been canceled before it finished execution. timeout indicates that the
|
||||
// job timeout was reached. failed indicates that the job failed. dependency
|
||||
// indicates that a job this job has been depending on failed and the job hence
|
||||
// has been removed too. skipped indicates that a job was skipped because it
|
||||
// didn't apply to the units current state.
|
||||
//
|
||||
// If no error occurs, the ID of the underlying systemd job will be returned. There
|
||||
// does exist the possibility for no error to be returned, but for the returned job
|
||||
// ID to be 0. In this case, the actual underlying ID is not 0 and this datapoint
|
||||
// should not be considered authoritative.
|
||||
//
|
||||
// If an error does occur, it will be returned to the user alongside a job ID of 0.
|
||||
func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
|
||||
}
|
||||
|
||||
// StopUnit is similar to StartUnit but stops the specified unit rather
|
||||
// than starting it.
|
||||
func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
|
||||
}
|
||||
|
||||
// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise.
|
||||
func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
|
||||
}
|
||||
|
||||
// RestartUnit restarts a service. If a service is restarted that isn't
|
||||
// running it will be started.
|
||||
func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
|
||||
}
|
||||
|
||||
// TryRestartUnit is like RestartUnit, except that a service that isn't running
|
||||
// is not affected by the restart.
|
||||
func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
|
||||
}
|
||||
|
||||
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
|
||||
// otherwise.
|
||||
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
|
||||
}
|
||||
|
||||
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
|
||||
// flavored restart otherwise.
|
||||
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
|
||||
}
|
||||
|
||||
// StartTransientUnit() may be used to create and start a transient unit, which
|
||||
// will be released as soon as it is not running or referenced anymore or the
|
||||
// system is rebooted. name is the unit name including suffix, and must be
|
||||
// unique. mode is the same as in StartUnit(), properties contains properties
|
||||
// of the unit.
|
||||
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
|
||||
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
|
||||
}
|
||||
|
||||
// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's
|
||||
// processes are killed.
|
||||
func (c *Conn) KillUnit(name string, signal int32) {
|
||||
c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
|
||||
}
|
||||
|
||||
// ResetFailedUnit resets the "failed" state of a specific unit.
|
||||
func (c *Conn) ResetFailedUnit(name string) error {
|
||||
return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
|
||||
}
|
||||
|
||||
// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface
|
||||
func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
|
||||
var err error
|
||||
var props map[string]dbus.Variant
|
||||
|
||||
path := unitPath(unit)
|
||||
if !path.IsValid() {
|
||||
return nil, errors.New("invalid unit name: " + unit)
|
||||
}
|
||||
|
||||
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
|
||||
err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(map[string]interface{}, len(props))
|
||||
for k, v := range props {
|
||||
out[k] = v.Value()
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GetUnitProperties takes the unit name and returns all of its dbus object properties.
|
||||
func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
|
||||
return c.getProperties(unit, "org.freedesktop.systemd1.Unit")
|
||||
}
|
||||
|
||||
func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) {
|
||||
var err error
|
||||
var prop dbus.Variant
|
||||
|
||||
path := unitPath(unit)
|
||||
if !path.IsValid() {
|
||||
return nil, errors.New("invalid unit name: " + unit)
|
||||
}
|
||||
|
||||
obj := c.sysconn.Object("org.freedesktop.systemd1", path)
|
||||
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Property{Name: propertyName, Value: prop}, nil
|
||||
}
|
||||
|
||||
func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) {
|
||||
return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName)
|
||||
}
|
||||
|
||||
// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type.
|
||||
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope
|
||||
// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit
|
||||
func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) {
|
||||
return c.getProperties(unit, "org.freedesktop.systemd1."+unitType)
|
||||
}
|
||||
|
||||
// SetUnitProperties() may be used to modify certain unit properties at runtime.
|
||||
// Not all properties may be changed at runtime, but many resource management
|
||||
// settings (primarily those in systemd.cgroup(5)) may. The changes are applied
|
||||
// instantly, and stored on disk for future boots, unless runtime is true, in which
|
||||
// case the settings only apply until the next reboot. name is the name of the unit
|
||||
// to modify. properties are the settings to set, encoded as an array of property
|
||||
// name and value pairs.
|
||||
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
|
||||
return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store()
|
||||
}
|
||||
|
||||
func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
|
||||
return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName)
|
||||
}
|
||||
|
||||
type UnitStatus struct {
|
||||
Name string // The primary unit name as string
|
||||
Description string // The human readable description string
|
||||
LoadState string // The load state (i.e. whether the unit file has been loaded successfully)
|
||||
ActiveState string // The active state (i.e. whether the unit is currently started or not)
|
||||
SubState string // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not)
|
||||
Followed string // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string.
|
||||
Path dbus.ObjectPath // The unit object path
|
||||
JobId uint32 // If there is a job queued for the job unit the numeric job id, 0 otherwise
|
||||
JobType string // The job type as string
|
||||
JobPath dbus.ObjectPath // The job object path
|
||||
}
|
||||
|
||||
// ListUnits returns an array with all currently loaded units. Note that
|
||||
// units may be known by multiple names at the same time, and hence there might
|
||||
// be more unit names loaded than actual units behind them.
|
||||
func (c *Conn) ListUnits() ([]UnitStatus, error) {
|
||||
result := make([][]interface{}, 0)
|
||||
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultInterface := make([]interface{}, len(result))
|
||||
for i := range result {
|
||||
resultInterface[i] = result[i]
|
||||
}
|
||||
|
||||
status := make([]UnitStatus, len(result))
|
||||
statusInterface := make([]interface{}, len(status))
|
||||
for i := range status {
|
||||
statusInterface[i] = &status[i]
|
||||
}
|
||||
|
||||
err = dbus.Store(resultInterface, statusInterface...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return status, nil
|
||||
}
|
||||
|
||||
type UnitFile struct {
|
||||
Path string
|
||||
Type string
|
||||
}
|
||||
|
||||
// ListUnitFiles returns an array of all available units on disk.
|
||||
func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
|
||||
result := make([][]interface{}, 0)
|
||||
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultInterface := make([]interface{}, len(result))
|
||||
for i := range result {
|
||||
resultInterface[i] = result[i]
|
||||
}
|
||||
|
||||
files := make([]UnitFile, len(result))
|
||||
fileInterface := make([]interface{}, len(files))
|
||||
for i := range files {
|
||||
fileInterface[i] = &files[i]
|
||||
}
|
||||
|
||||
err = dbus.Store(resultInterface, fileInterface...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
type LinkUnitFileChange EnableUnitFileChange
|
||||
|
||||
// LinkUnitFiles() links unit files (that are located outside of the
|
||||
// usual unit search paths) into the unit search path.
|
||||
//
|
||||
// It takes a list of absolute paths to unit files to link and two
|
||||
// booleans. The first boolean controls whether the unit shall be
|
||||
// enabled for runtime only (true, /run), or persistently (false,
|
||||
// /etc).
|
||||
// The second controls whether symlinks pointing to other units shall
|
||||
// be replaced if necessary.
|
||||
//
|
||||
// This call returns a list of the changes made. The list consists of
|
||||
// structures with three strings: the type of the change (one of symlink
|
||||
// or unlink), the file name of the symlink and the destination of the
|
||||
// symlink.
|
||||
func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
|
||||
result := make([][]interface{}, 0)
|
||||
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultInterface := make([]interface{}, len(result))
|
||||
for i := range result {
|
||||
resultInterface[i] = result[i]
|
||||
}
|
||||
|
||||
changes := make([]LinkUnitFileChange, len(result))
|
||||
changesInterface := make([]interface{}, len(changes))
|
||||
for i := range changes {
|
||||
changesInterface[i] = &changes[i]
|
||||
}
|
||||
|
||||
err = dbus.Store(resultInterface, changesInterface...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
// EnableUnitFiles() may be used to enable one or more units in the system (by
|
||||
// creating symlinks to them in /etc or /run).
|
||||
//
|
||||
// It takes a list of unit files to enable (either just file names or full
|
||||
// absolute paths if the unit files are residing outside the usual unit
|
||||
// search paths), and two booleans: the first controls whether the unit shall
|
||||
// be enabled for runtime only (true, /run), or persistently (false, /etc).
|
||||
// The second one controls whether symlinks pointing to other units shall
|
||||
// be replaced if necessary.
|
||||
//
|
||||
// This call returns one boolean and an array with the changes made. The
|
||||
// boolean signals whether the unit files contained any enablement
|
||||
// information (i.e. an [Install]) section. The changes list consists of
|
||||
// structures with three strings: the type of the change (one of symlink
|
||||
// or unlink), the file name of the symlink and the destination of the
|
||||
// symlink.
|
||||
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
|
||||
var carries_install_info bool
|
||||
|
||||
result := make([][]interface{}, 0)
|
||||
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
resultInterface := make([]interface{}, len(result))
|
||||
for i := range result {
|
||||
resultInterface[i] = result[i]
|
||||
}
|
||||
|
||||
changes := make([]EnableUnitFileChange, len(result))
|
||||
changesInterface := make([]interface{}, len(changes))
|
||||
for i := range changes {
|
||||
changesInterface[i] = &changes[i]
|
||||
}
|
||||
|
||||
err = dbus.Store(resultInterface, changesInterface...)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return carries_install_info, changes, nil
|
||||
}
|
||||
|
||||
type EnableUnitFileChange struct {
|
||||
Type string // Type of the change (one of symlink or unlink)
|
||||
Filename string // File name of the symlink
|
||||
Destination string // Destination of the symlink
|
||||
}
|
||||
|
||||
// DisableUnitFiles() may be used to disable one or more units in the system (by
|
||||
// removing symlinks to them from /etc or /run).
|
||||
//
|
||||
// It takes a list of unit files to disable (either just file names or full
|
||||
// absolute paths if the unit files are residing outside the usual unit
|
||||
// search paths), and one boolean: whether the unit was enabled for runtime
|
||||
// only (true, /run), or persistently (false, /etc).
|
||||
//
|
||||
// This call returns an array with the changes made. The changes list
|
||||
// consists of structures with three strings: the type of the change (one of
|
||||
// symlink or unlink), the file name of the symlink and the destination of the
|
||||
// symlink.
|
||||
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
|
||||
result := make([][]interface{}, 0)
|
||||
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultInterface := make([]interface{}, len(result))
|
||||
for i := range result {
|
||||
resultInterface[i] = result[i]
|
||||
}
|
||||
|
||||
changes := make([]DisableUnitFileChange, len(result))
|
||||
changesInterface := make([]interface{}, len(changes))
|
||||
for i := range changes {
|
||||
changesInterface[i] = &changes[i]
|
||||
}
|
||||
|
||||
err = dbus.Store(resultInterface, changesInterface...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
type DisableUnitFileChange struct {
|
||||
Type string // Type of the change (one of symlink or unlink)
|
||||
Filename string // File name of the symlink
|
||||
Destination string // Destination of the symlink
|
||||
}
|
||||
|
||||
// Reload instructs systemd to scan for and reload unit files. This is
|
||||
// equivalent to a 'systemctl daemon-reload'.
|
||||
func (c *Conn) Reload() error {
|
||||
return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
|
||||
}
|
||||
|
||||
func unitPath(name string) dbus.ObjectPath {
|
||||
return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name))
|
||||
}
|
345
vendor/github.com/coreos/go-systemd/dbus/methods_test.go
generated
vendored
345
vendor/github.com/coreos/go-systemd/dbus/methods_test.go
generated
vendored
@ -1,345 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
func setupConn(t *testing.T) *Conn {
|
||||
conn, err := New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
func findFixture(target string, t *testing.T) string {
|
||||
abs, err := filepath.Abs("../fixtures/" + target)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
func setupUnit(target string, conn *Conn, t *testing.T) {
|
||||
// Blindly stop the unit in case it is running
|
||||
conn.StopUnit(target, "replace", nil)
|
||||
|
||||
// Blindly remove the symlink in case it exists
|
||||
targetRun := filepath.Join("/run/systemd/system/", target)
|
||||
os.Remove(targetRun)
|
||||
}
|
||||
|
||||
func linkUnit(target string, conn *Conn, t *testing.T) {
|
||||
abs := findFixture(target, t)
|
||||
fixture := []string{abs}
|
||||
|
||||
changes, err := conn.LinkUnitFiles(fixture, true, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(changes) < 1 {
|
||||
t.Fatalf("Expected one change, got %v", changes)
|
||||
}
|
||||
|
||||
runPath := filepath.Join("/run/systemd/system/", target)
|
||||
if changes[0].Filename != runPath {
|
||||
t.Fatal("Unexpected target filename")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that basic unit starting and stopping works.
|
||||
func TestStartStopUnit(t *testing.T) {
|
||||
target := "start-stop.service"
|
||||
conn := setupConn(t)
|
||||
|
||||
setupUnit(target, conn, t)
|
||||
linkUnit(target, conn, t)
|
||||
|
||||
// 2. Start the unit
|
||||
reschan := make(chan string)
|
||||
_, err := conn.StartUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
job := <-reschan
|
||||
if job != "done" {
|
||||
t.Fatal("Job is not done:", job)
|
||||
}
|
||||
|
||||
units, err := conn.ListUnits()
|
||||
|
||||
var unit *UnitStatus
|
||||
for _, u := range units {
|
||||
if u.Name == target {
|
||||
unit = &u
|
||||
}
|
||||
}
|
||||
|
||||
if unit == nil {
|
||||
t.Fatalf("Test unit not found in list")
|
||||
}
|
||||
|
||||
if unit.ActiveState != "active" {
|
||||
t.Fatalf("Test unit not active")
|
||||
}
|
||||
|
||||
// 3. Stop the unit
|
||||
_, err = conn.StopUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait for StopUnit job to complete
|
||||
<-reschan
|
||||
|
||||
units, err = conn.ListUnits()
|
||||
|
||||
unit = nil
|
||||
for _, u := range units {
|
||||
if u.Name == target {
|
||||
unit = &u
|
||||
}
|
||||
}
|
||||
|
||||
if unit != nil {
|
||||
t.Fatalf("Test unit found in list, should be stopped")
|
||||
}
|
||||
}
|
||||
|
||||
// Enables a unit and then immediately tears it down
|
||||
func TestEnableDisableUnit(t *testing.T) {
|
||||
target := "enable-disable.service"
|
||||
conn := setupConn(t)
|
||||
|
||||
setupUnit(target, conn, t)
|
||||
abs := findFixture(target, t)
|
||||
runPath := filepath.Join("/run/systemd/system/", target)
|
||||
|
||||
// 1. Enable the unit
|
||||
install, changes, err := conn.EnableUnitFiles([]string{abs}, true, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if install != false {
|
||||
t.Fatal("Install was true")
|
||||
}
|
||||
|
||||
if len(changes) < 1 {
|
||||
t.Fatalf("Expected one change, got %v", changes)
|
||||
}
|
||||
|
||||
if changes[0].Filename != runPath {
|
||||
t.Fatal("Unexpected target filename")
|
||||
}
|
||||
|
||||
// 2. Disable the unit
|
||||
dChanges, err := conn.DisableUnitFiles([]string{abs}, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(dChanges) != 1 {
|
||||
t.Fatalf("Changes should include the path, %v", dChanges)
|
||||
}
|
||||
if dChanges[0].Filename != runPath {
|
||||
t.Fatalf("Change should include correct filename, %+v", dChanges[0])
|
||||
}
|
||||
if dChanges[0].Destination != "" {
|
||||
t.Fatalf("Change destination should be empty, %+v", dChanges[0])
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetUnitProperties reads the `-.mount` which should exist on all systemd
|
||||
// systems and ensures that one of its properties is valid.
|
||||
func TestGetUnitProperties(t *testing.T) {
|
||||
conn := setupConn(t)
|
||||
|
||||
unit := "-.mount"
|
||||
|
||||
info, err := conn.GetUnitProperties(unit)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
names := info["Wants"].([]string)
|
||||
|
||||
if len(names) < 1 {
|
||||
t.Fatal("/ is unwanted")
|
||||
}
|
||||
|
||||
if names[0] != "system.slice" {
|
||||
t.Fatal("unexpected wants for /")
|
||||
}
|
||||
|
||||
prop, err := conn.GetUnitProperty(unit, "Wants")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if prop.Name != "Wants" {
|
||||
t.Fatal("unexpected property name")
|
||||
}
|
||||
|
||||
val := prop.Value.Value().([]string)
|
||||
if !reflect.DeepEqual(val, names) {
|
||||
t.Fatal("unexpected property value")
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetUnitPropertiesRejectsInvalidName attempts to get the properties for a
|
||||
// unit with an invalid name. This test should be run with --test.timeout set,
|
||||
// as a fail will manifest as GetUnitProperties hanging indefinitely.
|
||||
func TestGetUnitPropertiesRejectsInvalidName(t *testing.T) {
|
||||
conn := setupConn(t)
|
||||
|
||||
unit := "//invalid#$^/"
|
||||
|
||||
_, err := conn.GetUnitProperties(unit)
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error, got nil")
|
||||
}
|
||||
|
||||
_, err = conn.GetUnitProperty(unit, "Wants")
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSetUnitProperties changes a cgroup setting on the `tmp.mount`
|
||||
// which should exist on all systemd systems and ensures that the
|
||||
// property was set.
|
||||
func TestSetUnitProperties(t *testing.T) {
|
||||
conn := setupConn(t)
|
||||
|
||||
unit := "tmp.mount"
|
||||
|
||||
if err := conn.SetUnitProperties(unit, true, Property{"CPUShares", dbus.MakeVariant(uint64(1023))}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := conn.GetUnitTypeProperties(unit, "Mount")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value := info["CPUShares"].(uint64)
|
||||
if value != 1023 {
|
||||
t.Fatal("CPUShares of unit is not 1023:", value)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that basic transient unit starting and stopping works.
|
||||
func TestStartStopTransientUnit(t *testing.T) {
|
||||
conn := setupConn(t)
|
||||
|
||||
props := []Property{
|
||||
PropExecStart([]string{"/bin/sleep", "400"}, false),
|
||||
}
|
||||
target := fmt.Sprintf("testing-transient-%d.service", rand.Int())
|
||||
|
||||
// Start the unit
|
||||
reschan := make(chan string)
|
||||
_, err := conn.StartTransientUnit(target, "replace", props, reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
job := <-reschan
|
||||
if job != "done" {
|
||||
t.Fatal("Job is not done:", job)
|
||||
}
|
||||
|
||||
units, err := conn.ListUnits()
|
||||
|
||||
var unit *UnitStatus
|
||||
for _, u := range units {
|
||||
if u.Name == target {
|
||||
unit = &u
|
||||
}
|
||||
}
|
||||
|
||||
if unit == nil {
|
||||
t.Fatalf("Test unit not found in list")
|
||||
}
|
||||
|
||||
if unit.ActiveState != "active" {
|
||||
t.Fatalf("Test unit not active")
|
||||
}
|
||||
|
||||
// 3. Stop the unit
|
||||
_, err = conn.StopUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait for StopUnit job to complete
|
||||
<-reschan
|
||||
|
||||
units, err = conn.ListUnits()
|
||||
|
||||
unit = nil
|
||||
for _, u := range units {
|
||||
if u.Name == target {
|
||||
unit = &u
|
||||
}
|
||||
}
|
||||
|
||||
if unit != nil {
|
||||
t.Fatalf("Test unit found in list, should be stopped")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnJobListener(t *testing.T) {
|
||||
target := "start-stop.service"
|
||||
conn := setupConn(t)
|
||||
|
||||
setupUnit(target, conn, t)
|
||||
linkUnit(target, conn, t)
|
||||
|
||||
jobSize := len(conn.jobListener.jobs)
|
||||
|
||||
reschan := make(chan string)
|
||||
_, err := conn.StartUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
<-reschan
|
||||
|
||||
_, err = conn.StopUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
<-reschan
|
||||
|
||||
currentJobSize := len(conn.jobListener.jobs)
|
||||
if jobSize != currentJobSize {
|
||||
t.Fatal("JobListener jobs leaked")
|
||||
}
|
||||
}
|
218
vendor/github.com/coreos/go-systemd/dbus/properties.go
generated
vendored
218
vendor/github.com/coreos/go-systemd/dbus/properties.go
generated
vendored
@ -1,218 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
// From the systemd docs:
|
||||
//
|
||||
// The properties array of StartTransientUnit() may take many of the settings
|
||||
// that may also be configured in unit files. Not all parameters are currently
|
||||
// accepted though, but we plan to cover more properties with future release.
|
||||
// Currently you may set the Description, Slice and all dependency types of
|
||||
// units, as well as RemainAfterExit, ExecStart for service units,
|
||||
// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares,
|
||||
// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth,
|
||||
// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit,
|
||||
// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map
|
||||
// directly to their counterparts in unit files and as normal D-Bus object
|
||||
// properties. The exception here is the PIDs field of scope units which is
|
||||
// used for construction of the scope only and specifies the initial PIDs to
|
||||
// add to the scope object.
|
||||
|
||||
type Property struct {
|
||||
Name string
|
||||
Value dbus.Variant
|
||||
}
|
||||
|
||||
type PropertyCollection struct {
|
||||
Name string
|
||||
Properties []Property
|
||||
}
|
||||
|
||||
type execStart struct {
|
||||
Path string // the binary path to execute
|
||||
Args []string // an array with all arguments to pass to the executed command, starting with argument 0
|
||||
UncleanIsFailure bool // a boolean whether it should be considered a failure if the process exits uncleanly
|
||||
}
|
||||
|
||||
// PropExecStart sets the ExecStart service property. The first argument is a
|
||||
// slice with the binary path to execute followed by the arguments to pass to
|
||||
// the executed command. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
|
||||
func PropExecStart(command []string, uncleanIsFailure bool) Property {
|
||||
execStarts := []execStart{
|
||||
execStart{
|
||||
Path: command[0],
|
||||
Args: command,
|
||||
UncleanIsFailure: uncleanIsFailure,
|
||||
},
|
||||
}
|
||||
|
||||
return Property{
|
||||
Name: "ExecStart",
|
||||
Value: dbus.MakeVariant(execStarts),
|
||||
}
|
||||
}
|
||||
|
||||
// PropRemainAfterExit sets the RemainAfterExit service property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit=
|
||||
func PropRemainAfterExit(b bool) Property {
|
||||
return Property{
|
||||
Name: "RemainAfterExit",
|
||||
Value: dbus.MakeVariant(b),
|
||||
}
|
||||
}
|
||||
|
||||
// PropDescription sets the Description unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description=
|
||||
func PropDescription(desc string) Property {
|
||||
return Property{
|
||||
Name: "Description",
|
||||
Value: dbus.MakeVariant(desc),
|
||||
}
|
||||
}
|
||||
|
||||
func propDependency(name string, units []string) Property {
|
||||
return Property{
|
||||
Name: name,
|
||||
Value: dbus.MakeVariant(units),
|
||||
}
|
||||
}
|
||||
|
||||
// PropRequires sets the Requires unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires=
|
||||
func PropRequires(units ...string) Property {
|
||||
return propDependency("Requires", units)
|
||||
}
|
||||
|
||||
// PropRequiresOverridable sets the RequiresOverridable unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable=
|
||||
func PropRequiresOverridable(units ...string) Property {
|
||||
return propDependency("RequiresOverridable", units)
|
||||
}
|
||||
|
||||
// PropRequisite sets the Requisite unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite=
|
||||
func PropRequisite(units ...string) Property {
|
||||
return propDependency("Requisite", units)
|
||||
}
|
||||
|
||||
// PropRequisiteOverridable sets the RequisiteOverridable unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable=
|
||||
func PropRequisiteOverridable(units ...string) Property {
|
||||
return propDependency("RequisiteOverridable", units)
|
||||
}
|
||||
|
||||
// PropWants sets the Wants unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants=
|
||||
func PropWants(units ...string) Property {
|
||||
return propDependency("Wants", units)
|
||||
}
|
||||
|
||||
// PropBindsTo sets the BindsTo unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo=
|
||||
func PropBindsTo(units ...string) Property {
|
||||
return propDependency("BindsTo", units)
|
||||
}
|
||||
|
||||
// PropRequiredBy sets the RequiredBy unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy=
|
||||
func PropRequiredBy(units ...string) Property {
|
||||
return propDependency("RequiredBy", units)
|
||||
}
|
||||
|
||||
// PropRequiredByOverridable sets the RequiredByOverridable unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable=
|
||||
func PropRequiredByOverridable(units ...string) Property {
|
||||
return propDependency("RequiredByOverridable", units)
|
||||
}
|
||||
|
||||
// PropWantedBy sets the WantedBy unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy=
|
||||
func PropWantedBy(units ...string) Property {
|
||||
return propDependency("WantedBy", units)
|
||||
}
|
||||
|
||||
// PropBoundBy sets the BoundBy unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy=
|
||||
func PropBoundBy(units ...string) Property {
|
||||
return propDependency("BoundBy", units)
|
||||
}
|
||||
|
||||
// PropConflicts sets the Conflicts unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts=
|
||||
func PropConflicts(units ...string) Property {
|
||||
return propDependency("Conflicts", units)
|
||||
}
|
||||
|
||||
// PropConflictedBy sets the ConflictedBy unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy=
|
||||
func PropConflictedBy(units ...string) Property {
|
||||
return propDependency("ConflictedBy", units)
|
||||
}
|
||||
|
||||
// PropBefore sets the Before unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before=
|
||||
func PropBefore(units ...string) Property {
|
||||
return propDependency("Before", units)
|
||||
}
|
||||
|
||||
// PropAfter sets the After unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After=
|
||||
func PropAfter(units ...string) Property {
|
||||
return propDependency("After", units)
|
||||
}
|
||||
|
||||
// PropOnFailure sets the OnFailure unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure=
|
||||
func PropOnFailure(units ...string) Property {
|
||||
return propDependency("OnFailure", units)
|
||||
}
|
||||
|
||||
// PropTriggers sets the Triggers unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers=
|
||||
func PropTriggers(units ...string) Property {
|
||||
return propDependency("Triggers", units)
|
||||
}
|
||||
|
||||
// PropTriggeredBy sets the TriggeredBy unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy=
|
||||
func PropTriggeredBy(units ...string) Property {
|
||||
return propDependency("TriggeredBy", units)
|
||||
}
|
||||
|
||||
// PropPropagatesReloadTo sets the PropagatesReloadTo unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo=
|
||||
func PropPropagatesReloadTo(units ...string) Property {
|
||||
return propDependency("PropagatesReloadTo", units)
|
||||
}
|
||||
|
||||
// PropRequiresMountsFor sets the RequiresMountsFor unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor=
|
||||
func PropRequiresMountsFor(units ...string) Property {
|
||||
return propDependency("RequiresMountsFor", units)
|
||||
}
|
||||
|
||||
// PropSlice sets the Slice unit property. See
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice=
|
||||
func PropSlice(slice string) Property {
|
||||
return Property{
|
||||
Name: "Slice",
|
||||
Value: dbus.MakeVariant(slice),
|
||||
}
|
||||
}
|
47
vendor/github.com/coreos/go-systemd/dbus/set.go
generated
vendored
47
vendor/github.com/coreos/go-systemd/dbus/set.go
generated
vendored
@ -1,47 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
type set struct {
|
||||
data map[string]bool
|
||||
}
|
||||
|
||||
func (s *set) Add(value string) {
|
||||
s.data[value] = true
|
||||
}
|
||||
|
||||
func (s *set) Remove(value string) {
|
||||
delete(s.data, value)
|
||||
}
|
||||
|
||||
func (s *set) Contains(value string) (exists bool) {
|
||||
_, exists = s.data[value]
|
||||
return
|
||||
}
|
||||
|
||||
func (s *set) Length() int {
|
||||
return len(s.data)
|
||||
}
|
||||
|
||||
func (s *set) Values() (values []string) {
|
||||
for val, _ := range s.data {
|
||||
values = append(values, val)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func newSet() *set {
|
||||
return &set{make(map[string]bool)}
|
||||
}
|
53
vendor/github.com/coreos/go-systemd/dbus/set_test.go
generated
vendored
53
vendor/github.com/coreos/go-systemd/dbus/set_test.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestBasicSetActions asserts that Add & Remove behavior is correct
|
||||
func TestBasicSetActions(t *testing.T) {
|
||||
s := newSet()
|
||||
|
||||
if s.Contains("foo") {
|
||||
t.Fatal("set should not contain 'foo'")
|
||||
}
|
||||
|
||||
s.Add("foo")
|
||||
|
||||
if !s.Contains("foo") {
|
||||
t.Fatal("set should contain 'foo'")
|
||||
}
|
||||
|
||||
v := s.Values()
|
||||
if len(v) != 1 {
|
||||
t.Fatal("set.Values did not report correct number of values")
|
||||
}
|
||||
if v[0] != "foo" {
|
||||
t.Fatal("set.Values did not report value")
|
||||
}
|
||||
|
||||
s.Remove("foo")
|
||||
|
||||
if s.Contains("foo") {
|
||||
t.Fatal("set should not contain 'foo'")
|
||||
}
|
||||
|
||||
v = s.Values()
|
||||
if len(v) != 0 {
|
||||
t.Fatal("set.Values did not report correct number of values")
|
||||
}
|
||||
}
|
250
vendor/github.com/coreos/go-systemd/dbus/subscription.go
generated
vendored
250
vendor/github.com/coreos/go-systemd/dbus/subscription.go
generated
vendored
@ -1,250 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
const (
|
||||
cleanIgnoreInterval = int64(10 * time.Second)
|
||||
ignoreInterval = int64(30 * time.Millisecond)
|
||||
)
|
||||
|
||||
// Subscribe sets up this connection to subscribe to all systemd dbus events.
|
||||
// This is required before calling SubscribeUnits. When the connection closes
|
||||
// systemd will automatically stop sending signals so there is no need to
|
||||
// explicitly call Unsubscribe().
|
||||
func (c *Conn) Subscribe() error {
|
||||
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
|
||||
c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
|
||||
|
||||
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unsubscribe this connection from systemd dbus events.
|
||||
func (c *Conn) Unsubscribe() error {
|
||||
err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) dispatch() {
|
||||
ch := make(chan *dbus.Signal, signalBuffer)
|
||||
|
||||
c.sigconn.Signal(ch)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
signal, ok := <-ch
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if signal.Name == "org.freedesktop.systemd1.Manager.JobRemoved" {
|
||||
c.jobComplete(signal)
|
||||
}
|
||||
|
||||
if c.subscriber.updateCh == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var unitPath dbus.ObjectPath
|
||||
switch signal.Name {
|
||||
case "org.freedesktop.systemd1.Manager.JobRemoved":
|
||||
unitName := signal.Body[2].(string)
|
||||
c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
|
||||
case "org.freedesktop.systemd1.Manager.UnitNew":
|
||||
unitPath = signal.Body[1].(dbus.ObjectPath)
|
||||
case "org.freedesktop.DBus.Properties.PropertiesChanged":
|
||||
if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
|
||||
unitPath = signal.Path
|
||||
}
|
||||
}
|
||||
|
||||
if unitPath == dbus.ObjectPath("") {
|
||||
continue
|
||||
}
|
||||
|
||||
c.sendSubStateUpdate(unitPath)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Returns two unbuffered channels which will receive all changed units every
|
||||
// interval. Deleted units are sent as nil.
|
||||
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
|
||||
return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)
|
||||
}
|
||||
|
||||
// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
|
||||
// size of the channels, the comparison function for detecting changes and a filter
|
||||
// function for cutting down on the noise that your channel receives.
|
||||
func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func(string) bool) (<-chan map[string]*UnitStatus, <-chan error) {
|
||||
old := make(map[string]*UnitStatus)
|
||||
statusChan := make(chan map[string]*UnitStatus, buffer)
|
||||
errChan := make(chan error, buffer)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
timerChan := time.After(interval)
|
||||
|
||||
units, err := c.ListUnits()
|
||||
if err == nil {
|
||||
cur := make(map[string]*UnitStatus)
|
||||
for i := range units {
|
||||
if filterUnit != nil && filterUnit(units[i].Name) {
|
||||
continue
|
||||
}
|
||||
cur[units[i].Name] = &units[i]
|
||||
}
|
||||
|
||||
// add all new or changed units
|
||||
changed := make(map[string]*UnitStatus)
|
||||
for n, u := range cur {
|
||||
if oldU, ok := old[n]; !ok || isChanged(oldU, u) {
|
||||
changed[n] = u
|
||||
}
|
||||
delete(old, n)
|
||||
}
|
||||
|
||||
// add all deleted units
|
||||
for oldN := range old {
|
||||
changed[oldN] = nil
|
||||
}
|
||||
|
||||
old = cur
|
||||
|
||||
if len(changed) != 0 {
|
||||
statusChan <- changed
|
||||
}
|
||||
} else {
|
||||
errChan <- err
|
||||
}
|
||||
|
||||
<-timerChan
|
||||
}
|
||||
}()
|
||||
|
||||
return statusChan, errChan
|
||||
}
|
||||
|
||||
type SubStateUpdate struct {
|
||||
UnitName string
|
||||
SubState string
|
||||
}
|
||||
|
||||
// SetSubStateSubscriber writes to updateCh when any unit's substate changes.
|
||||
// Although this writes to updateCh on every state change, the reported state
|
||||
// may be more recent than the change that generated it (due to an unavoidable
|
||||
// race in the systemd dbus interface). That is, this method provides a good
|
||||
// way to keep a current view of all units' states, but is not guaranteed to
|
||||
// show every state transition they go through. Furthermore, state changes
|
||||
// will only be written to the channel with non-blocking writes. If updateCh
|
||||
// is full, it attempts to write an error to errCh; if errCh is full, the error
|
||||
// passes silently.
|
||||
func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) {
|
||||
c.subscriber.Lock()
|
||||
defer c.subscriber.Unlock()
|
||||
c.subscriber.updateCh = updateCh
|
||||
c.subscriber.errCh = errCh
|
||||
}
|
||||
|
||||
func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
|
||||
c.subscriber.Lock()
|
||||
defer c.subscriber.Unlock()
|
||||
|
||||
if c.shouldIgnore(path) {
|
||||
return
|
||||
}
|
||||
|
||||
info, err := c.GetUnitProperties(string(path))
|
||||
if err != nil {
|
||||
select {
|
||||
case c.subscriber.errCh <- err:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
name := info["Id"].(string)
|
||||
substate := info["SubState"].(string)
|
||||
|
||||
update := &SubStateUpdate{name, substate}
|
||||
select {
|
||||
case c.subscriber.updateCh <- update:
|
||||
default:
|
||||
select {
|
||||
case c.subscriber.errCh <- errors.New("update channel full!"):
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
c.updateIgnore(path, info)
|
||||
}
|
||||
|
||||
// The ignore functions work around a wart in the systemd dbus interface.
|
||||
// Requesting the properties of an unloaded unit will cause systemd to send a
|
||||
// pair of UnitNew/UnitRemoved signals. Because we need to get a unit's
|
||||
// properties on UnitNew (as that's the only indication of a new unit coming up
|
||||
// for the first time), we would enter an infinite loop if we did not attempt
|
||||
// to detect and ignore these spurious signals. The signal themselves are
|
||||
// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an
|
||||
// unloaded unit's signals for a short time after requesting its properties.
|
||||
// This means that we will miss e.g. a transient unit being restarted
|
||||
// *immediately* upon failure and also a transient unit being started
|
||||
// immediately after requesting its status (with systemctl status, for example,
|
||||
// because this causes a UnitNew signal to be sent which then causes us to fetch
|
||||
// the properties).
|
||||
|
||||
func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool {
|
||||
t, ok := c.subscriber.ignore[path]
|
||||
return ok && t >= time.Now().UnixNano()
|
||||
}
|
||||
|
||||
func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) {
|
||||
c.cleanIgnore()
|
||||
|
||||
// unit is unloaded - it will trigger bad systemd dbus behavior
|
||||
if info["LoadState"].(string) == "not-found" {
|
||||
c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval
|
||||
}
|
||||
}
|
||||
|
||||
// without this, ignore would grow unboundedly over time
|
||||
func (c *Conn) cleanIgnore() {
|
||||
now := time.Now().UnixNano()
|
||||
if c.subscriber.cleanIgnore < now {
|
||||
c.subscriber.cleanIgnore = now + cleanIgnoreInterval
|
||||
|
||||
for p, t := range c.subscriber.ignore {
|
||||
if t < now {
|
||||
delete(c.subscriber.ignore, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
vendor/github.com/coreos/go-systemd/dbus/subscription_set.go
generated
vendored
57
vendor/github.com/coreos/go-systemd/dbus/subscription_set.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SubscriptionSet returns a subscription set which is like conn.Subscribe but
|
||||
// can filter to only return events for a set of units.
|
||||
type SubscriptionSet struct {
|
||||
*set
|
||||
conn *Conn
|
||||
}
|
||||
|
||||
func (s *SubscriptionSet) filter(unit string) bool {
|
||||
return !s.Contains(unit)
|
||||
}
|
||||
|
||||
// Subscribe starts listening for dbus events for all of the units in the set.
|
||||
// Returns channels identical to conn.SubscribeUnits.
|
||||
func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
|
||||
// TODO: Make fully evented by using systemd 209 with properties changed values
|
||||
return s.conn.SubscribeUnitsCustom(time.Second, 0,
|
||||
mismatchUnitStatus,
|
||||
func(unit string) bool { return s.filter(unit) },
|
||||
)
|
||||
}
|
||||
|
||||
// NewSubscriptionSet returns a new subscription set.
|
||||
func (conn *Conn) NewSubscriptionSet() *SubscriptionSet {
|
||||
return &SubscriptionSet{newSet(), conn}
|
||||
}
|
||||
|
||||
// mismatchUnitStatus returns true if the provided UnitStatus objects
|
||||
// are not equivalent. false is returned if the objects are equivalent.
|
||||
// Only the Name, Description and state-related fields are used in
|
||||
// the comparison.
|
||||
func mismatchUnitStatus(u1, u2 *UnitStatus) bool {
|
||||
return u1.Name != u2.Name ||
|
||||
u1.Description != u2.Description ||
|
||||
u1.LoadState != u2.LoadState ||
|
||||
u1.ActiveState != u2.ActiveState ||
|
||||
u1.SubState != u2.SubState
|
||||
}
|
82
vendor/github.com/coreos/go-systemd/dbus/subscription_set_test.go
generated
vendored
82
vendor/github.com/coreos/go-systemd/dbus/subscription_set_test.go
generated
vendored
@ -1,82 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestSubscribeUnit exercises the basics of subscription of a particular unit.
|
||||
func TestSubscriptionSetUnit(t *testing.T) {
|
||||
target := "subscribe-events-set.service"
|
||||
|
||||
conn, err := New()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = conn.Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subSet := conn.NewSubscriptionSet()
|
||||
evChan, errChan := subSet.Subscribe()
|
||||
|
||||
subSet.Add(target)
|
||||
setupUnit(target, conn, t)
|
||||
linkUnit(target, conn, t)
|
||||
|
||||
reschan := make(chan string)
|
||||
_, err = conn.StartUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
job := <-reschan
|
||||
if job != "done" {
|
||||
t.Fatal("Couldn't start", target)
|
||||
}
|
||||
|
||||
timeout := make(chan bool, 1)
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
close(timeout)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case changes := <-evChan:
|
||||
tCh, ok := changes[target]
|
||||
|
||||
if !ok {
|
||||
t.Fatal("Unexpected event:", changes)
|
||||
}
|
||||
|
||||
if tCh.ActiveState == "active" && tCh.Name == target {
|
||||
goto success
|
||||
}
|
||||
case err = <-errChan:
|
||||
t.Fatal(err)
|
||||
case <-timeout:
|
||||
t.Fatal("Reached timeout")
|
||||
}
|
||||
}
|
||||
|
||||
success:
|
||||
return
|
||||
}
|
105
vendor/github.com/coreos/go-systemd/dbus/subscription_test.go
generated
vendored
105
vendor/github.com/coreos/go-systemd/dbus/subscription_test.go
generated
vendored
@ -1,105 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dbus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestSubscribe exercises the basics of subscription
|
||||
func TestSubscribe(t *testing.T) {
|
||||
conn, err := New()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = conn.Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = conn.Unsubscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubscribeUnit exercises the basics of subscription of a particular unit.
|
||||
func TestSubscribeUnit(t *testing.T) {
|
||||
target := "subscribe-events.service"
|
||||
|
||||
conn, err := New()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = conn.Subscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = conn.Unsubscribe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
evChan, errChan := conn.SubscribeUnits(time.Second)
|
||||
|
||||
setupUnit(target, conn, t)
|
||||
linkUnit(target, conn, t)
|
||||
|
||||
reschan := make(chan string)
|
||||
_, err = conn.StartUnit(target, "replace", reschan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
job := <-reschan
|
||||
if job != "done" {
|
||||
t.Fatal("Couldn't start", target)
|
||||
}
|
||||
|
||||
timeout := make(chan bool, 1)
|
||||
go func() {
|
||||
time.Sleep(3 * time.Second)
|
||||
close(timeout)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case changes := <-evChan:
|
||||
tCh, ok := changes[target]
|
||||
|
||||
// Just continue until we see our event.
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if tCh.ActiveState == "active" && tCh.Name == target {
|
||||
goto success
|
||||
}
|
||||
case err = <-errChan:
|
||||
t.Fatal(err)
|
||||
case <-timeout:
|
||||
t.Fatal("Reached timeout")
|
||||
}
|
||||
}
|
||||
|
||||
success:
|
||||
return
|
||||
}
|
58
vendor/github.com/coreos/go-systemd/examples/activation/activation.go
generated
vendored
58
vendor/github.com/coreos/go-systemd/examples/activation/activation.go
generated
vendored
@ -1,58 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Activation example used by the activation unit tests.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
func fixListenPid() {
|
||||
if os.Getenv("FIX_LISTEN_PID") != "" {
|
||||
// HACK: real systemd would set LISTEN_PID before exec'ing but
|
||||
// this is too difficult in golang for the purpose of a test.
|
||||
// Do not do this in real code.
|
||||
os.Setenv("LISTEN_PID", fmt.Sprintf("%d", os.Getpid()))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fixListenPid()
|
||||
|
||||
files := activation.Files(false)
|
||||
|
||||
if len(files) == 0 {
|
||||
panic("No files")
|
||||
}
|
||||
|
||||
if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
|
||||
panic("Should not unset envs")
|
||||
}
|
||||
|
||||
files = activation.Files(true)
|
||||
|
||||
if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
|
||||
panic("Can not unset envs")
|
||||
}
|
||||
|
||||
// Write out the expected strings to the two pipes
|
||||
files[0].Write([]byte("Hello world"))
|
||||
files[1].Write([]byte("Goodbye world"))
|
||||
|
||||
return
|
||||
}
|
19
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/README.md
generated
vendored
19
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/README.md
generated
vendored
@ -1,19 +0,0 @@
|
||||
## socket activated http server
|
||||
|
||||
This is a simple example of using socket activation with systemd to serve a
|
||||
simple HTTP server on http://127.0.0.1:8076
|
||||
|
||||
To try it out `go get` the httpserver and run it under the systemd-activate helper
|
||||
|
||||
```
|
||||
export GOPATH=`pwd`
|
||||
go get github.com/coreos/go-systemd/examples/activation/httpserver
|
||||
sudo /usr/lib/systemd/systemd-activate -l 127.0.0.1:8076 ./bin/httpserver
|
||||
```
|
||||
|
||||
Then curl the URL and you will notice that it starts up:
|
||||
|
||||
```
|
||||
curl 127.0.0.1:8076
|
||||
hello socket activated world!
|
||||
```
|
11
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/hello.service
generated
vendored
11
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/hello.service
generated
vendored
@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Hello World HTTP
|
||||
Requires=network.target
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/httpserver
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
5
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/hello.socket
generated
vendored
5
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/hello.socket
generated
vendored
@ -1,5 +0,0 @@
|
||||
[Socket]
|
||||
ListenStream=127.0.0.1:8076
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
40
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go
generated
vendored
40
vendor/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
func HelloServer(w http.ResponseWriter, req *http.Request) {
|
||||
io.WriteString(w, "hello socket activated world!\n")
|
||||
}
|
||||
|
||||
func main() {
|
||||
listeners, err := activation.Listeners(true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(listeners) != 1 {
|
||||
panic("Unexpected number of socket activation fds")
|
||||
}
|
||||
|
||||
http.HandleFunc("/", HelloServer)
|
||||
http.Serve(listeners[0], nil)
|
||||
}
|
64
vendor/github.com/coreos/go-systemd/examples/activation/listen.go
generated
vendored
64
vendor/github.com/coreos/go-systemd/examples/activation/listen.go
generated
vendored
@ -1,64 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Activation example used by the activation unit tests.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
func fixListenPid() {
|
||||
if os.Getenv("FIX_LISTEN_PID") != "" {
|
||||
// HACK: real systemd would set LISTEN_PID before exec'ing but
|
||||
// this is too difficult in golang for the purpose of a test.
|
||||
// Do not do this in real code.
|
||||
os.Setenv("LISTEN_PID", fmt.Sprintf("%d", os.Getpid()))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fixListenPid()
|
||||
|
||||
listeners, _ := activation.Listeners(false)
|
||||
|
||||
if len(listeners) == 0 {
|
||||
panic("No listeners")
|
||||
}
|
||||
|
||||
if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
|
||||
panic("Should not unset envs")
|
||||
}
|
||||
|
||||
listeners, err := activation.Listeners(true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
|
||||
panic("Can not unset envs")
|
||||
}
|
||||
|
||||
c0, _ := listeners[0].Accept()
|
||||
c1, _ := listeners[1].Accept()
|
||||
|
||||
// Write out the expected strings to the two pipes
|
||||
c0.Write([]byte("Hello world"))
|
||||
c1.Write([]byte("Goodbye world"))
|
||||
|
||||
return
|
||||
}
|
86
vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go
generated
vendored
86
vendor/github.com/coreos/go-systemd/examples/activation/udpconn.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Activation example used by the activation unit tests.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
func fixListenPid() {
|
||||
if os.Getenv("FIX_LISTEN_PID") != "" {
|
||||
// HACK: real systemd would set LISTEN_PID before exec'ing but
|
||||
// this is too difficult in golang for the purpose of a test.
|
||||
// Do not do this in real code.
|
||||
os.Setenv("LISTEN_PID", fmt.Sprintf("%d", os.Getpid()))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fixListenPid()
|
||||
|
||||
pc, _ := activation.PacketConns(false)
|
||||
|
||||
if len(pc) == 0 {
|
||||
panic("No packetConns")
|
||||
}
|
||||
|
||||
if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
|
||||
panic("Should not unset envs")
|
||||
}
|
||||
|
||||
pc, err := activation.PacketConns(true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
|
||||
panic("Can not unset envs")
|
||||
}
|
||||
|
||||
udp1, ok := pc[0].(*net.UDPConn)
|
||||
if !ok {
|
||||
panic("packetConn 1 not UDP")
|
||||
}
|
||||
udp2, ok := pc[1].(*net.UDPConn)
|
||||
if !ok {
|
||||
panic("packetConn 2 not UDP")
|
||||
}
|
||||
|
||||
_, addr1, err := udp1.ReadFromUDP(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, addr2, err := udp2.ReadFromUDP(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Write out the expected strings to the two pipes
|
||||
_, err = udp1.WriteToUDP([]byte("Hello world"), addr1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = udp2.WriteToUDP([]byte("Goodbye world"), addr2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
5
vendor/github.com/coreos/go-systemd/fixtures/enable-disable.service
generated
vendored
5
vendor/github.com/coreos/go-systemd/fixtures/enable-disable.service
generated
vendored
@ -1,5 +0,0 @@
|
||||
[Unit]
|
||||
Description=enable disable test
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sleep 400
|
5
vendor/github.com/coreos/go-systemd/fixtures/start-stop.service
generated
vendored
5
vendor/github.com/coreos/go-systemd/fixtures/start-stop.service
generated
vendored
@ -1,5 +0,0 @@
|
||||
[Unit]
|
||||
Description=start stop test
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sleep 400
|
5
vendor/github.com/coreos/go-systemd/fixtures/subscribe-events-set.service
generated
vendored
5
vendor/github.com/coreos/go-systemd/fixtures/subscribe-events-set.service
generated
vendored
@ -1,5 +0,0 @@
|
||||
[Unit]
|
||||
Description=start stop test
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sleep 400
|
5
vendor/github.com/coreos/go-systemd/fixtures/subscribe-events.service
generated
vendored
5
vendor/github.com/coreos/go-systemd/fixtures/subscribe-events.service
generated
vendored
@ -1,5 +0,0 @@
|
||||
[Unit]
|
||||
Description=start stop test
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/sleep 400
|
178
vendor/github.com/coreos/go-systemd/journal/journal.go
generated
vendored
178
vendor/github.com/coreos/go-systemd/journal/journal.go
generated
vendored
@ -1,178 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package journal provides write bindings to the local systemd journal.
|
||||
// It is implemented in pure Go and connects to the journal directly over its
|
||||
// unix socket.
|
||||
//
|
||||
// To read from the journal, see the "sdjournal" package, which wraps the
|
||||
// sd-journal a C API.
|
||||
//
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html
|
||||
package journal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Priority of a journal message
|
||||
type Priority int
|
||||
|
||||
const (
|
||||
PriEmerg Priority = iota
|
||||
PriAlert
|
||||
PriCrit
|
||||
PriErr
|
||||
PriWarning
|
||||
PriNotice
|
||||
PriInfo
|
||||
PriDebug
|
||||
)
|
||||
|
||||
var conn net.Conn
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
conn, err = net.Dial("unixgram", "/run/systemd/journal/socket")
|
||||
if err != nil {
|
||||
conn = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Enabled returns true if the local systemd journal is available for logging
|
||||
func Enabled() bool {
|
||||
return conn != nil
|
||||
}
|
||||
|
||||
// Send a message to the local systemd journal. vars is a map of journald
|
||||
// fields to values. Fields must be composed of uppercase letters, numbers,
|
||||
// and underscores, but must not start with an underscore. Within these
|
||||
// restrictions, any arbitrary field name may be used. Some names have special
|
||||
// significance: see the journalctl documentation
|
||||
// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
|
||||
// for more details. vars may be nil.
|
||||
func Send(message string, priority Priority, vars map[string]string) error {
|
||||
if conn == nil {
|
||||
return journalError("could not connect to journald socket")
|
||||
}
|
||||
|
||||
data := new(bytes.Buffer)
|
||||
appendVariable(data, "PRIORITY", strconv.Itoa(int(priority)))
|
||||
appendVariable(data, "MESSAGE", message)
|
||||
for k, v := range vars {
|
||||
appendVariable(data, k, v)
|
||||
}
|
||||
|
||||
_, err := io.Copy(conn, data)
|
||||
if err != nil && isSocketSpaceError(err) {
|
||||
file, err := tempFd()
|
||||
if err != nil {
|
||||
return journalError(err.Error())
|
||||
}
|
||||
_, err = io.Copy(file, data)
|
||||
if err != nil {
|
||||
return journalError(err.Error())
|
||||
}
|
||||
|
||||
rights := syscall.UnixRights(int(file.Fd()))
|
||||
|
||||
/* this connection should always be a UnixConn, but better safe than sorry */
|
||||
unixConn, ok := conn.(*net.UnixConn)
|
||||
if !ok {
|
||||
return journalError("can't send file through non-Unix connection")
|
||||
}
|
||||
unixConn.WriteMsgUnix([]byte{}, rights, nil)
|
||||
} else if err != nil {
|
||||
return journalError(err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Print prints a message to the local systemd journal using Send().
|
||||
func Print(priority Priority, format string, a ...interface{}) error {
|
||||
return Send(fmt.Sprintf(format, a...), priority, nil)
|
||||
}
|
||||
|
||||
func appendVariable(w io.Writer, name, value string) {
|
||||
if !validVarName(name) {
|
||||
journalError("variable name contains invalid character, ignoring")
|
||||
}
|
||||
if strings.ContainsRune(value, '\n') {
|
||||
/* When the value contains a newline, we write:
|
||||
* - the variable name, followed by a newline
|
||||
* - the size (in 64bit little endian format)
|
||||
* - the data, followed by a newline
|
||||
*/
|
||||
fmt.Fprintln(w, name)
|
||||
binary.Write(w, binary.LittleEndian, uint64(len(value)))
|
||||
fmt.Fprintln(w, value)
|
||||
} else {
|
||||
/* just write the variable and value all on one line */
|
||||
fmt.Fprintf(w, "%s=%s\n", name, value)
|
||||
}
|
||||
}
|
||||
|
||||
func validVarName(name string) bool {
|
||||
/* The variable name must be in uppercase and consist only of characters,
|
||||
* numbers and underscores, and may not begin with an underscore. (from the docs)
|
||||
*/
|
||||
|
||||
valid := name[0] != '_'
|
||||
for _, c := range name {
|
||||
valid = valid && ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_'
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
func isSocketSpaceError(err error) bool {
|
||||
opErr, ok := err.(*net.OpError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
sysErr, ok := opErr.Err.(syscall.Errno)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return sysErr == syscall.EMSGSIZE || sysErr == syscall.ENOBUFS
|
||||
}
|
||||
|
||||
func tempFd() (*os.File, error) {
|
||||
file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
syscall.Unlink(file.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func journalError(s string) error {
|
||||
s = "journal error: " + s
|
||||
fmt.Fprintln(os.Stderr, s)
|
||||
return errors.New(s)
|
||||
}
|
108
vendor/github.com/coreos/go-systemd/login1/dbus.go
generated
vendored
108
vendor/github.com/coreos/go-systemd/login1/dbus.go
generated
vendored
@ -1,108 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Integration with the systemd logind API. See http://www.freedesktop.org/wiki/Software/systemd/logind/
|
||||
package login1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
const (
|
||||
dbusInterface = "org.freedesktop.login1.Manager"
|
||||
dbusPath = "/org/freedesktop/login1"
|
||||
)
|
||||
|
||||
// Conn is a connection to systemds dbus endpoint.
|
||||
type Conn struct {
|
||||
conn *dbus.Conn
|
||||
object dbus.BusObject
|
||||
}
|
||||
|
||||
// New() establishes a connection to the system bus and authenticates.
|
||||
func New() (*Conn, error) {
|
||||
c := new(Conn)
|
||||
|
||||
if err := c.initConnection(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Conn) initConnection() error {
|
||||
var err error
|
||||
c.conn, err = dbus.SystemBusPrivate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only use EXTERNAL method, and hardcode the uid (not username)
|
||||
// to avoid a username lookup (which requires a dynamically linked
|
||||
// libc)
|
||||
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
||||
|
||||
err = c.conn.Auth(methods)
|
||||
if err != nil {
|
||||
c.conn.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.conn.Hello()
|
||||
if err != nil {
|
||||
c.conn.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
c.object = c.conn.Object("org.freedesktop.login1", dbus.ObjectPath(dbusPath))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reboot asks logind for a reboot optionally asking for auth.
|
||||
func (c *Conn) Reboot(askForAuth bool) {
|
||||
c.object.Call(dbusInterface+".Reboot", 0, askForAuth)
|
||||
}
|
||||
|
||||
// Inhibit takes inhibition lock in logind.
|
||||
func (c *Conn) Inhibit(what, who, why, mode string) (*os.File, error) {
|
||||
var fd dbus.UnixFD
|
||||
|
||||
err := c.object.Call(dbusInterface+".Inhibit", 0, what, who, why, mode).Store(&fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.NewFile(uintptr(fd), "inhibit"), nil
|
||||
}
|
||||
|
||||
// Subscribe to signals on the logind dbus
|
||||
func (c *Conn) Subscribe(members ...string) chan *dbus.Signal {
|
||||
for _, member := range members {
|
||||
c.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
fmt.Sprintf("type='signal',interface='org.freedesktop.login1.Manager',member='%s'", member))
|
||||
}
|
||||
ch := make(chan *dbus.Signal, 10)
|
||||
c.conn.Signal(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// PowerOff asks logind for a power off optionally asking for auth.
|
||||
func (c *Conn) PowerOff(askForAuth bool) {
|
||||
c.object.Call(dbusInterface+".PowerOff", 0, askForAuth)
|
||||
}
|
81
vendor/github.com/coreos/go-systemd/machine1/dbus.go
generated
vendored
81
vendor/github.com/coreos/go-systemd/machine1/dbus.go
generated
vendored
@ -1,81 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Integration with the systemd machined API. See http://www.freedesktop.org/wiki/Software/systemd/machined/
|
||||
package machine1
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
)
|
||||
|
||||
const (
|
||||
dbusInterface = "org.freedesktop.machine1.Manager"
|
||||
dbusPath = "/org/freedesktop/machine1"
|
||||
)
|
||||
|
||||
// Conn is a connection to systemds dbus endpoint.
|
||||
type Conn struct {
|
||||
conn *dbus.Conn
|
||||
object dbus.BusObject
|
||||
}
|
||||
|
||||
// New() establishes a connection to the system bus and authenticates.
|
||||
func New() (*Conn, error) {
|
||||
c := new(Conn)
|
||||
|
||||
if err := c.initConnection(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Conn) initConnection() error {
|
||||
var err error
|
||||
c.conn, err = dbus.SystemBusPrivate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only use EXTERNAL method, and hardcode the uid (not username)
|
||||
// to avoid a username lookup (which requires a dynamically linked
|
||||
// libc)
|
||||
methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
|
||||
|
||||
err = c.conn.Auth(methods)
|
||||
if err != nil {
|
||||
c.conn.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.conn.Hello()
|
||||
if err != nil {
|
||||
c.conn.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
c.object = c.conn.Object("org.freedesktop.machine1", dbus.ObjectPath(dbusPath))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterMachine registers the container with the systemd-machined
|
||||
func (c *Conn) RegisterMachine(name string, id []byte, service string, class string, pid int, root_directory string) error {
|
||||
return c.object.Call(dbusInterface+".RegisterMachine", 0, name, id, service, class, uint32(pid), root_directory).Err
|
||||
}
|
30
vendor/github.com/coreos/go-systemd/machine1/dbus_test.go
generated
vendored
30
vendor/github.com/coreos/go-systemd/machine1/dbus_test.go
generated
vendored
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2015 CoreOS Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package machine1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestNew ensures that New() works without errors.
|
||||
func TestNew(t *testing.T) {
|
||||
_, err := New()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
356
vendor/github.com/coreos/go-systemd/sdjournal/journal.go
generated
vendored
356
vendor/github.com/coreos/go-systemd/sdjournal/journal.go
generated
vendored
@ -1,356 +0,0 @@
|
||||
// Copyright 2015 RedHat, Inc.
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package sdjournal provides a low-level Go interface to the
|
||||
// systemd journal wrapped around the sd-journal C API.
|
||||
//
|
||||
// All public read methods map closely to the sd-journal API functions. See the
|
||||
// sd-journal.h documentation[1] for information about each function.
|
||||
//
|
||||
// To write to the journal, see the pure-Go "journal" package
|
||||
//
|
||||
// [1] http://www.freedesktop.org/software/systemd/man/sd-journal.html
|
||||
package sdjournal
|
||||
|
||||
/*
|
||||
#cgo pkg-config: libsystemd
|
||||
#include <systemd/sd-journal.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Journal entry field strings which correspond to:
|
||||
// http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
|
||||
const (
|
||||
SD_JOURNAL_FIELD_SYSTEMD_UNIT = "_SYSTEMD_UNIT"
|
||||
SD_JOURNAL_FIELD_MESSAGE = "MESSAGE"
|
||||
SD_JOURNAL_FIELD_PID = "_PID"
|
||||
SD_JOURNAL_FIELD_UID = "_UID"
|
||||
SD_JOURNAL_FIELD_GID = "_GID"
|
||||
SD_JOURNAL_FIELD_HOSTNAME = "_HOSTNAME"
|
||||
SD_JOURNAL_FIELD_MACHINE_ID = "_MACHINE_ID"
|
||||
)
|
||||
|
||||
// Journal event constants
|
||||
const (
|
||||
SD_JOURNAL_NOP = int(C.SD_JOURNAL_NOP)
|
||||
SD_JOURNAL_APPEND = int(C.SD_JOURNAL_APPEND)
|
||||
SD_JOURNAL_INVALIDATE = int(C.SD_JOURNAL_INVALIDATE)
|
||||
)
|
||||
|
||||
const (
|
||||
// IndefiniteWait is a sentinel value that can be passed to
|
||||
// sdjournal.Wait() to signal an indefinite wait for new journal
|
||||
// events. It is implemented as the maximum value for a time.Duration:
|
||||
// https://github.com/golang/go/blob/e4dcf5c8c22d98ac9eac7b9b226596229624cb1d/src/time/time.go#L434
|
||||
IndefiniteWait time.Duration = 1<<63 - 1
|
||||
)
|
||||
|
||||
// Journal is a Go wrapper of an sd_journal structure.
|
||||
type Journal struct {
|
||||
cjournal *C.sd_journal
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Match is a convenience wrapper to describe filters supplied to AddMatch.
|
||||
type Match struct {
|
||||
Field string
|
||||
Value string
|
||||
}
|
||||
|
||||
// String returns a string representation of a Match suitable for use with AddMatch.
|
||||
func (m *Match) String() string {
|
||||
return m.Field + "=" + m.Value
|
||||
}
|
||||
|
||||
// NewJournal returns a new Journal instance pointing to the local journal
|
||||
func NewJournal() (*Journal, error) {
|
||||
j := &Journal{}
|
||||
r := C.sd_journal_open(&j.cjournal, C.SD_JOURNAL_LOCAL_ONLY)
|
||||
|
||||
if r < 0 {
|
||||
return nil, fmt.Errorf("failed to open journal: %d", r)
|
||||
}
|
||||
|
||||
return j, nil
|
||||
}
|
||||
|
||||
// NewJournalFromDir returns a new Journal instance pointing to a journal residing
|
||||
// in a given directory. The supplied path may be relative or absolute; if
|
||||
// relative, it will be converted to an absolute path before being opened.
|
||||
func NewJournalFromDir(path string) (*Journal, error) {
|
||||
path, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(p))
|
||||
|
||||
j := &Journal{}
|
||||
r := C.sd_journal_open_directory(&j.cjournal, p, 0)
|
||||
if r < 0 {
|
||||
return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, r)
|
||||
}
|
||||
|
||||
return j, nil
|
||||
}
|
||||
|
||||
// Close closes a journal opened with NewJournal.
|
||||
func (j *Journal) Close() error {
|
||||
j.mu.Lock()
|
||||
C.sd_journal_close(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddMatch adds a match by which to filter the entries of the journal.
|
||||
func (j *Journal) AddMatch(match string) error {
|
||||
m := C.CString(match)
|
||||
defer C.free(unsafe.Pointer(m))
|
||||
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_add_match(j.cjournal, unsafe.Pointer(m), C.size_t(len(match)))
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to add match: %d", r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDisjunction inserts a logical OR in the match list.
|
||||
func (j *Journal) AddDisjunction() error {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_add_disjunction(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to add a disjunction in the match list: %d", r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddConjunction inserts a logical AND in the match list.
|
||||
func (j *Journal) AddConjunction() error {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_add_conjunction(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to add a conjunction in the match list: %d", r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlushMatches flushes all matches, disjunctions and conjunctions.
|
||||
func (j *Journal) FlushMatches() {
|
||||
j.mu.Lock()
|
||||
C.sd_journal_flush_matches(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
}
|
||||
|
||||
// Next advances the read pointer into the journal by one entry.
|
||||
func (j *Journal) Next() (int, error) {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_next(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return int(r), fmt.Errorf("failed to iterate journal: %d", r)
|
||||
}
|
||||
|
||||
return int(r), nil
|
||||
}
|
||||
|
||||
// NextSkip advances the read pointer by multiple entries at once,
|
||||
// as specified by the skip parameter.
|
||||
func (j *Journal) NextSkip(skip uint64) (uint64, error) {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_next_skip(j.cjournal, C.uint64_t(skip))
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return uint64(r), fmt.Errorf("failed to iterate journal: %d", r)
|
||||
}
|
||||
|
||||
return uint64(r), nil
|
||||
}
|
||||
|
||||
// Previous sets the read pointer into the journal back by one entry.
|
||||
func (j *Journal) Previous() (uint64, error) {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_previous(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return uint64(r), fmt.Errorf("failed to iterate journal: %d", r)
|
||||
}
|
||||
|
||||
return uint64(r), nil
|
||||
}
|
||||
|
||||
// PreviousSkip sets back the read pointer by multiple entries at once,
|
||||
// as specified by the skip parameter.
|
||||
func (j *Journal) PreviousSkip(skip uint64) (uint64, error) {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_previous_skip(j.cjournal, C.uint64_t(skip))
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return uint64(r), fmt.Errorf("failed to iterate journal: %d", r)
|
||||
}
|
||||
|
||||
return uint64(r), nil
|
||||
}
|
||||
|
||||
// GetData gets the data object associated with a specific field from the
|
||||
// current journal entry.
|
||||
func (j *Journal) GetData(field string) (string, error) {
|
||||
f := C.CString(field)
|
||||
defer C.free(unsafe.Pointer(f))
|
||||
|
||||
var d unsafe.Pointer
|
||||
var l C.size_t
|
||||
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_get_data(j.cjournal, f, &d, &l)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return "", fmt.Errorf("failed to read message: %d", r)
|
||||
}
|
||||
|
||||
msg := C.GoStringN((*C.char)(d), C.int(l))
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// GetDataValue gets the data object associated with a specific field from the
|
||||
// current journal entry, returning only the value of the object.
|
||||
func (j *Journal) GetDataValue(field string) (string, error) {
|
||||
val, err := j.GetData(field)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.SplitN(val, "=", 2)[1], nil
|
||||
}
|
||||
|
||||
// SetDataThresold sets the data field size threshold for data returned by
|
||||
// GetData. To retrieve the complete data fields this threshold should be
|
||||
// turned off by setting it to 0, so that the library always returns the
|
||||
// complete data objects.
|
||||
func (j *Journal) SetDataThreshold(threshold uint64) error {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_set_data_threshold(j.cjournal, C.size_t(threshold))
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to set data threshold: %d", r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRealtimeUsec gets the realtime (wallclock) timestamp of the current
|
||||
// journal entry.
|
||||
func (j *Journal) GetRealtimeUsec() (uint64, error) {
|
||||
var usec C.uint64_t
|
||||
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_get_realtime_usec(j.cjournal, &usec)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return 0, fmt.Errorf("error getting timestamp for entry: %d", r)
|
||||
}
|
||||
|
||||
return uint64(usec), nil
|
||||
}
|
||||
|
||||
// SeekTail may be used to seek to the end of the journal, i.e. the most recent
|
||||
// available entry.
|
||||
func (j *Journal) SeekTail() error {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_seek_tail(j.cjournal)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to seek to tail of journal: %d", r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock)
|
||||
// timestamp, i.e. CLOCK_REALTIME.
|
||||
func (j *Journal) SeekRealtimeUsec(usec uint64) error {
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_seek_realtime_usec(j.cjournal, C.uint64_t(usec))
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return fmt.Errorf("failed to seek to %d: %d", usec, r)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wait will synchronously wait until the journal gets changed. The maximum time
|
||||
// this call sleeps may be controlled with the timeout parameter. If
|
||||
// sdjournal.IndefiniteWait is passed as the timeout parameter, Wait will
|
||||
// wait indefinitely for a journal change.
|
||||
func (j *Journal) Wait(timeout time.Duration) int {
|
||||
var to uint64
|
||||
if timeout == IndefiniteWait {
|
||||
// sd_journal_wait(3) calls for a (uint64_t) -1 to be passed to signify
|
||||
// indefinite wait, but using a -1 overflows our C.uint64_t, so we use an
|
||||
// equivalent hex value.
|
||||
to = 0xffffffffffffffff
|
||||
} else {
|
||||
to = uint64(time.Now().Add(timeout).Unix() / 1000)
|
||||
}
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_wait(j.cjournal, C.uint64_t(to))
|
||||
j.mu.Unlock()
|
||||
|
||||
return int(r)
|
||||
}
|
||||
|
||||
// GetUsage returns the journal disk space usage, in bytes.
|
||||
func (j *Journal) GetUsage() (uint64, error) {
|
||||
var out C.uint64_t
|
||||
j.mu.Lock()
|
||||
r := C.sd_journal_get_usage(j.cjournal, &out)
|
||||
j.mu.Unlock()
|
||||
|
||||
if r < 0 {
|
||||
return 0, fmt.Errorf("failed to get journal disk space usage: %d", r)
|
||||
}
|
||||
|
||||
return uint64(out), nil
|
||||
}
|
90
vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go
generated
vendored
90
vendor/github.com/coreos/go-systemd/sdjournal/journal_test.go
generated
vendored
@ -1,90 +0,0 @@
|
||||
// Copyright 2015 RedHat, Inc.
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sdjournal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-systemd/journal"
|
||||
)
|
||||
|
||||
func TestJournalFollow(t *testing.T) {
|
||||
r, err := NewJournalReader(JournalReaderConfig{
|
||||
Since: time.Duration(-15) * time.Second,
|
||||
Matches: []Match{
|
||||
{
|
||||
Field: SD_JOURNAL_FIELD_SYSTEMD_UNIT,
|
||||
Value: "NetworkManager.service",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error opening journal: %s", err)
|
||||
}
|
||||
|
||||
if r == nil {
|
||||
t.Fatal("Got a nil reader")
|
||||
}
|
||||
|
||||
defer r.Close()
|
||||
|
||||
// start writing some test entries
|
||||
done := make(chan struct{}, 1)
|
||||
defer close(done)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
if err = journal.Print(journal.PriInfo, "test message %s", time.Now()); err != nil {
|
||||
t.Fatalf("Error writing to journal: %s", err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// and follow the reader synchronously
|
||||
timeout := time.Duration(5) * time.Second
|
||||
if err = r.Follow(time.After(timeout), os.Stdout); err != ErrExpired {
|
||||
t.Fatalf("Error during follow: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJournalGetUsage(t *testing.T) {
|
||||
j, err := NewJournal()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error opening journal: %s", err)
|
||||
}
|
||||
|
||||
if j == nil {
|
||||
t.Fatal("Got a nil journal")
|
||||
}
|
||||
|
||||
defer j.Close()
|
||||
|
||||
_, err = j.GetUsage()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting journal size: %s", err)
|
||||
}
|
||||
}
|
201
vendor/github.com/coreos/go-systemd/sdjournal/read.go
generated
vendored
201
vendor/github.com/coreos/go-systemd/sdjournal/read.go
generated
vendored
@ -1,201 +0,0 @@
|
||||
// Copyright 2015 RedHat, Inc.
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package sdjournal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrExpired = errors.New("Timeout expired")
|
||||
)
|
||||
|
||||
// JournalReaderConfig represents options to drive the behavior of a JournalReader.
|
||||
type JournalReaderConfig struct {
|
||||
// The Since and NumFromTail options are mutually exclusive and determine
|
||||
// where the reading begins within the journal.
|
||||
Since time.Duration // start relative to a Duration from now
|
||||
NumFromTail uint64 // start relative to the tail
|
||||
|
||||
// Show only journal entries whose fields match the supplied values. If
|
||||
// the array is empty, entries will not be filtered.
|
||||
Matches []Match
|
||||
}
|
||||
|
||||
// JournalReader is an io.ReadCloser which provides a simple interface for iterating through the
|
||||
// systemd journal.
|
||||
type JournalReader struct {
|
||||
journal *Journal
|
||||
}
|
||||
|
||||
// NewJournalReader creates a new JournalReader with configuration options that are similar to the
|
||||
// systemd journalctl tool's iteration and filtering features.
|
||||
func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) {
|
||||
r := &JournalReader{}
|
||||
|
||||
var err error
|
||||
// Open the journal
|
||||
if r.journal, err = NewJournal(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add any supplied matches
|
||||
for _, m := range config.Matches {
|
||||
r.journal.AddMatch(m.String())
|
||||
}
|
||||
|
||||
// Set the start position based on options
|
||||
if config.Since != 0 {
|
||||
// Start based on a relative time
|
||||
start := time.Now().Add(config.Since)
|
||||
if err := r.journal.SeekRealtimeUsec(uint64(start.UnixNano() / 1000)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if config.NumFromTail != 0 {
|
||||
// Start based on a number of lines before the tail
|
||||
if err := r.journal.SeekTail(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Move the read pointer into position near the tail. Go one further than
|
||||
// the option so that the initial cursor advancement positions us at the
|
||||
// correct starting point.
|
||||
if _, err := r.journal.PreviousSkip(config.NumFromTail + 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *JournalReader) Read(b []byte) (int, error) {
|
||||
var err error
|
||||
var c int
|
||||
|
||||
// Advance the journal cursor
|
||||
c, err = r.journal.Next()
|
||||
|
||||
// An unexpected error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// EOF detection
|
||||
if c == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
// Build a message
|
||||
var msg string
|
||||
msg, err = r.buildMessage()
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Copy and return the message
|
||||
copy(b, []byte(msg))
|
||||
|
||||
return len(msg), nil
|
||||
}
|
||||
|
||||
func (r *JournalReader) Close() error {
|
||||
return r.journal.Close()
|
||||
}
|
||||
|
||||
// Follow synchronously follows the JournalReader, writing each new journal entry to writer. The
|
||||
// follow will continue until a single time.Time is received on the until channel.
|
||||
func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) (err error) {
|
||||
|
||||
// Process journal entries and events. Entries are flushed until the tail or
|
||||
// timeout is reached, and then we wait for new events or the timeout.
|
||||
process:
|
||||
for {
|
||||
var msg = make([]byte, 64*1<<(10))
|
||||
|
||||
c, err := r.Read(msg)
|
||||
if err != nil && err != io.EOF {
|
||||
break process
|
||||
}
|
||||
|
||||
select {
|
||||
case <-until:
|
||||
return ErrExpired
|
||||
default:
|
||||
if c > 0 {
|
||||
writer.Write(msg)
|
||||
continue process
|
||||
}
|
||||
}
|
||||
|
||||
// We're at the tail, so wait for new events or time out.
|
||||
// Holds journal events to process. Tightly bounded for now unless there's a
|
||||
// reason to unblock the journal watch routine more quickly.
|
||||
events := make(chan int, 1)
|
||||
pollDone := make(chan bool, 1)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-pollDone:
|
||||
return
|
||||
default:
|
||||
events <- r.journal.Wait(time.Duration(1) * time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-until:
|
||||
pollDone <- true
|
||||
return ErrExpired
|
||||
case e := <-events:
|
||||
pollDone <- true
|
||||
switch e {
|
||||
case SD_JOURNAL_NOP, SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE:
|
||||
// TODO: need to account for any of these?
|
||||
default:
|
||||
log.Printf("Received unknown event: %d\n", e)
|
||||
}
|
||||
continue process
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// buildMessage returns a string representing the current journal entry in a simple format which
|
||||
// includes the entry timestamp and MESSAGE field.
|
||||
func (r *JournalReader) buildMessage() (string, error) {
|
||||
var msg string
|
||||
var usec uint64
|
||||
var err error
|
||||
|
||||
if msg, err = r.journal.GetData("MESSAGE"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if usec, err = r.journal.GetRealtimeUsec(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
timestamp := time.Unix(0, int64(usec)*int64(time.Microsecond))
|
||||
|
||||
return fmt.Sprintf("%s %s\n", timestamp, msg), nil
|
||||
}
|
76
vendor/github.com/coreos/go-systemd/test
generated
vendored
76
vendor/github.com/coreos/go-systemd/test
generated
vendored
@ -1,76 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Run all tests
|
||||
# ./test
|
||||
# ./test -v
|
||||
#
|
||||
# Run tests for one package
|
||||
# PKG=./foo ./test
|
||||
# PKG=bar ./test
|
||||
#
|
||||
|
||||
# Invoke ./cover for HTML output
|
||||
COVER=${COVER:-"-cover"}
|
||||
|
||||
PROJ="go-systemd"
|
||||
ORG_PATH="github.com/coreos"
|
||||
REPO_PATH="${ORG_PATH}/${PROJ}"
|
||||
|
||||
# As a convenience, set up a self-contained GOPATH if none set
|
||||
if [ -z "$GOPATH" ]; then
|
||||
if [ ! -h gopath/src/${REPO_PATH} ]; then
|
||||
mkdir -p gopath/src/${ORG_PATH}
|
||||
ln -s ../../../.. gopath/src/${REPO_PATH} || exit 255
|
||||
fi
|
||||
export GOPATH=${PWD}/gopath
|
||||
go get -u github.com/godbus/dbus
|
||||
fi
|
||||
|
||||
TESTABLE="activation journal login1 machine1 unit"
|
||||
FORMATTABLE="$TESTABLE sdjournal dbus"
|
||||
if [ -e "/run/systemd/system/" ]; then
|
||||
TESTABLE="${TESTABLE} sdjournal"
|
||||
if [ "$EUID" == "0" ]; then
|
||||
# testing actual systemd behaviour requires root
|
||||
TESTABLE="${TESTABLE} dbus"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# user has not provided PKG override
|
||||
if [ -z "$PKG" ]; then
|
||||
TEST=$TESTABLE
|
||||
FMT=$FORMATTABLE
|
||||
|
||||
# user has provided PKG override
|
||||
else
|
||||
# strip out slashes and dots from PKG=./foo/
|
||||
TEST=${PKG//\//}
|
||||
TEST=${TEST//./}
|
||||
|
||||
# only run gofmt on packages provided by user
|
||||
FMT="$TEST"
|
||||
fi
|
||||
|
||||
# split TEST into an array and prepend REPO_PATH to each local package
|
||||
split=(${TEST// / })
|
||||
TEST=${split[@]/#/${REPO_PATH}/}
|
||||
|
||||
echo "Running tests..."
|
||||
go test ${COVER} $@ ${TEST}
|
||||
|
||||
echo "Checking gofmt..."
|
||||
fmtRes=$(gofmt -l $FMT)
|
||||
if [ -n "${fmtRes}" ]; then
|
||||
echo -e "gofmt checking failed:\n${fmtRes}"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
echo "Checking govet..."
|
||||
vetRes=$(go vet $TEST)
|
||||
if [ -n "${vetRes}" ]; then
|
||||
echo -e "govet checking failed:\n${vetRes}"
|
||||
exit 255
|
||||
fi
|
||||
|
||||
echo "Success"
|
276
vendor/github.com/coreos/go-systemd/unit/deserialize.go
generated
vendored
276
vendor/github.com/coreos/go-systemd/unit/deserialize.go
generated
vendored
@ -1,276 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const (
|
||||
// SYSTEMD_LINE_MAX mimics the maximum line length that systemd can use.
|
||||
// On typical systemd platforms (i.e. modern Linux), this will most
|
||||
// commonly be 2048, so let's use that as a sanity check.
|
||||
// Technically, we should probably pull this at runtime:
|
||||
// SYSTEMD_LINE_MAX = int(C.sysconf(C.__SC_LINE_MAX))
|
||||
// but this would introduce an (unfortunate) dependency on cgo
|
||||
SYSTEMD_LINE_MAX = 2048
|
||||
|
||||
// characters that systemd considers indicate a newline
|
||||
SYSTEMD_NEWLINE = "\r\n"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLineTooLong = fmt.Errorf("line too long (max %d bytes)", SYSTEMD_LINE_MAX)
|
||||
)
|
||||
|
||||
// Deserialize parses a systemd unit file into a list of UnitOption objects.
|
||||
func Deserialize(f io.Reader) (opts []*UnitOption, err error) {
|
||||
lexer, optchan, errchan := newLexer(f)
|
||||
go lexer.lex()
|
||||
|
||||
for opt := range optchan {
|
||||
opts = append(opts, &(*opt))
|
||||
}
|
||||
|
||||
err = <-errchan
|
||||
return opts, err
|
||||
}
|
||||
|
||||
func newLexer(f io.Reader) (*lexer, <-chan *UnitOption, <-chan error) {
|
||||
optchan := make(chan *UnitOption)
|
||||
errchan := make(chan error, 1)
|
||||
buf := bufio.NewReader(f)
|
||||
|
||||
return &lexer{buf, optchan, errchan, ""}, optchan, errchan
|
||||
}
|
||||
|
||||
type lexer struct {
|
||||
buf *bufio.Reader
|
||||
optchan chan *UnitOption
|
||||
errchan chan error
|
||||
section string
|
||||
}
|
||||
|
||||
func (l *lexer) lex() {
|
||||
var err error
|
||||
defer func() {
|
||||
close(l.optchan)
|
||||
close(l.errchan)
|
||||
}()
|
||||
next := l.lexNextSection
|
||||
for next != nil {
|
||||
if l.buf.Buffered() >= SYSTEMD_LINE_MAX {
|
||||
// systemd truncates lines longer than LINE_MAX
|
||||
// https://bugs.freedesktop.org/show_bug.cgi?id=85308
|
||||
// Rather than allowing this to pass silently, let's
|
||||
// explicitly gate people from encountering this
|
||||
line, err := l.buf.Peek(SYSTEMD_LINE_MAX)
|
||||
if err != nil {
|
||||
l.errchan <- err
|
||||
return
|
||||
}
|
||||
if bytes.IndexAny(line, SYSTEMD_NEWLINE) == -1 {
|
||||
l.errchan <- ErrLineTooLong
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
next, err = next()
|
||||
if err != nil {
|
||||
l.errchan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type lexStep func() (lexStep, error)
|
||||
|
||||
func (l *lexer) lexSectionName() (lexStep, error) {
|
||||
sec, err := l.buf.ReadBytes(']')
|
||||
if err != nil {
|
||||
return nil, errors.New("unable to find end of section")
|
||||
}
|
||||
|
||||
return l.lexSectionSuffixFunc(string(sec[:len(sec)-1])), nil
|
||||
}
|
||||
|
||||
func (l *lexer) lexSectionSuffixFunc(section string) lexStep {
|
||||
return func() (lexStep, error) {
|
||||
garbage, _, err := l.toEOL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
garbage = bytes.TrimSpace(garbage)
|
||||
if len(garbage) > 0 {
|
||||
return nil, fmt.Errorf("found garbage after section name %s: %v", l.section, garbage)
|
||||
}
|
||||
|
||||
return l.lexNextSectionOrOptionFunc(section), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) ignoreLineFunc(next lexStep) lexStep {
|
||||
return func() (lexStep, error) {
|
||||
for {
|
||||
line, _, err := l.toEOL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
line = bytes.TrimSuffix(line, []byte{' '})
|
||||
|
||||
// lack of continuation means this line has been exhausted
|
||||
if !bytes.HasSuffix(line, []byte{'\\'}) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// reached end of buffer, safe to exit
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) lexNextSection() (lexStep, error) {
|
||||
r, _, err := l.buf.ReadRune()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r == '[' {
|
||||
return l.lexSectionName, nil
|
||||
} else if isComment(r) {
|
||||
return l.ignoreLineFunc(l.lexNextSection), nil
|
||||
}
|
||||
|
||||
return l.lexNextSection, nil
|
||||
}
|
||||
|
||||
func (l *lexer) lexNextSectionOrOptionFunc(section string) lexStep {
|
||||
return func() (lexStep, error) {
|
||||
r, _, err := l.buf.ReadRune()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if unicode.IsSpace(r) {
|
||||
return l.lexNextSectionOrOptionFunc(section), nil
|
||||
} else if r == '[' {
|
||||
return l.lexSectionName, nil
|
||||
} else if isComment(r) {
|
||||
return l.ignoreLineFunc(l.lexNextSectionOrOptionFunc(section)), nil
|
||||
}
|
||||
|
||||
l.buf.UnreadRune()
|
||||
return l.lexOptionNameFunc(section), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) lexOptionNameFunc(section string) lexStep {
|
||||
return func() (lexStep, error) {
|
||||
var partial bytes.Buffer
|
||||
for {
|
||||
r, _, err := l.buf.ReadRune()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r == '\n' || r == '\r' {
|
||||
return nil, errors.New("unexpected newline encountered while parsing option name")
|
||||
}
|
||||
|
||||
if r == '=' {
|
||||
break
|
||||
}
|
||||
|
||||
partial.WriteRune(r)
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(partial.String())
|
||||
return l.lexOptionValueFunc(section, name, bytes.Buffer{}), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) lexOptionValueFunc(section, name string, partial bytes.Buffer) lexStep {
|
||||
return func() (lexStep, error) {
|
||||
for {
|
||||
line, eof, err := l.toEOL()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(bytes.TrimSpace(line)) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
partial.Write(line)
|
||||
|
||||
// lack of continuation means this value has been exhausted
|
||||
idx := bytes.LastIndex(line, []byte{'\\'})
|
||||
if idx == -1 || idx != (len(line)-1) {
|
||||
break
|
||||
}
|
||||
|
||||
if !eof {
|
||||
partial.WriteRune('\n')
|
||||
}
|
||||
|
||||
return l.lexOptionValueFunc(section, name, partial), nil
|
||||
}
|
||||
|
||||
val := partial.String()
|
||||
if strings.HasSuffix(val, "\n") {
|
||||
// A newline was added to the end, so the file didn't end with a backslash.
|
||||
// => Keep the newline
|
||||
val = strings.TrimSpace(val) + "\n"
|
||||
} else {
|
||||
val = strings.TrimSpace(val)
|
||||
}
|
||||
l.optchan <- &UnitOption{Section: section, Name: name, Value: val}
|
||||
|
||||
return l.lexNextSectionOrOptionFunc(section), nil
|
||||
}
|
||||
}
|
||||
|
||||
// toEOL reads until the end-of-line or end-of-file.
|
||||
// Returns (data, EOFfound, error)
|
||||
func (l *lexer) toEOL() ([]byte, bool, error) {
|
||||
line, err := l.buf.ReadBytes('\n')
|
||||
// ignore EOF here since it's roughly equivalent to EOL
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
line = bytes.TrimSuffix(line, []byte{'\r'})
|
||||
line = bytes.TrimSuffix(line, []byte{'\n'})
|
||||
|
||||
return line, err == io.EOF, nil
|
||||
}
|
||||
|
||||
func isComment(r rune) bool {
|
||||
return r == '#' || r == ';'
|
||||
}
|
381
vendor/github.com/coreos/go-systemd/unit/deserialize_test.go
generated
vendored
381
vendor/github.com/coreos/go-systemd/unit/deserialize_test.go
generated
vendored
@ -1,381 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeserialize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input []byte
|
||||
output []*UnitOption
|
||||
}{
|
||||
// multiple options underneath a section
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description=Foo
|
||||
Description=Bar
|
||||
Requires=baz.service
|
||||
After=baz.service
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
&UnitOption{"Unit", "Requires", "baz.service"},
|
||||
&UnitOption{"Unit", "After", "baz.service"},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple sections
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description=Foo
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/sleep infinity
|
||||
|
||||
[X-Third-Party]
|
||||
Pants=on
|
||||
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Service", "ExecStart", "/usr/bin/sleep infinity"},
|
||||
&UnitOption{"X-Third-Party", "Pants", "on"},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple sections with no options
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
[Service]
|
||||
[X-Third-Party]
|
||||
`),
|
||||
[]*UnitOption{},
|
||||
},
|
||||
|
||||
// multiple values not special-cased
|
||||
{
|
||||
[]byte(`[Service]
|
||||
Environment= "FOO=BAR" "BAZ=QUX"
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Service", "Environment", "\"FOO=BAR\" \"BAZ=QUX\""},
|
||||
},
|
||||
},
|
||||
|
||||
// line continuations unmodified
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description= Unnecessarily wrapped \
|
||||
words here
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", `Unnecessarily wrapped \
|
||||
words here`},
|
||||
},
|
||||
},
|
||||
|
||||
// comments ignored
|
||||
{
|
||||
[]byte(`; comment alpha
|
||||
# comment bravo
|
||||
[Unit]
|
||||
; comment charlie
|
||||
# comment delta
|
||||
#Description=Foo
|
||||
Description=Bar
|
||||
; comment echo
|
||||
# comment foxtrot
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// apparent comment lines inside of line continuations not ignored
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description=Bar\
|
||||
# comment alpha
|
||||
|
||||
Description=Bar\
|
||||
# comment bravo \
|
||||
Baz
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar\\\n# comment alpha"},
|
||||
&UnitOption{"Unit", "Description", "Bar\\\n# comment bravo \\\nBaz"},
|
||||
},
|
||||
},
|
||||
|
||||
// options outside of sections are ignored
|
||||
{
|
||||
[]byte(`Description=Foo
|
||||
[Unit]
|
||||
Description=Bar
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// garbage outside of sections are ignored
|
||||
{
|
||||
[]byte(`<<<<<<<<
|
||||
[Unit]
|
||||
Description=Bar
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// garbage used as unit option
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
<<<<<<<<=Bar
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "<<<<<<<<", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// option name with spaces are valid
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Some Thing = Bar
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Some Thing", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// lack of trailing newline doesn't cause problem for non-continued file
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description=Bar`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
},
|
||||
},
|
||||
|
||||
// unit file with continuation but no following line is ok, too
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description=Bar \`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Bar \\"},
|
||||
},
|
||||
},
|
||||
|
||||
// Assert utf8 characters are preserved
|
||||
{
|
||||
[]byte(`[©]
|
||||
µ☃=ÇôrèÕ$`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"©", "µ☃", "ÇôrèÕ$"},
|
||||
},
|
||||
},
|
||||
|
||||
// whitespace removed around option name
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description =words here
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "words here"},
|
||||
},
|
||||
},
|
||||
|
||||
// whitespace around option value stripped
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description= words here `),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "words here"},
|
||||
},
|
||||
},
|
||||
|
||||
// whitespace around option value stripped, regardless of continuation
|
||||
{
|
||||
[]byte(`[Unit]
|
||||
Description= words here \
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "words here \\\n"},
|
||||
},
|
||||
},
|
||||
|
||||
// backslash not considered continuation if followed by text
|
||||
{
|
||||
[]byte(`[Service]
|
||||
ExecStart=/bin/bash -c "while true; do echo \"ping\"; sleep 1; done"
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Service", "ExecStart", `/bin/bash -c "while true; do echo \"ping\"; sleep 1; done"`},
|
||||
},
|
||||
},
|
||||
|
||||
// backslash not considered continuation if followed by whitespace, but still trimmed
|
||||
{
|
||||
[]byte(`[Service]
|
||||
ExecStart=/bin/bash echo poof \ `),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Service", "ExecStart", `/bin/bash echo poof \`},
|
||||
},
|
||||
},
|
||||
// a long unit file line that's just equal to the maximum permitted length
|
||||
{
|
||||
[]byte(`[Service]
|
||||
ExecStart=/bin/bash -c "echo ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................."`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Service", "ExecStart", `/bin/bash -c "echo ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................."`},
|
||||
},
|
||||
},
|
||||
// the same, but with a trailing newline
|
||||
{
|
||||
[]byte(`[Service]
|
||||
ExecStart=/bin/bash -c "echo ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................."
|
||||
Option=value
|
||||
`),
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Service", "ExecStart", `/bin/bash -c "echo ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................."`},
|
||||
&UnitOption{"Service", "Option", "value"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert := func(expect, output []*UnitOption) error {
|
||||
if len(expect) != len(output) {
|
||||
return fmt.Errorf("expected %d items, got %d", len(expect), len(output))
|
||||
}
|
||||
|
||||
for i, _ := range expect {
|
||||
if !reflect.DeepEqual(expect[i], output[i]) {
|
||||
return fmt.Errorf("item %d: expected %v, got %v", i, expect[i], output[i])
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
output, err := Deserialize(bytes.NewReader(tt.input))
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error parsing unit: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = assert(tt.output, output)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: %v", i, err)
|
||||
t.Log("Expected options:")
|
||||
logUnitOptionSlice(t, tt.output)
|
||||
t.Log("Actual options:")
|
||||
logUnitOptionSlice(t, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeserializeFail(t *testing.T) {
|
||||
tests := [][]byte{
|
||||
// malformed section header
|
||||
[]byte(`[Unit
|
||||
Description=Foo
|
||||
`),
|
||||
|
||||
// garbage following section header
|
||||
[]byte(`[Unit] pants
|
||||
Description=Foo
|
||||
`),
|
||||
|
||||
// option without value
|
||||
[]byte(`[Unit]
|
||||
Description
|
||||
`),
|
||||
|
||||
// garbage inside of section
|
||||
[]byte(`[Unit]
|
||||
<<<<<<
|
||||
Description=Foo
|
||||
`),
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
output, err := Deserialize(bytes.NewReader(tt))
|
||||
if err == nil {
|
||||
t.Errorf("case %d: unexpected nil error", i)
|
||||
t.Log("Output:")
|
||||
logUnitOptionSlice(t, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func logUnitOptionSlice(t *testing.T, opts []*UnitOption) {
|
||||
for idx, opt := range opts {
|
||||
t.Logf("%d: %v", idx, opt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeserializeLineTooLong(t *testing.T) {
|
||||
tests := [][]byte{
|
||||
// section header that's far too long
|
||||
[]byte(`[Seeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeervice]
|
||||
`),
|
||||
// sane-looking unit file with a line just greater than the maximum allowed (currently, 2048)
|
||||
[]byte(`[Service]
|
||||
ExecStart=/bin/bash -c "echo ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................."
|
||||
`),
|
||||
// sane-looking unit file with option value way too long
|
||||
[]byte(`
|
||||
# test unit file
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/docker rm %p
|
||||
ExecStartPre=-/usr/bin/docker pull busybox
|
||||
ExecStart=/usr/bin/docker run --rm --name %p --net=host \
|
||||
-e "test=1123t" \
|
||||
-e "test=1123t" \
|
||||
-e "fiz=1123t" \
|
||||
-e "buz=1123t" \
|
||||
-e "FOO=BARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBABARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARRBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBAR"BARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBABARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARRBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBARBAR" \
|
||||
busybox sleep 10
|
||||
ExecStop=-/usr/bin/docker kill %p
|
||||
SyslogIdentifier=busybox
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
`),
|
||||
// single arbitrary line that's way too long
|
||||
[]byte(`arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 character arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 character arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 character arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 character arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters arbitrary and extraordinarily long line that is far greater than 2048 characters`),
|
||||
// sane-looking unit file with option name way too long
|
||||
[]byte(`[Service]
|
||||
ExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStartExecStart=/bin/true
|
||||
`),
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
output, err := Deserialize(bytes.NewReader(tt))
|
||||
if err != ErrLineTooLong {
|
||||
t.Errorf("case %d: unexpected err: %v", i, err)
|
||||
t.Log("Output:")
|
||||
logUnitOptionSlice(t, output)
|
||||
}
|
||||
}
|
||||
}
|
88
vendor/github.com/coreos/go-systemd/unit/end_to_end_test.go
generated
vendored
88
vendor/github.com/coreos/go-systemd/unit/end_to_end_test.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeserializeAndReserialize(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
wout string
|
||||
}{
|
||||
{
|
||||
`[Service]
|
||||
ExecStart=/bin/bash -c "while true; do echo \"ping\"; sleep 1; done"
|
||||
`,
|
||||
`[Service]
|
||||
ExecStart=/bin/bash -c "while true; do echo \"ping\"; sleep 1; done"
|
||||
`},
|
||||
{
|
||||
`[Unit]
|
||||
Description= Unnecessarily wrapped \
|
||||
words here`,
|
||||
`[Unit]
|
||||
Description=Unnecessarily wrapped \
|
||||
words here
|
||||
`,
|
||||
},
|
||||
{
|
||||
`[Unit]
|
||||
Description=Demo \
|
||||
|
||||
Requires=docker.service
|
||||
`,
|
||||
`[Unit]
|
||||
Description=Demo \
|
||||
|
||||
Requires=docker.service
|
||||
`,
|
||||
},
|
||||
{
|
||||
`; comment alpha
|
||||
# comment bravo
|
||||
[Unit]
|
||||
; comment charlie
|
||||
# comment delta
|
||||
#Description=Foo
|
||||
Description=Bar
|
||||
; comment echo
|
||||
# comment foxtrot
|
||||
`,
|
||||
`[Unit]
|
||||
Description=Bar
|
||||
`},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
ds, err := Deserialize(bytes.NewBufferString(tt.in))
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error parsing unit: %v", i, err)
|
||||
continue
|
||||
}
|
||||
out, err := ioutil.ReadAll(Serialize(ds))
|
||||
if err != nil {
|
||||
t.Errorf("case %d: unexpected error serializing unit: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if g := string(out); g != tt.wout {
|
||||
t.Errorf("case %d: incorrect output", i)
|
||||
t.Logf("Expected:\n%#v", tt.wout)
|
||||
t.Logf("Actual:\n%#v", g)
|
||||
}
|
||||
}
|
||||
}
|
116
vendor/github.com/coreos/go-systemd/unit/escape.go
generated
vendored
116
vendor/github.com/coreos/go-systemd/unit/escape.go
generated
vendored
@ -1,116 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Implements systemd-escape [--unescape] [--path]
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
allowed = `:_.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`
|
||||
)
|
||||
|
||||
// If isPath is true:
|
||||
// We remove redundant '/'s, the leading '/', and trailing '/'.
|
||||
// If the result is empty, a '/' is inserted.
|
||||
//
|
||||
// We always:
|
||||
// Replace the following characters with `\x%x`:
|
||||
// Leading `.`
|
||||
// `-`, `\`, and anything not in this set: `:-_.\[0-9a-zA-Z]`
|
||||
// Replace '/' with '-'.
|
||||
func escape(unescaped string, isPath bool) string {
|
||||
e := []byte{}
|
||||
inSlashes := false
|
||||
start := true
|
||||
for i := 0; i < len(unescaped); i++ {
|
||||
c := unescaped[i]
|
||||
if isPath {
|
||||
if c == '/' {
|
||||
inSlashes = true
|
||||
continue
|
||||
} else if inSlashes {
|
||||
inSlashes = false
|
||||
if !start {
|
||||
e = append(e, '-')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c == '/' {
|
||||
e = append(e, '-')
|
||||
} else if start && c == '.' || strings.IndexByte(allowed, c) == -1 {
|
||||
e = append(e, []byte(fmt.Sprintf(`\x%x`, c))...)
|
||||
} else {
|
||||
e = append(e, c)
|
||||
}
|
||||
start = false
|
||||
}
|
||||
if isPath && len(e) == 0 {
|
||||
e = append(e, '-')
|
||||
}
|
||||
return string(e)
|
||||
}
|
||||
|
||||
// If isPath is true:
|
||||
// We always return a string beginning with '/'.
|
||||
//
|
||||
// We always:
|
||||
// Replace '-' with '/'.
|
||||
// Replace `\x%x` with the value represented in hex.
|
||||
func unescape(escaped string, isPath bool) string {
|
||||
u := []byte{}
|
||||
for i := 0; i < len(escaped); i++ {
|
||||
c := escaped[i]
|
||||
if c == '-' {
|
||||
c = '/'
|
||||
} else if c == '\\' && len(escaped)-i >= 4 && escaped[i+1] == 'x' {
|
||||
n, err := strconv.ParseInt(escaped[i+2:i+4], 16, 8)
|
||||
if err == nil {
|
||||
c = byte(n)
|
||||
i += 3
|
||||
}
|
||||
}
|
||||
u = append(u, c)
|
||||
}
|
||||
if isPath && (len(u) == 0 || u[0] != '/') {
|
||||
u = append([]byte("/"), u...)
|
||||
}
|
||||
return string(u)
|
||||
}
|
||||
|
||||
// UnitNameEscape escapes a string as `systemd-escape` would
|
||||
func UnitNameEscape(unescaped string) string {
|
||||
return escape(unescaped, false)
|
||||
}
|
||||
|
||||
// UnitNameUnescape unescapes a string as `systemd-escape --unescape` would
|
||||
func UnitNameUnescape(escaped string) string {
|
||||
return unescape(escaped, false)
|
||||
}
|
||||
|
||||
// UnitNamePathEscape escapes a string as `systemd-escape --path` would
|
||||
func UnitNamePathEscape(unescaped string) string {
|
||||
return escape(unescaped, true)
|
||||
}
|
||||
|
||||
// UnitNamePathUnescape unescapes a string as `systemd-escape --path --unescape` would
|
||||
func UnitNamePathUnescape(escaped string) string {
|
||||
return unescape(escaped, true)
|
||||
}
|
211
vendor/github.com/coreos/go-systemd/unit/escape_test.go
generated
vendored
211
vendor/github.com/coreos/go-systemd/unit/escape_test.go
generated
vendored
@ -1,211 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnitNameEscape(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
out string
|
||||
isPath bool
|
||||
}{
|
||||
// turn empty string path into escaped /
|
||||
{
|
||||
in: "",
|
||||
out: "-",
|
||||
isPath: true,
|
||||
},
|
||||
// turn redundant ////s into single escaped /
|
||||
{
|
||||
in: "/////////",
|
||||
out: "-",
|
||||
isPath: true,
|
||||
},
|
||||
// remove all redundant ////s
|
||||
{
|
||||
in: "///foo////bar/////tail//////",
|
||||
out: "foo-bar-tail",
|
||||
isPath: true,
|
||||
},
|
||||
// leave empty string empty
|
||||
{
|
||||
in: "",
|
||||
out: "",
|
||||
isPath: false,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: ".",
|
||||
out: `\x2e`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: "/.",
|
||||
out: `\x2e`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: "/////////.",
|
||||
out: `\x2e`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: "/////////.///////////////",
|
||||
out: `\x2e`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: ".....",
|
||||
out: `\x2e....`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: "/.foo/.bar",
|
||||
out: `\x2efoo-.bar`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: ".foo/.bar",
|
||||
out: `\x2efoo-.bar`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape leading dot
|
||||
{
|
||||
in: ".foo/.bar",
|
||||
out: `\x2efoo-.bar`,
|
||||
isPath: false,
|
||||
},
|
||||
// escape disallowed
|
||||
{
|
||||
in: `///..\-!#??///`,
|
||||
out: `---..\x5c\x2d\x21\x23\x3f\x3f---`,
|
||||
isPath: false,
|
||||
},
|
||||
// escape disallowed
|
||||
{
|
||||
in: `///..\-!#??///`,
|
||||
out: `\x2e.\x5c\x2d\x21\x23\x3f\x3f`,
|
||||
isPath: true,
|
||||
},
|
||||
// escape real-world example
|
||||
{
|
||||
in: `user-cloudinit@/var/lib/coreos/vagrant/vagrantfile-user-data.service`,
|
||||
out: `user\x2dcloudinit\x40-var-lib-coreos-vagrant-vagrantfile\x2duser\x2ddata.service`,
|
||||
isPath: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
var s string
|
||||
if tt.isPath {
|
||||
s = UnitNamePathEscape(tt.in)
|
||||
} else {
|
||||
s = UnitNameEscape(tt.in)
|
||||
}
|
||||
if s != tt.out {
|
||||
t.Errorf("case %d: failed escaping %v isPath: %v - expected %v, got %v", i, tt.in, tt.isPath, tt.out, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitNameUnescape(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
out string
|
||||
isPath bool
|
||||
}{
|
||||
// turn empty string path into /
|
||||
{
|
||||
in: "",
|
||||
out: "/",
|
||||
isPath: true,
|
||||
},
|
||||
// leave empty string empty
|
||||
{
|
||||
in: "",
|
||||
out: "",
|
||||
isPath: false,
|
||||
},
|
||||
// turn ////s into
|
||||
{
|
||||
in: "---------",
|
||||
out: "/////////",
|
||||
isPath: true,
|
||||
},
|
||||
// unescape hex
|
||||
{
|
||||
in: `---..\x5c\x2d\x21\x23\x3f\x3f---`,
|
||||
out: `///..\-!#??///`,
|
||||
isPath: false,
|
||||
},
|
||||
// unescape hex
|
||||
{
|
||||
in: `\x2e.\x5c\x2d\x21\x23\x3f\x3f`,
|
||||
out: `/..\-!#??`,
|
||||
isPath: true,
|
||||
},
|
||||
// unescape hex, retain invalids
|
||||
{
|
||||
in: `\x2e.\x5c\x2d\xaZ\x.o\x21\x23\x3f\x3f`,
|
||||
out: `/..\-\xaZ\x.o!#??`,
|
||||
isPath: true,
|
||||
},
|
||||
// unescape hex, retain invalids, partial tail
|
||||
{
|
||||
in: `\x2e.\x5c\x\x2d\xaZ\x.o\x21\x23\x3f\x3f\x3`,
|
||||
out: `/..\\x-\xaZ\x.o!#??\x3`,
|
||||
isPath: true,
|
||||
},
|
||||
// unescape hex, retain invalids, partial tail
|
||||
{
|
||||
in: `\x2e.\x5c\x\x2d\xaZ\x.o\x21\x23\x3f\x3f\x`,
|
||||
out: `/..\\x-\xaZ\x.o!#??\x`,
|
||||
isPath: true,
|
||||
},
|
||||
// unescape hex, retain invalids, partial tail
|
||||
{
|
||||
in: `\x2e.\x5c\x\x2d\xaZ\x.o\x21\x23\x3f\x3f\`,
|
||||
out: `/..\\x-\xaZ\x.o!#??\`,
|
||||
isPath: true,
|
||||
},
|
||||
// unescape real-world example
|
||||
{
|
||||
in: `user\x2dcloudinit\x40-var-lib-coreos-vagrant-vagrantfile\x2duser\x2ddata.service`,
|
||||
out: `user-cloudinit@/var/lib/coreos/vagrant/vagrantfile-user-data.service`,
|
||||
isPath: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
var s string
|
||||
if tt.isPath {
|
||||
s = UnitNamePathUnescape(tt.in)
|
||||
} else {
|
||||
s = UnitNameUnescape(tt.in)
|
||||
}
|
||||
if s != tt.out {
|
||||
t.Errorf("case %d: failed unescaping %v isPath: %v - expected %v, got %v", i, tt.in, tt.isPath, tt.out, s)
|
||||
}
|
||||
}
|
||||
}
|
54
vendor/github.com/coreos/go-systemd/unit/option.go
generated
vendored
54
vendor/github.com/coreos/go-systemd/unit/option.go
generated
vendored
@ -1,54 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type UnitOption struct {
|
||||
Section string
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
func NewUnitOption(section, name, value string) *UnitOption {
|
||||
return &UnitOption{Section: section, Name: name, Value: value}
|
||||
}
|
||||
|
||||
func (uo *UnitOption) String() string {
|
||||
return fmt.Sprintf("{Section: %q, Name: %q, Value: %q}", uo.Section, uo.Name, uo.Value)
|
||||
}
|
||||
|
||||
func (uo *UnitOption) Match(other *UnitOption) bool {
|
||||
return uo.Section == other.Section &&
|
||||
uo.Name == other.Name &&
|
||||
uo.Value == other.Value
|
||||
}
|
||||
|
||||
func AllMatch(u1 []*UnitOption, u2 []*UnitOption) bool {
|
||||
length := len(u1)
|
||||
if length != len(u2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
if !u1[i].Match(u2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
214
vendor/github.com/coreos/go-systemd/unit/option_test.go
generated
vendored
214
vendor/github.com/coreos/go-systemd/unit/option_test.go
generated
vendored
@ -1,214 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAllMatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
u1 []*UnitOption
|
||||
u2 []*UnitOption
|
||||
match bool
|
||||
}{
|
||||
// empty lists match
|
||||
{
|
||||
u1: []*UnitOption{},
|
||||
u2: []*UnitOption{},
|
||||
match: true,
|
||||
},
|
||||
|
||||
// simple match of a single option
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
},
|
||||
match: true,
|
||||
},
|
||||
|
||||
// single option mismatched
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "BAR"},
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
|
||||
// multiple options match
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
},
|
||||
match: true,
|
||||
},
|
||||
|
||||
// mismatch length
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
|
||||
// multiple options misordered
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
|
||||
// interleaved sections mismatch
|
||||
{
|
||||
u1: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
{Section: "Service", Name: "ExecStop", Value: "/bin/true"},
|
||||
},
|
||||
u2: []*UnitOption{
|
||||
{Section: "Unit", Name: "Description", Value: "FOO"},
|
||||
{Section: "Service", Name: "ExecStart", Value: "/bin/true"},
|
||||
{Section: "Unit", Name: "BindsTo", Value: "bar.service"},
|
||||
{Section: "Service", Name: "ExecStop", Value: "/bin/true"},
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
match := AllMatch(tt.u1, tt.u2)
|
||||
if match != tt.match {
|
||||
t.Errorf("case %d: failed comparing u1 to u2 - expected match=%t, got %t", i, tt.match, match)
|
||||
}
|
||||
|
||||
match = AllMatch(tt.u2, tt.u1)
|
||||
if match != tt.match {
|
||||
t.Errorf("case %d: failed comparing u2 to u1 - expected match=%t, got %t", i, tt.match, match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
o1 *UnitOption
|
||||
o2 *UnitOption
|
||||
match bool
|
||||
}{
|
||||
// empty options match
|
||||
{
|
||||
o1: &UnitOption{},
|
||||
o2: &UnitOption{},
|
||||
match: true,
|
||||
},
|
||||
|
||||
// all fields match
|
||||
{
|
||||
o1: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
o2: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
match: true,
|
||||
},
|
||||
|
||||
// Section mismatch
|
||||
{
|
||||
o1: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
o2: &UnitOption{
|
||||
Section: "X-Other",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
|
||||
// Name mismatch
|
||||
{
|
||||
o1: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
o2: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "BindsTo",
|
||||
Value: "FOO",
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
|
||||
// Value mismatch
|
||||
{
|
||||
o1: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "FOO",
|
||||
},
|
||||
o2: &UnitOption{
|
||||
Section: "Unit",
|
||||
Name: "Description",
|
||||
Value: "BAR",
|
||||
},
|
||||
match: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
match := tt.o1.Match(tt.o2)
|
||||
if match != tt.match {
|
||||
t.Errorf("case %d: failed comparing o1 to o2 - expected match=%t, got %t", i, tt.match, match)
|
||||
}
|
||||
|
||||
match = tt.o2.Match(tt.o1)
|
||||
if match != tt.match {
|
||||
t.Errorf("case %d: failed comparing o2 to o1 - expected match=%t, got %t", i, tt.match, match)
|
||||
}
|
||||
}
|
||||
}
|
75
vendor/github.com/coreos/go-systemd/unit/serialize.go
generated
vendored
75
vendor/github.com/coreos/go-systemd/unit/serialize.go
generated
vendored
@ -1,75 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Serialize encodes all of the given UnitOption objects into a
|
||||
// unit file. When serialized the options are sorted in their
|
||||
// supplied order but grouped by section.
|
||||
func Serialize(opts []*UnitOption) io.Reader {
|
||||
var buf bytes.Buffer
|
||||
|
||||
if len(opts) == 0 {
|
||||
return &buf
|
||||
}
|
||||
|
||||
// Index of sections -> ordered options
|
||||
idx := map[string][]*UnitOption{}
|
||||
// Separately preserve order in which sections were seen
|
||||
sections := []string{}
|
||||
for _, opt := range opts {
|
||||
sec := opt.Section
|
||||
if _, ok := idx[sec]; !ok {
|
||||
sections = append(sections, sec)
|
||||
}
|
||||
idx[sec] = append(idx[sec], opt)
|
||||
}
|
||||
|
||||
for i, sect := range sections {
|
||||
writeSectionHeader(&buf, sect)
|
||||
writeNewline(&buf)
|
||||
|
||||
opts := idx[sect]
|
||||
for _, opt := range opts {
|
||||
writeOption(&buf, opt)
|
||||
writeNewline(&buf)
|
||||
}
|
||||
if i < len(sections)-1 {
|
||||
writeNewline(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
return &buf
|
||||
}
|
||||
|
||||
func writeNewline(buf *bytes.Buffer) {
|
||||
buf.WriteRune('\n')
|
||||
}
|
||||
|
||||
func writeSectionHeader(buf *bytes.Buffer, section string) {
|
||||
buf.WriteRune('[')
|
||||
buf.WriteString(section)
|
||||
buf.WriteRune(']')
|
||||
}
|
||||
|
||||
func writeOption(buf *bytes.Buffer, opt *UnitOption) {
|
||||
buf.WriteString(opt.Name)
|
||||
buf.WriteRune('=')
|
||||
buf.WriteString(opt.Value)
|
||||
}
|
170
vendor/github.com/coreos/go-systemd/unit/serialize_test.go
generated
vendored
170
vendor/github.com/coreos/go-systemd/unit/serialize_test.go
generated
vendored
@ -1,170 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package unit
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSerialize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input []*UnitOption
|
||||
output string
|
||||
}{
|
||||
// no options results in empty file
|
||||
{
|
||||
[]*UnitOption{},
|
||||
``,
|
||||
},
|
||||
|
||||
// options with same section share the header
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Unit", "BindsTo", "bar.service"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Foo
|
||||
BindsTo=bar.service
|
||||
`,
|
||||
},
|
||||
|
||||
// options with same name are not combined
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Unit", "Description", "Bar"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Foo
|
||||
Description=Bar
|
||||
`,
|
||||
},
|
||||
|
||||
// multiple options printed under different section headers
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Service", "ExecStart", "/usr/bin/sleep infinity"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Foo
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/sleep infinity
|
||||
`,
|
||||
},
|
||||
|
||||
// options are grouped into sections
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Service", "ExecStart", "/usr/bin/sleep infinity"},
|
||||
&UnitOption{"Unit", "BindsTo", "bar.service"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Foo
|
||||
BindsTo=bar.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/sleep infinity
|
||||
`,
|
||||
},
|
||||
|
||||
// options are ordered within groups, and sections are ordered in the order in which they were first seen
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Foo"},
|
||||
&UnitOption{"Service", "ExecStart", "/usr/bin/sleep infinity"},
|
||||
&UnitOption{"Unit", "BindsTo", "bar.service"},
|
||||
&UnitOption{"X-Foo", "Bar", "baz"},
|
||||
&UnitOption{"Service", "ExecStop", "/usr/bin/sleep 1"},
|
||||
&UnitOption{"Unit", "Documentation", "https://foo.com"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Foo
|
||||
BindsTo=bar.service
|
||||
Documentation=https://foo.com
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/sleep infinity
|
||||
ExecStop=/usr/bin/sleep 1
|
||||
|
||||
[X-Foo]
|
||||
Bar=baz
|
||||
`,
|
||||
},
|
||||
|
||||
// utf8 characters are not a problem
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"©", "µ☃", "ÇôrèÕ$"},
|
||||
},
|
||||
`[©]
|
||||
µ☃=ÇôrèÕ$
|
||||
`,
|
||||
},
|
||||
|
||||
// no verification is done on section names
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Un\nit", "Description", "Foo"},
|
||||
},
|
||||
`[Un
|
||||
it]
|
||||
Description=Foo
|
||||
`,
|
||||
},
|
||||
|
||||
// no verification is done on option names
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Desc\nription", "Foo"},
|
||||
},
|
||||
`[Unit]
|
||||
Desc
|
||||
ription=Foo
|
||||
`,
|
||||
},
|
||||
|
||||
// no verification is done on option values
|
||||
{
|
||||
[]*UnitOption{
|
||||
&UnitOption{"Unit", "Description", "Fo\no"},
|
||||
},
|
||||
`[Unit]
|
||||
Description=Fo
|
||||
o
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
outReader := Serialize(tt.input)
|
||||
outBytes, err := ioutil.ReadAll(outReader)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: encountered error while reading output: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
output := string(outBytes)
|
||||
if tt.output != output {
|
||||
t.Errorf("case %d: incorrect output", i)
|
||||
t.Logf("Expected:\n%s", tt.output)
|
||||
t.Logf("Actual:\n%s", output)
|
||||
}
|
||||
}
|
||||
}
|
270
vendor/github.com/coreos/go-systemd/util/util.go
generated
vendored
270
vendor/github.com/coreos/go-systemd/util/util.go
generated
vendored
@ -1,270 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package util contains utility functions related to systemd that applications
|
||||
// can use to check things like whether systemd is running. Note that some of
|
||||
// these functions attempt to manually load systemd libraries at runtime rather
|
||||
// than linking against them.
|
||||
package util
|
||||
|
||||
// #cgo LDFLAGS: -ldl
|
||||
// #include <stdlib.h>
|
||||
// #include <dlfcn.h>
|
||||
// #include <sys/types.h>
|
||||
// #include <unistd.h>
|
||||
//
|
||||
// int
|
||||
// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
|
||||
// {
|
||||
// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
|
||||
//
|
||||
// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
|
||||
// return sd_pid_get_owner_uid(pid, uid);
|
||||
// }
|
||||
//
|
||||
// int
|
||||
// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
|
||||
// {
|
||||
// int (*sd_pid_get_unit)(pid_t, char **);
|
||||
//
|
||||
// sd_pid_get_unit = (int (*)(pid_t, char **))f;
|
||||
// return sd_pid_get_unit(pid, unit);
|
||||
// }
|
||||
//
|
||||
// int
|
||||
// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
|
||||
// {
|
||||
// int (*sd_pid_get_slice)(pid_t, char **);
|
||||
//
|
||||
// sd_pid_get_slice = (int (*)(pid_t, char **))f;
|
||||
// return sd_pid_get_slice(pid, slice);
|
||||
// }
|
||||
//
|
||||
// int
|
||||
// am_session_leader()
|
||||
// {
|
||||
// return (getsid(0) == getpid());
|
||||
// }
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var ErrSoNotFound = errors.New("unable to open a handle to libsystemd")
|
||||
|
||||
// libHandle represents an open handle to the systemd C library
|
||||
type libHandle struct {
|
||||
handle unsafe.Pointer
|
||||
libname string
|
||||
}
|
||||
|
||||
func (h *libHandle) Close() error {
|
||||
if r := C.dlclose(h.handle); r != 0 {
|
||||
return fmt.Errorf("error closing %v: %d", h.libname, r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getHandle tries to get a handle to a systemd library (.so), attempting to
|
||||
// access it by several different names and returning the first that is
|
||||
// successfully opened. Callers are responsible for closing the handler.
|
||||
// If no library can be successfully opened, an error is returned.
|
||||
func getHandle() (*libHandle, error) {
|
||||
for _, name := range []string{
|
||||
// systemd < 209
|
||||
"libsystemd-login.so",
|
||||
"libsystemd-login.so.0",
|
||||
|
||||
// systemd >= 209 merged libsystemd-login into libsystemd proper
|
||||
"libsystemd.so",
|
||||
"libsystemd.so.0",
|
||||
} {
|
||||
libname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(libname))
|
||||
handle := C.dlopen(libname, C.RTLD_LAZY)
|
||||
if handle != nil {
|
||||
h := &libHandle{
|
||||
handle: handle,
|
||||
libname: name,
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrSoNotFound
|
||||
}
|
||||
|
||||
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
|
||||
// the current process is running.
|
||||
// This function is a wrapper around the libsystemd C library; if it cannot be
|
||||
// opened, an error is returned.
|
||||
func GetRunningSlice() (slice string, err error) {
|
||||
var h *libHandle
|
||||
h, err = getHandle()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err1 := h.Close(); err1 != nil {
|
||||
err = err1
|
||||
}
|
||||
}()
|
||||
|
||||
sym := C.CString("sd_pid_get_slice")
|
||||
defer C.free(unsafe.Pointer(sym))
|
||||
sd_pid_get_slice := C.dlsym(h.handle, sym)
|
||||
if sd_pid_get_slice == nil {
|
||||
err = fmt.Errorf("error resolving sd_pid_get_slice function")
|
||||
return
|
||||
}
|
||||
|
||||
var s string
|
||||
sl := C.CString(s)
|
||||
defer C.free(unsafe.Pointer(sl))
|
||||
|
||||
ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
|
||||
if ret < 0 {
|
||||
err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
|
||||
return
|
||||
}
|
||||
|
||||
return C.GoString(sl), nil
|
||||
}
|
||||
|
||||
// RunningFromSystemService tries to detect whether the current process has
|
||||
// been invoked from a system service. The condition for this is whether the
|
||||
// process is _not_ a user process. User processes are those running in session
|
||||
// scopes or under per-user `systemd --user` instances.
|
||||
//
|
||||
// To avoid false positives on systems without `pam_systemd` (which is
|
||||
// responsible for creating user sessions), this function also uses a heuristic
|
||||
// to detect whether it's being invoked from a session leader process. This is
|
||||
// the case if the current process is executed directly from a service file
|
||||
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
|
||||
// command is instead launched in a subshell or similar so that it is not
|
||||
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
|
||||
//
|
||||
// This function is a wrapper around the libsystemd C library; if this is
|
||||
// unable to successfully open a handle to the library for any reason (e.g. it
|
||||
// cannot be found), an errr will be returned
|
||||
func RunningFromSystemService() (ret bool, err error) {
|
||||
var h *libHandle
|
||||
h, err = getHandle()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err1 := h.Close(); err1 != nil {
|
||||
err = err1
|
||||
}
|
||||
}()
|
||||
|
||||
sym := C.CString("sd_pid_get_owner_uid")
|
||||
defer C.free(unsafe.Pointer(sym))
|
||||
sd_pid_get_owner_uid := C.dlsym(h.handle, sym)
|
||||
if sd_pid_get_owner_uid == nil {
|
||||
err = fmt.Errorf("error resolving sd_pid_get_owner_uid function")
|
||||
return
|
||||
}
|
||||
|
||||
var uid C.uid_t
|
||||
errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
|
||||
serrno := syscall.Errno(-errno)
|
||||
// when we're running from a unit file, sd_pid_get_owner_uid returns
|
||||
// ENOENT (systemd <220) or ENXIO (systemd >=220)
|
||||
switch {
|
||||
case errno >= 0:
|
||||
ret = false
|
||||
case serrno == syscall.ENOENT, serrno == syscall.ENXIO:
|
||||
// Since the implementation of sessions in systemd relies on
|
||||
// the `pam_systemd` module, using the sd_pid_get_owner_uid
|
||||
// heuristic alone can result in false positives if that module
|
||||
// (or PAM itself) is not present or properly configured on the
|
||||
// system. As such, we also check if we're the session leader,
|
||||
// which should be the case if we're invoked from a unit file,
|
||||
// but not if e.g. we're invoked from the command line from a
|
||||
// user's login session
|
||||
ret = C.am_session_leader() == 1
|
||||
default:
|
||||
err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CurrentUnitName attempts to retrieve the name of the systemd system unit
|
||||
// from which the calling process has been invoked. It wraps the systemd
|
||||
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
|
||||
// systemd system unit, this function will return an error.
|
||||
func CurrentUnitName() (unit string, err error) {
|
||||
var h *libHandle
|
||||
h, err = getHandle()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err1 := h.Close(); err1 != nil {
|
||||
err = err1
|
||||
}
|
||||
}()
|
||||
|
||||
sym := C.CString("sd_pid_get_unit")
|
||||
defer C.free(unsafe.Pointer(sym))
|
||||
sd_pid_get_unit := C.dlsym(h.handle, sym)
|
||||
if sd_pid_get_unit == nil {
|
||||
err = fmt.Errorf("error resolving sd_pid_get_unit function")
|
||||
return
|
||||
}
|
||||
|
||||
var s string
|
||||
u := C.CString(s)
|
||||
defer C.free(unsafe.Pointer(u))
|
||||
|
||||
ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
|
||||
if ret < 0 {
|
||||
err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
|
||||
return
|
||||
}
|
||||
|
||||
unit = C.GoString(u)
|
||||
return
|
||||
}
|
||||
|
||||
// IsRunningSystemd checks whether the host was booted with systemd as its init
|
||||
// system. This functions similarly to systemd's `sd_booted(3)`: internally, it
|
||||
// checks whether /run/systemd/system/ exists and is a directory.
|
||||
// http://www.freedesktop.org/software/systemd/man/sd_booted.html
|
||||
func IsRunningSystemd() bool {
|
||||
fi, err := os.Lstat("/run/systemd/system")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return fi.IsDir()
|
||||
}
|
||||
|
||||
// GetMachineID returns a host's 128-bit machine ID as a string. This functions
|
||||
// similarly to systemd's `sd_id128_get_machine`: internally, it simply reads
|
||||
// the contents of /etc/machine-id
|
||||
// http://www.freedesktop.org/software/systemd/man/sd_id128_get_machine.html
|
||||
func GetMachineID() (string, error) {
|
||||
machineID, err := ioutil.ReadFile("/etc/machine-id")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read /etc/machine-id: %v", err)
|
||||
}
|
||||
return strings.TrimSpace(string(machineID)), nil
|
||||
}
|
8
vendor/github.com/coreos/pkg/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/coreos/pkg/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5.4
|
||||
- 1.6.2
|
||||
|
||||
script:
|
||||
- ./test
|
3
vendor/github.com/coreos/pkg/README.md
generated
vendored
3
vendor/github.com/coreos/pkg/README.md
generated
vendored
@ -1,3 +1,4 @@
|
||||
a collection of go utility packages
|
||||
|
||||
[![Build Status](https://semaphoreci.com/api/v1/projects/14b3f261-22c2-4f56-b1ff-f23f4aa03f5c/411991/badge.svg)](https://semaphoreci.com/coreos/pkg) [![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/coreos/pkg)
|
||||
[![Build Status](https://travis-ci.org/coreos/pkg.png?branch=master)](https://travis-ci.org/coreos/pkg)
|
||||
[![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/coreos/pkg)
|
||||
|
53
vendor/github.com/coreos/pkg/capnslog/formatters.go
generated
vendored
53
vendor/github.com/coreos/pkg/capnslog/formatters.go
generated
vendored
@ -18,6 +18,7 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@ -28,7 +29,7 @@ type Formatter interface {
|
||||
Flush()
|
||||
}
|
||||
|
||||
func NewStringFormatter(w io.Writer) *StringFormatter {
|
||||
func NewStringFormatter(w io.Writer) Formatter {
|
||||
return &StringFormatter{
|
||||
w: bufio.NewWriter(w),
|
||||
}
|
||||
@ -104,3 +105,53 @@ func (c *PrettyFormatter) Format(pkg string, l LogLevel, depth int, entries ...i
|
||||
func (c *PrettyFormatter) Flush() {
|
||||
c.w.Flush()
|
||||
}
|
||||
|
||||
// LogFormatter emulates the form of the traditional built-in logger.
|
||||
type LogFormatter struct {
|
||||
logger *log.Logger
|
||||
prefix string
|
||||
}
|
||||
|
||||
// NewLogFormatter is a helper to produce a new LogFormatter struct. It uses the
|
||||
// golang log package to actually do the logging work so that logs look similar.
|
||||
func NewLogFormatter(w io.Writer, prefix string, flag int) Formatter {
|
||||
return &LogFormatter{
|
||||
logger: log.New(w, "", flag), // don't use prefix here
|
||||
prefix: prefix, // save it instead
|
||||
}
|
||||
}
|
||||
|
||||
// Format builds a log message for the LogFormatter. The LogLevel is ignored.
|
||||
func (lf *LogFormatter) Format(pkg string, _ LogLevel, _ int, entries ...interface{}) {
|
||||
str := fmt.Sprint(entries...)
|
||||
prefix := lf.prefix
|
||||
if pkg != "" {
|
||||
prefix = fmt.Sprintf("%s%s: ", prefix, pkg)
|
||||
}
|
||||
lf.logger.Output(5, fmt.Sprintf("%s%v", prefix, str)) // call depth is 5
|
||||
}
|
||||
|
||||
// Flush is included so that the interface is complete, but is a no-op.
|
||||
func (lf *LogFormatter) Flush() {
|
||||
// noop
|
||||
}
|
||||
|
||||
// NilFormatter is a no-op log formatter that does nothing.
|
||||
type NilFormatter struct {
|
||||
}
|
||||
|
||||
// NewNilFormatter is a helper to produce a new LogFormatter struct. It logs no
|
||||
// messages so that you can cause part of your logging to be silent.
|
||||
func NewNilFormatter() Formatter {
|
||||
return &NilFormatter{}
|
||||
}
|
||||
|
||||
// Format does nothing.
|
||||
func (_ *NilFormatter) Format(_ string, _ LogLevel, _ int, _ ...interface{}) {
|
||||
// noop
|
||||
}
|
||||
|
||||
// Flush is included so that the interface is complete, but is a no-op.
|
||||
func (_ *NilFormatter) Flush() {
|
||||
// noop
|
||||
}
|
||||
|
41
vendor/github.com/coreos/pkg/capnslog/pkg_logger.go
generated
vendored
41
vendor/github.com/coreos/pkg/capnslog/pkg_logger.go
generated
vendored
@ -27,17 +27,19 @@ type PackageLogger struct {
|
||||
const calldepth = 2
|
||||
|
||||
func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...interface{}) {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
if inLevel != CRITICAL && p.level < inLevel {
|
||||
return
|
||||
}
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
if logger.formatter != nil {
|
||||
logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PackageLogger) LevelAt(l LogLevel) bool {
|
||||
logger.Lock()
|
||||
defer logger.Unlock()
|
||||
return p.level >= l
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@ func (p *PackageLogger) Println(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Printf(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
|
||||
p.Logf(INFO, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Print(args ...interface{}) {
|
||||
@ -80,8 +82,7 @@ func (p *PackageLogger) Panic(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
|
||||
s := fmt.Sprintf(format, args...)
|
||||
p.internalLog(calldepth, CRITICAL, s)
|
||||
p.Logf(CRITICAL, format, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@ -91,10 +92,16 @@ func (p *PackageLogger) Fatal(args ...interface{}) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Fatalln(args ...interface{}) {
|
||||
s := fmt.Sprintln(args...)
|
||||
p.internalLog(calldepth, CRITICAL, s)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Error Functions
|
||||
|
||||
func (p *PackageLogger) Errorf(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, ERROR, fmt.Sprintf(format, args...))
|
||||
p.Logf(ERROR, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Error(entries ...interface{}) {
|
||||
@ -104,7 +111,7 @@ func (p *PackageLogger) Error(entries ...interface{}) {
|
||||
// Warning Functions
|
||||
|
||||
func (p *PackageLogger) Warningf(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, WARNING, fmt.Sprintf(format, args...))
|
||||
p.Logf(WARNING, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Warning(entries ...interface{}) {
|
||||
@ -114,7 +121,7 @@ func (p *PackageLogger) Warning(entries ...interface{}) {
|
||||
// Notice Functions
|
||||
|
||||
func (p *PackageLogger) Noticef(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, NOTICE, fmt.Sprintf(format, args...))
|
||||
p.Logf(NOTICE, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Notice(entries ...interface{}) {
|
||||
@ -124,7 +131,7 @@ func (p *PackageLogger) Notice(entries ...interface{}) {
|
||||
// Info Functions
|
||||
|
||||
func (p *PackageLogger) Infof(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
|
||||
p.Logf(INFO, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Info(entries ...interface{}) {
|
||||
@ -134,20 +141,32 @@ func (p *PackageLogger) Info(entries ...interface{}) {
|
||||
// Debug Functions
|
||||
|
||||
func (p *PackageLogger) Debugf(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, DEBUG, fmt.Sprintf(format, args...))
|
||||
if p.level < DEBUG {
|
||||
return
|
||||
}
|
||||
p.Logf(DEBUG, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Debug(entries ...interface{}) {
|
||||
if p.level < DEBUG {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, DEBUG, entries...)
|
||||
}
|
||||
|
||||
// Trace Functions
|
||||
|
||||
func (p *PackageLogger) Tracef(format string, args ...interface{}) {
|
||||
p.internalLog(calldepth, TRACE, fmt.Sprintf(format, args...))
|
||||
if p.level < TRACE {
|
||||
return
|
||||
}
|
||||
p.Logf(TRACE, format, args...)
|
||||
}
|
||||
|
||||
func (p *PackageLogger) Trace(entries ...interface{}) {
|
||||
if p.level < TRACE {
|
||||
return
|
||||
}
|
||||
p.internalLog(calldepth, TRACE, entries...)
|
||||
}
|
||||
|
||||
|
82
vendor/github.com/coreos/pkg/dlopen/dlopen.go
generated
vendored
Normal file
82
vendor/github.com/coreos/pkg/dlopen/dlopen.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2016 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package dlopen provides some convenience functions to dlopen a library and
|
||||
// get its symbols.
|
||||
package dlopen
|
||||
|
||||
// #cgo LDFLAGS: -ldl
|
||||
// #include <stdlib.h>
|
||||
// #include <dlfcn.h>
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var ErrSoNotFound = errors.New("unable to open a handle to the library")
|
||||
|
||||
// LibHandle represents an open handle to a library (.so)
|
||||
type LibHandle struct {
|
||||
Handle unsafe.Pointer
|
||||
Libname string
|
||||
}
|
||||
|
||||
// GetHandle tries to get a handle to a library (.so), attempting to access it
|
||||
// by the names specified in libs and returning the first that is successfully
|
||||
// opened. Callers are responsible for closing the handler. If no library can
|
||||
// be successfully opened, an error is returned.
|
||||
func GetHandle(libs []string) (*LibHandle, error) {
|
||||
for _, name := range libs {
|
||||
libname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(libname))
|
||||
handle := C.dlopen(libname, C.RTLD_LAZY)
|
||||
if handle != nil {
|
||||
h := &LibHandle{
|
||||
Handle: handle,
|
||||
Libname: name,
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrSoNotFound
|
||||
}
|
||||
|
||||
// GetSymbolPointer takes a symbol name and returns a pointer to the symbol.
|
||||
func (l *LibHandle) GetSymbolPointer(symbol string) (unsafe.Pointer, error) {
|
||||
sym := C.CString(symbol)
|
||||
defer C.free(unsafe.Pointer(sym))
|
||||
|
||||
C.dlerror()
|
||||
p := C.dlsym(l.Handle, sym)
|
||||
e := C.dlerror()
|
||||
if e != nil {
|
||||
return nil, fmt.Errorf("error resolving symbol %q: %v", symbol, errors.New(C.GoString(e)))
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Close closes a LibHandle.
|
||||
func (l *LibHandle) Close() error {
|
||||
C.dlerror()
|
||||
C.dlclose(l.Handle)
|
||||
e := C.dlerror()
|
||||
if e != nil {
|
||||
return fmt.Errorf("error closing %v: %v", l.Libname, errors.New(C.GoString(e)))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
56
vendor/github.com/coreos/pkg/dlopen/dlopen_example.go
generated
vendored
Normal file
56
vendor/github.com/coreos/pkg/dlopen/dlopen_example.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// +build linux
|
||||
|
||||
package dlopen
|
||||
|
||||
// #include <string.h>
|
||||
// #include <stdlib.h>
|
||||
//
|
||||
// int
|
||||
// my_strlen(void *f, const char *s)
|
||||
// {
|
||||
// size_t (*strlen)(const char *);
|
||||
//
|
||||
// strlen = (size_t (*)(const char *))f;
|
||||
// return strlen(s);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func strlen(libs []string, s string) (int, error) {
|
||||
h, err := GetHandle(libs)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf(`couldn't get a handle to the library: %v`, err)
|
||||
}
|
||||
defer h.Close()
|
||||
|
||||
f := "strlen"
|
||||
cs := C.CString(s)
|
||||
defer C.free(unsafe.Pointer(cs))
|
||||
|
||||
strlen, err := h.GetSymbolPointer(f)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf(`couldn't get symbol %q: %v`, f, err)
|
||||
}
|
||||
|
||||
len := C.my_strlen(strlen, cs)
|
||||
|
||||
return int(len), nil
|
||||
}
|
63
vendor/github.com/coreos/pkg/dlopen/dlopen_test.go
generated
vendored
Normal file
63
vendor/github.com/coreos/pkg/dlopen/dlopen_test.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package dlopen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func checkFailure(shouldSucceed bool, err error) (rErr error) {
|
||||
switch {
|
||||
case err != nil && shouldSucceed:
|
||||
rErr = fmt.Errorf("expected test to succeed, failed unexpectedly: %v", err)
|
||||
case err == nil && !shouldSucceed:
|
||||
rErr = fmt.Errorf("expected test to fail, succeeded unexpectedly")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestDlopen(t *testing.T) {
|
||||
tests := []struct {
|
||||
libs []string
|
||||
shouldSucceed bool
|
||||
}{
|
||||
{
|
||||
libs: []string{
|
||||
"libc.so.6",
|
||||
"libc.so",
|
||||
},
|
||||
shouldSucceed: true,
|
||||
},
|
||||
{
|
||||
libs: []string{
|
||||
"libstrange.so",
|
||||
},
|
||||
shouldSucceed: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
expLen := 4
|
||||
len, err := strlen(tt.libs, "test")
|
||||
if checkFailure(tt.shouldSucceed, err) != nil {
|
||||
t.Errorf("case %d: %v", i, err)
|
||||
}
|
||||
|
||||
if tt.shouldSucceed && len != expLen {
|
||||
t.Errorf("case %d: expected length %d, got %d", i, expLen, len)
|
||||
}
|
||||
}
|
||||
}
|
77
vendor/github.com/coreos/pkg/flagutil/env_file.go
generated
vendored
Normal file
77
vendor/github.com/coreos/pkg/flagutil/env_file.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package flagutil
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetFlagsFromEnvFile iterates the given flagset and if any flags are not
|
||||
// already set it attempts to set their values from the given env file. Env
|
||||
// files may have KEY=VALUE lines where the environment variable names are
|
||||
// in UPPERCASE, prefixed by the given PREFIX, and dashes are replaced by
|
||||
// underscores. For example, if prefix=PREFIX, some-flag is named
|
||||
// PREFIX_SOME_FLAG.
|
||||
// Comment lines are skipped, but more complex env file parsing is not
|
||||
// performed.
|
||||
func SetFlagsFromEnvFile(fs *flag.FlagSet, prefix string, path string) (err error) {
|
||||
alreadySet := make(map[string]bool)
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
alreadySet[f.Name] = true
|
||||
})
|
||||
envs, err := parseEnvFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
if !alreadySet[f.Name] {
|
||||
key := prefix + "_" + strings.ToUpper(strings.Replace(f.Name, "-", "_", -1))
|
||||
val := envs[key]
|
||||
if val != "" {
|
||||
if serr := fs.Set(f.Name, val); serr != nil {
|
||||
err = fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func parseEnvFile(path string) (map[string]string, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
envs := make(map[string]string)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
token := scanner.Text()
|
||||
if !skipLine(token) {
|
||||
key, val, err := parseLine(token)
|
||||
if err == nil {
|
||||
envs[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
return envs, nil
|
||||
}
|
||||
|
||||
func skipLine(line string) bool {
|
||||
return len(line) == 0 || strings.HasPrefix(line, "#")
|
||||
}
|
||||
|
||||
func parseLine(line string) (key string, val string, err error) {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
pair := strings.SplitN(trimmed, "=", 2)
|
||||
if len(pair) != 2 {
|
||||
err = fmt.Errorf("invalid KEY=value line: %q", line)
|
||||
return
|
||||
}
|
||||
key = strings.TrimSpace(pair[0])
|
||||
val = strings.TrimSpace(pair[1])
|
||||
return
|
||||
}
|
107
vendor/github.com/coreos/pkg/flagutil/file_env_test.go
generated
vendored
Normal file
107
vendor/github.com/coreos/pkg/flagutil/file_env_test.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
package flagutil
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var envFile = `
|
||||
# some secret env vars
|
||||
MYPROJ_A=foo
|
||||
MYPROJ_C=woof
|
||||
`
|
||||
|
||||
func TestSetFlagsFromEnvFile(t *testing.T) {
|
||||
fs := flag.NewFlagSet("testing", flag.ExitOnError)
|
||||
fs.String("a", "", "")
|
||||
fs.String("b", "", "")
|
||||
fs.String("c", "", "")
|
||||
fs.Parse([]string{})
|
||||
|
||||
// add command-line flags
|
||||
if err := fs.Set("b", "bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fs.Set("c", "quack"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// first verify that flags are as expected before reading the env
|
||||
for f, want := range map[string]string{
|
||||
"a": "",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Fatalf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
file, err := ioutil.TempFile("", "env-file")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(file.Name())
|
||||
file.Write([]byte(envFile))
|
||||
|
||||
// read env file and verify flags were updated as expected
|
||||
err = SetFlagsFromEnvFile(fs, "MYPROJ", file.Name())
|
||||
if err != nil {
|
||||
t.Errorf("err=%v, want nil", err)
|
||||
}
|
||||
for f, want := range map[string]string{
|
||||
"a": "foo",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Errorf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFlagsFromEnvFile_FlagSetError(t *testing.T) {
|
||||
// now verify that an error is propagated
|
||||
fs := flag.NewFlagSet("testing", flag.ExitOnError)
|
||||
fs.Int("x", 0, "")
|
||||
file, err := ioutil.TempFile("", "env-file")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(file.Name())
|
||||
file.Write([]byte("MYPROJ_X=not_a_number"))
|
||||
if err := SetFlagsFromEnvFile(fs, "MYPROJ", file.Name()); err == nil {
|
||||
t.Errorf("err=nil, want != nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLine(t *testing.T) {
|
||||
cases := []struct {
|
||||
line string
|
||||
expectedKey string
|
||||
expectedVal string
|
||||
nilErr bool
|
||||
}{
|
||||
{"key=value", "key", "value", true},
|
||||
{" key = value ", "key", "value", true},
|
||||
{"key='#gopher' #blah", "key", "'#gopher' #blah", true},
|
||||
// invalid
|
||||
{"key:value", "", "", false},
|
||||
{"keyvalue", "", "", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
key, val, err := parseLine(c.line)
|
||||
if (err == nil) != c.nilErr {
|
||||
if c.nilErr {
|
||||
t.Errorf("got %s, want err=nil", err)
|
||||
} else {
|
||||
t.Errorf("got err=nil, want err!=nil")
|
||||
}
|
||||
}
|
||||
if c.expectedKey != key || c.expectedVal != val {
|
||||
t.Errorf("got %q=%q, want %q=%q", key, val, c.expectedKey, c.expectedVal)
|
||||
}
|
||||
}
|
||||
}
|
140
vendor/github.com/coreos/pkg/k8s-tlsutil/k8s-tlsutil.go
generated
vendored
Normal file
140
vendor/github.com/coreos/pkg/k8s-tlsutil/k8s-tlsutil.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
package k8stlsutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
RSAKeySize = 2048
|
||||
Duration365d = time.Hour * 24 * 365
|
||||
)
|
||||
|
||||
type CertConfig struct {
|
||||
CommonName string
|
||||
Organization []string
|
||||
AltNames AltNames
|
||||
}
|
||||
|
||||
// AltNames contains the domain names and IP addresses that will be added
|
||||
// to the API Server's x509 certificate SubAltNames field. The values will
|
||||
// be passed directly to the x509.Certificate object.
|
||||
type AltNames struct {
|
||||
DNSNames []string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
func NewPrivateKey() (*rsa.PrivateKey, error) {
|
||||
return rsa.GenerateKey(rand.Reader, RSAKeySize)
|
||||
}
|
||||
|
||||
func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
|
||||
der, err := x509.MarshalPKIXPublicKey(key)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
block := pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
return pem.EncodeToMemory(&block), nil
|
||||
}
|
||||
|
||||
func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
|
||||
block := pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
||||
}
|
||||
return pem.EncodeToMemory(&block)
|
||||
}
|
||||
|
||||
func EncodeCertificatePEM(cert *x509.Certificate) []byte {
|
||||
block := pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: cert.Raw,
|
||||
}
|
||||
return pem.EncodeToMemory(&block)
|
||||
}
|
||||
|
||||
func NewSelfSignedCACertificate(cfg CertConfig, key *rsa.PrivateKey, validDuration time.Duration) (*x509.Certificate, error) {
|
||||
now := time.Now()
|
||||
|
||||
dur := Duration365d * 10
|
||||
if validDuration != 0 {
|
||||
dur = validDuration
|
||||
}
|
||||
|
||||
tmpl := x509.Certificate{
|
||||
SerialNumber: new(big.Int).SetInt64(0),
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: cfg.Organization,
|
||||
},
|
||||
NotBefore: now,
|
||||
NotAfter: now.Add(dur),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
certDERBytes, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x509.ParseCertificate(certDERBytes)
|
||||
}
|
||||
|
||||
func ParsePEMEncodedCACert(pemdata []byte) (*x509.Certificate, error) {
|
||||
decoded, _ := pem.Decode(pemdata)
|
||||
if decoded == nil {
|
||||
return nil, errors.New("no PEM data found")
|
||||
}
|
||||
return x509.ParseCertificate(decoded.Bytes)
|
||||
}
|
||||
|
||||
func ParsePEMEncodedPrivateKey(pemdata []byte) (*rsa.PrivateKey, error) {
|
||||
decoded, _ := pem.Decode(pemdata)
|
||||
if decoded == nil {
|
||||
return nil, errors.New("no PEM data found")
|
||||
}
|
||||
return x509.ParsePKCS1PrivateKey(decoded.Bytes)
|
||||
}
|
||||
|
||||
func NewSignedCertificate(cfg CertConfig, key *rsa.PrivateKey, caCert *x509.Certificate, caKey *rsa.PrivateKey, validDuration time.Duration) (*x509.Certificate, error) {
|
||||
serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dur := Duration365d
|
||||
if validDuration != 0 {
|
||||
dur = validDuration
|
||||
}
|
||||
|
||||
certTmpl := x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: caCert.Subject.Organization,
|
||||
},
|
||||
DNSNames: cfg.AltNames.DNSNames,
|
||||
IPAddresses: cfg.AltNames.IPs,
|
||||
SerialNumber: serial,
|
||||
NotBefore: caCert.NotBefore,
|
||||
NotAfter: time.Now().Add(dur),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
certDERBytes, err := x509.CreateCertificate(rand.Reader, &certTmpl, caCert, key.Public(), caKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x509.ParseCertificate(certDERBytes)
|
||||
}
|
13
vendor/github.com/coreos/pkg/netutil/proxy.go
generated
vendored
13
vendor/github.com/coreos/pkg/netutil/proxy.go
generated
vendored
@ -2,15 +2,10 @@ package netutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var (
|
||||
log = capnslog.NewPackageLogger("github.com/coreos/pkg/netutil", "main")
|
||||
)
|
||||
|
||||
// ProxyTCP proxies between two TCP connections.
|
||||
@ -30,9 +25,9 @@ func ProxyTCP(conn1, conn2 net.Conn, tlsWriteDeadline, tlsReadDeadline time.Dura
|
||||
|
||||
func copyBytes(dst, src net.Conn, wg *sync.WaitGroup, writeDeadline, readDeadline time.Duration) {
|
||||
defer wg.Done()
|
||||
n, err := io.Copy(dst, src)
|
||||
_, err := io.Copy(dst, src)
|
||||
if err != nil {
|
||||
log.Errorf("proxy i/o error: %v", err)
|
||||
log.Printf("proxy i/o error: %v", err)
|
||||
}
|
||||
|
||||
if cr, ok := src.(*net.TCPConn); ok {
|
||||
@ -50,6 +45,4 @@ func copyBytes(dst, src net.Conn, wg *sync.WaitGroup, writeDeadline, readDeadlin
|
||||
rto := time.Now().Add(readDeadline)
|
||||
dst.SetReadDeadline(rto)
|
||||
}
|
||||
|
||||
log.Debugf("proxy copied %d bytes %s -> %s", n, src.RemoteAddr(), dst.RemoteAddr())
|
||||
}
|
||||
|
189
vendor/github.com/coreos/pkg/progressutil/iocopy.go
generated
vendored
Normal file
189
vendor/github.com/coreos/pkg/progressutil/iocopy.go
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
// Copyright 2016 CoreOS Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package progressutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAlreadyStarted = errors.New("cannot add copies after PrintAndWait has been called")
|
||||
)
|
||||
|
||||
type copyReader struct {
|
||||
reader io.Reader
|
||||
current int64
|
||||
total int64
|
||||
pb *ProgressBar
|
||||
}
|
||||
|
||||
func (cr *copyReader) Read(p []byte) (int, error) {
|
||||
n, err := cr.reader.Read(p)
|
||||
cr.current += int64(n)
|
||||
err1 := cr.updateProgressBar()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (cr *copyReader) updateProgressBar() error {
|
||||
cr.pb.SetPrintAfter(cr.formattedProgress())
|
||||
|
||||
progress := float64(cr.current) / float64(cr.total)
|
||||
if progress > 1 {
|
||||
progress = 1
|
||||
}
|
||||
return cr.pb.SetCurrentProgress(progress)
|
||||
}
|
||||
|
||||
// NewCopyProgressPrinter returns a new CopyProgressPrinter
|
||||
func NewCopyProgressPrinter() *CopyProgressPrinter {
|
||||
return &CopyProgressPrinter{
|
||||
results: make(chan error),
|
||||
cancel: make(chan struct{}),
|
||||
pbp: &ProgressBarPrinter{PadToBeEven: true},
|
||||
}
|
||||
}
|
||||
|
||||
// CopyProgressPrinter will perform an arbitrary number of io.Copy calls, while
|
||||
// continually printing the progress of each copy.
|
||||
type CopyProgressPrinter struct {
|
||||
results chan error
|
||||
cancel chan struct{}
|
||||
|
||||
// `lock` mutex protects all fields below it in CopyProgressPrinter struct
|
||||
lock sync.Mutex
|
||||
readers []*copyReader
|
||||
started bool
|
||||
pbp *ProgressBarPrinter
|
||||
}
|
||||
|
||||
// AddCopy adds a copy for this CopyProgressPrinter to perform. An io.Copy call
|
||||
// will be made to copy bytes from reader to dest, and name and size will be
|
||||
// used to label the progress bar and display how much progress has been made.
|
||||
// If size is 0, the total size of the reader is assumed to be unknown.
|
||||
// AddCopy can only be called before PrintAndWait; otherwise, ErrAlreadyStarted
|
||||
// will be returned.
|
||||
func (cpp *CopyProgressPrinter) AddCopy(reader io.Reader, name string, size int64, dest io.Writer) error {
|
||||
cpp.lock.Lock()
|
||||
defer cpp.lock.Unlock()
|
||||
|
||||
if cpp.started {
|
||||
return ErrAlreadyStarted
|
||||
}
|
||||
|
||||
cr := ©Reader{
|
||||
reader: reader,
|
||||
current: 0,
|
||||
total: size,
|
||||
pb: cpp.pbp.AddProgressBar(),
|
||||
}
|
||||
cr.pb.SetPrintBefore(name)
|
||||
cr.pb.SetPrintAfter(cr.formattedProgress())
|
||||
|
||||
cpp.readers = append(cpp.readers, cr)
|
||||
|
||||
go func() {
|
||||
_, err := io.Copy(dest, cr)
|
||||
select {
|
||||
case <-cpp.cancel:
|
||||
return
|
||||
case cpp.results <- err:
|
||||
return
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintAndWait will print the progress for each copy operation added with
|
||||
// AddCopy to printTo every printInterval. This will continue until every added
|
||||
// copy is finished, or until cancel is written to.
|
||||
// PrintAndWait may only be called once; any subsequent calls will immediately
|
||||
// return ErrAlreadyStarted. After PrintAndWait has been called, no more
|
||||
// copies may be added to the CopyProgressPrinter.
|
||||
func (cpp *CopyProgressPrinter) PrintAndWait(printTo io.Writer, printInterval time.Duration, cancel chan struct{}) error {
|
||||
cpp.lock.Lock()
|
||||
if cpp.started {
|
||||
cpp.lock.Unlock()
|
||||
return ErrAlreadyStarted
|
||||
}
|
||||
cpp.started = true
|
||||
cpp.lock.Unlock()
|
||||
|
||||
n := len(cpp.readers)
|
||||
if n == 0 {
|
||||
// Nothing to do.
|
||||
return nil
|
||||
}
|
||||
|
||||
defer close(cpp.cancel)
|
||||
t := time.NewTicker(printInterval)
|
||||
allDone := false
|
||||
for i := 0; i < n; {
|
||||
select {
|
||||
case <-cancel:
|
||||
return nil
|
||||
case <-t.C:
|
||||
_, err := cpp.pbp.Print(printTo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case err := <-cpp.results:
|
||||
i++
|
||||
// Once completion is signaled, further on this just drains
|
||||
// (unlikely) errors from the channel.
|
||||
if err == nil && !allDone {
|
||||
allDone, err = cpp.pbp.Print(printTo)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *copyReader) formattedProgress() string {
|
||||
var totalStr string
|
||||
if cr.total == 0 {
|
||||
totalStr = "?"
|
||||
} else {
|
||||
totalStr = ByteUnitStr(cr.total)
|
||||
}
|
||||
return fmt.Sprintf("%s / %s", ByteUnitStr(cr.current), totalStr)
|
||||
}
|
||||
|
||||
var byteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
||||
|
||||
// ByteUnitStr pretty prints a number of bytes.
|
||||
func ByteUnitStr(n int64) string {
|
||||
var unit string
|
||||
size := float64(n)
|
||||
for i := 1; i < len(byteUnits); i++ {
|
||||
if size < 1000 {
|
||||
unit = byteUnits[i-1]
|
||||
break
|
||||
}
|
||||
|
||||
size = size / 1000
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%.3g %s", size, unit)
|
||||
}
|
140
vendor/github.com/coreos/pkg/progressutil/iocopy_test.go
generated
vendored
Normal file
140
vendor/github.com/coreos/pkg/progressutil/iocopy_test.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright 2016 CoreOS Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package progressutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type fakeReader struct {
|
||||
input chan []byte
|
||||
done bool
|
||||
}
|
||||
|
||||
func (fr *fakeReader) Read(p []byte) (int, error) {
|
||||
if fr.done {
|
||||
return 0, io.EOF
|
||||
}
|
||||
i := copy(p, <-fr.input)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func TestCopyOne(t *testing.T) {
|
||||
cpp := NewCopyProgressPrinter()
|
||||
cpp.pbp.printToTTYAlways = true
|
||||
|
||||
sampleData := []byte("this is a test!")
|
||||
|
||||
fr := &fakeReader{make(chan []byte, 1), false}
|
||||
fw := &bytes.Buffer{}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
err := cpp.AddCopy(fr, "download", int64(len(sampleData)*10), fw)
|
||||
if err != nil {
|
||||
t.Errorf("%v\n", err)
|
||||
}
|
||||
|
||||
doneChan := make(chan error)
|
||||
go func() {
|
||||
doneChan <- cpp.PrintAndWait(out, time.Millisecond*10, nil)
|
||||
}()
|
||||
|
||||
time.Sleep(time.Millisecond * 15)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
// Empty the buffer
|
||||
printedData := out.Bytes()
|
||||
sizeString := ByteUnitStr(int64(len(sampleData)*i)) + " / " + ByteUnitStr(int64(len(sampleData)*10))
|
||||
bar := renderExpectedBar(80, "download", float64(i)/10, sizeString)
|
||||
var expectedOutput string
|
||||
if i == 0 {
|
||||
expectedOutput = fmt.Sprintf("%s\n", bar)
|
||||
} else {
|
||||
expectedOutput = fmt.Sprintf("\033[1A%s\n", bar)
|
||||
}
|
||||
if string(printedData) != expectedOutput {
|
||||
t.Errorf("unexpected output:\nexpected:\n\n%sactual:\n\n%s", expectedOutput, string(printedData))
|
||||
}
|
||||
if i == 9 {
|
||||
fr.done = true
|
||||
}
|
||||
fr.input <- sampleData
|
||||
|
||||
out.Reset()
|
||||
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
|
||||
err = <-doneChan
|
||||
if err != nil {
|
||||
t.Errorf("error from PrintAndWait: %v", err)
|
||||
}
|
||||
|
||||
if bytes.Compare(fw.Bytes(), bytes.Repeat(sampleData, 10)) != 0 {
|
||||
t.Errorf("copied bytes don't match!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrAlreadyStarted(t *testing.T) {
|
||||
cpp := NewCopyProgressPrinter()
|
||||
fr := &fakeReader{make(chan []byte, 1), false}
|
||||
fw := &bytes.Buffer{}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
err := cpp.AddCopy(fr, "download", 10^10, fw)
|
||||
if err != nil {
|
||||
t.Errorf("%v\n", err)
|
||||
}
|
||||
|
||||
cancel := make(chan struct{})
|
||||
doneChan := make(chan error)
|
||||
go func() {
|
||||
doneChan <- cpp.PrintAndWait(out, time.Second, cancel)
|
||||
}()
|
||||
|
||||
for {
|
||||
cpp.lock.Lock()
|
||||
started := cpp.started
|
||||
cpp.lock.Unlock()
|
||||
if !started {
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err = cpp.AddCopy(fr, "download", 10^10, fw)
|
||||
if err != ErrAlreadyStarted {
|
||||
t.Errorf("Was expecting ErrAlreadyStarted, got something else: %v\n", err)
|
||||
}
|
||||
|
||||
err = cpp.PrintAndWait(out, time.Second, cancel)
|
||||
if err != ErrAlreadyStarted {
|
||||
t.Errorf("Was expecting ErrAlreadyStarted, got something else: %v\n", err)
|
||||
}
|
||||
|
||||
cancel <- struct{}{}
|
||||
|
||||
err = <-doneChan
|
||||
if err != nil {
|
||||
t.Errorf("%v\n", err)
|
||||
}
|
||||
}
|
263
vendor/github.com/coreos/pkg/progressutil/progressbar.go
generated
vendored
Normal file
263
vendor/github.com/coreos/pkg/progressutil/progressbar.go
generated
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
// Copyright 2016 CoreOS Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package progressutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrorProgressOutOfBounds is returned if the progress is set to a value
|
||||
// not between 0 and 1.
|
||||
ErrorProgressOutOfBounds = fmt.Errorf("progress is out of bounds (0 to 1)")
|
||||
|
||||
// ErrorNoBarsAdded is returned when no progress bars have been added to a
|
||||
// ProgressBarPrinter before PrintAndWait is called.
|
||||
ErrorNoBarsAdded = fmt.Errorf("AddProgressBar hasn't been called yet")
|
||||
)
|
||||
|
||||
// ProgressBar represents one progress bar in a ProgressBarPrinter. Should not
|
||||
// be created directly, use the AddProgressBar on a ProgressBarPrinter to
|
||||
// create these.
|
||||
type ProgressBar struct {
|
||||
lock sync.Mutex
|
||||
|
||||
currentProgress float64
|
||||
printBefore string
|
||||
printAfter string
|
||||
done bool
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) clone() *ProgressBar {
|
||||
pb.lock.Lock()
|
||||
pbClone := &ProgressBar{
|
||||
currentProgress: pb.currentProgress,
|
||||
printBefore: pb.printBefore,
|
||||
printAfter: pb.printAfter,
|
||||
done: pb.done,
|
||||
}
|
||||
pb.lock.Unlock()
|
||||
return pbClone
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) GetCurrentProgress() float64 {
|
||||
pb.lock.Lock()
|
||||
val := pb.currentProgress
|
||||
pb.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// SetCurrentProgress sets the progress of this ProgressBar. The progress must
|
||||
// be between 0 and 1 inclusive.
|
||||
func (pb *ProgressBar) SetCurrentProgress(progress float64) error {
|
||||
if progress < 0 || progress > 1 {
|
||||
return ErrorProgressOutOfBounds
|
||||
}
|
||||
pb.lock.Lock()
|
||||
pb.currentProgress = progress
|
||||
pb.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDone returns whether or not this progress bar is done
|
||||
func (pb *ProgressBar) GetDone() bool {
|
||||
pb.lock.Lock()
|
||||
val := pb.done
|
||||
pb.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// SetDone sets whether or not this progress bar is done
|
||||
func (pb *ProgressBar) SetDone(val bool) {
|
||||
pb.lock.Lock()
|
||||
pb.done = val
|
||||
pb.lock.Unlock()
|
||||
}
|
||||
|
||||
// GetPrintBefore gets the text printed on the line before the progress bar.
|
||||
func (pb *ProgressBar) GetPrintBefore() string {
|
||||
pb.lock.Lock()
|
||||
val := pb.printBefore
|
||||
pb.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// SetPrintBefore sets the text printed on the line before the progress bar.
|
||||
func (pb *ProgressBar) SetPrintBefore(before string) {
|
||||
pb.lock.Lock()
|
||||
pb.printBefore = before
|
||||
pb.lock.Unlock()
|
||||
}
|
||||
|
||||
// GetPrintAfter gets the text printed on the line after the progress bar.
|
||||
func (pb *ProgressBar) GetPrintAfter() string {
|
||||
pb.lock.Lock()
|
||||
val := pb.printAfter
|
||||
pb.lock.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// SetPrintAfter sets the text printed on the line after the progress bar.
|
||||
func (pb *ProgressBar) SetPrintAfter(after string) {
|
||||
pb.lock.Lock()
|
||||
pb.printAfter = after
|
||||
pb.lock.Unlock()
|
||||
}
|
||||
|
||||
// ProgressBarPrinter will print out the progress of some number of
|
||||
// ProgressBars.
|
||||
type ProgressBarPrinter struct {
|
||||
lock sync.Mutex
|
||||
|
||||
// DisplayWidth can be set to influence how large the progress bars are.
|
||||
// The bars will be scaled to attempt to produce lines of this number of
|
||||
// characters, but lines of different lengths may still be printed. When
|
||||
// this value is 0 (aka unset), 80 character columns are assumed.
|
||||
DisplayWidth int
|
||||
// PadToBeEven, when set to true, will make Print pad the printBefore text
|
||||
// with trailing spaces and the printAfter text with leading spaces to make
|
||||
// the progress bars the same length.
|
||||
PadToBeEven bool
|
||||
numLinesInLastPrint int
|
||||
progressBars []*ProgressBar
|
||||
maxBefore int
|
||||
maxAfter int
|
||||
|
||||
// printToTTYAlways forces this ProgressBarPrinter to always behave as if
|
||||
// in a tty. Used for tests.
|
||||
printToTTYAlways bool
|
||||
}
|
||||
|
||||
// AddProgressBar will create a new ProgressBar, register it with this
|
||||
// ProgressBarPrinter, and return it. This must be called at least once before
|
||||
// PrintAndWait is called.
|
||||
func (pbp *ProgressBarPrinter) AddProgressBar() *ProgressBar {
|
||||
pb := &ProgressBar{}
|
||||
pbp.lock.Lock()
|
||||
pbp.progressBars = append(pbp.progressBars, pb)
|
||||
pbp.lock.Unlock()
|
||||
return pb
|
||||
}
|
||||
|
||||
// Print will print out progress information for each ProgressBar that has been
|
||||
// added to this ProgressBarPrinter. The progress will be written to printTo,
|
||||
// and if printTo is a terminal it will draw progress bars. AddProgressBar
|
||||
// must be called at least once before Print is called. If printing to a
|
||||
// terminal, all draws after the first one will move the cursor up to draw over
|
||||
// the previously printed bars.
|
||||
func (pbp *ProgressBarPrinter) Print(printTo io.Writer) (bool, error) {
|
||||
pbp.lock.Lock()
|
||||
var bars []*ProgressBar
|
||||
for _, bar := range pbp.progressBars {
|
||||
bars = append(bars, bar.clone())
|
||||
}
|
||||
numColumns := pbp.DisplayWidth
|
||||
pbp.lock.Unlock()
|
||||
|
||||
if len(bars) == 0 {
|
||||
return false, ErrorNoBarsAdded
|
||||
}
|
||||
|
||||
if numColumns == 0 {
|
||||
numColumns = 80
|
||||
}
|
||||
|
||||
if pbp.isTerminal(printTo) {
|
||||
moveCursorUp(printTo, pbp.numLinesInLastPrint)
|
||||
}
|
||||
|
||||
for _, bar := range bars {
|
||||
beforeSize := len(bar.GetPrintBefore())
|
||||
afterSize := len(bar.GetPrintAfter())
|
||||
if beforeSize > pbp.maxBefore {
|
||||
pbp.maxBefore = beforeSize
|
||||
}
|
||||
if afterSize > pbp.maxAfter {
|
||||
pbp.maxAfter = afterSize
|
||||
}
|
||||
}
|
||||
|
||||
allDone := true
|
||||
for _, bar := range bars {
|
||||
if pbp.isTerminal(printTo) {
|
||||
bar.printToTerminal(printTo, numColumns, pbp.PadToBeEven, pbp.maxBefore, pbp.maxAfter)
|
||||
} else {
|
||||
bar.printToNonTerminal(printTo)
|
||||
}
|
||||
allDone = allDone && bar.GetCurrentProgress() == 1
|
||||
}
|
||||
|
||||
pbp.numLinesInLastPrint = len(bars)
|
||||
|
||||
return allDone, nil
|
||||
}
|
||||
|
||||
// moveCursorUp moves the cursor up numLines in the terminal
|
||||
func moveCursorUp(printTo io.Writer, numLines int) {
|
||||
if numLines > 0 {
|
||||
fmt.Fprintf(printTo, "\033[%dA", numLines)
|
||||
}
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) printToTerminal(printTo io.Writer, numColumns int, padding bool, maxBefore, maxAfter int) {
|
||||
before := pb.GetPrintBefore()
|
||||
after := pb.GetPrintAfter()
|
||||
|
||||
if padding {
|
||||
before = before + strings.Repeat(" ", maxBefore-len(before))
|
||||
after = strings.Repeat(" ", maxAfter-len(after)) + after
|
||||
}
|
||||
|
||||
progressBarSize := numColumns - (len(fmt.Sprintf("%s [] %s", before, after)))
|
||||
progressBar := ""
|
||||
if progressBarSize > 0 {
|
||||
currentProgress := int(pb.GetCurrentProgress() * float64(progressBarSize))
|
||||
progressBar = fmt.Sprintf("[%s%s] ",
|
||||
strings.Repeat("=", currentProgress),
|
||||
strings.Repeat(" ", progressBarSize-currentProgress))
|
||||
} else {
|
||||
// If we can't fit the progress bar, better to not pad the before/after.
|
||||
before = pb.GetPrintBefore()
|
||||
after = pb.GetPrintAfter()
|
||||
}
|
||||
|
||||
fmt.Fprintf(printTo, "%s %s%s\n", before, progressBar, after)
|
||||
}
|
||||
|
||||
func (pb *ProgressBar) printToNonTerminal(printTo io.Writer) {
|
||||
if !pb.GetDone() {
|
||||
fmt.Fprintf(printTo, "%s %s\n", pb.printBefore, pb.printAfter)
|
||||
if pb.GetCurrentProgress() == 1 {
|
||||
pb.SetDone(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isTerminal returns True when w is going to a tty, and false otherwise.
|
||||
func (pbp *ProgressBarPrinter) isTerminal(w io.Writer) bool {
|
||||
if pbp.printToTTYAlways {
|
||||
return true
|
||||
}
|
||||
if f, ok := w.(*os.File); ok {
|
||||
return terminal.IsTerminal(int(f.Fd()))
|
||||
}
|
||||
return false
|
||||
}
|
116
vendor/github.com/coreos/pkg/progressutil/progressbar_test.go
generated
vendored
Normal file
116
vendor/github.com/coreos/pkg/progressutil/progressbar_test.go
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2016 CoreOS Inc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package progressutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNoBarsAdded(t *testing.T) {
|
||||
pbp := &ProgressBarPrinter{}
|
||||
allDone, err := pbp.Print(ioutil.Discard)
|
||||
if allDone {
|
||||
t.Errorf("shouldn't have gotten all done when no bars have been added")
|
||||
}
|
||||
if err != ErrorNoBarsAdded {
|
||||
t.Errorf("was expecting ErrorNoBarsAdded, got this instead: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProgressOutOfBounds(t *testing.T) {
|
||||
pbp := &ProgressBarPrinter{}
|
||||
pb := pbp.AddProgressBar()
|
||||
|
||||
for _, testcase := range []struct {
|
||||
progress float64
|
||||
expectedErr error
|
||||
}{
|
||||
{-0.1, ErrorProgressOutOfBounds},
|
||||
{0, nil},
|
||||
{0.5, nil},
|
||||
{1, nil},
|
||||
{1.1, ErrorProgressOutOfBounds},
|
||||
} {
|
||||
err := pb.SetCurrentProgress(testcase.progress)
|
||||
if err != testcase.expectedErr {
|
||||
t.Errorf("got unexpected error. expected=%v actual=%v", testcase.expectedErr, err)
|
||||
}
|
||||
if err == nil {
|
||||
currProgress := pb.GetCurrentProgress()
|
||||
if currProgress != testcase.progress {
|
||||
t.Errorf("no error was returned, but the progress wasn't updated. should be: %f, actual: %f", testcase.progress, currProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDrawOne(t *testing.T) {
|
||||
pbp := ProgressBarPrinter{}
|
||||
pbp.printToTTYAlways = true
|
||||
pb := pbp.AddProgressBar()
|
||||
|
||||
pbp.Print(ioutil.Discard)
|
||||
|
||||
for _, testcase := range []struct {
|
||||
beforeText string
|
||||
progress float64
|
||||
afterText string
|
||||
shouldBeDone bool
|
||||
}{
|
||||
{"before", 0, "after", false},
|
||||
{"before2", 0.1, "after2", false},
|
||||
{"before3", 0.5, "after3", false},
|
||||
{"before4", 1, "after4", true},
|
||||
} {
|
||||
buf := &bytes.Buffer{}
|
||||
pb.SetPrintBefore(testcase.beforeText)
|
||||
pb.SetPrintAfter(testcase.afterText)
|
||||
err := pb.SetCurrentProgress(testcase.progress)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
done, err := pbp.Print(buf)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if done != testcase.shouldBeDone {
|
||||
t.Errorf("unexpected done, expected=%t actual=%t", testcase.shouldBeDone, done)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
|
||||
bar := renderExpectedBar(80, testcase.beforeText, testcase.progress, testcase.afterText)
|
||||
|
||||
expectedOutput := fmt.Sprintf("\033[1A%s\n", bar)
|
||||
|
||||
if output != expectedOutput {
|
||||
t.Errorf("unexpected output:\nexpected:\n\n%sactual:\n\n%s", expectedOutput, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func renderExpectedBar(numColumns int, before string, progress float64, after string) string {
|
||||
progressBarSize := numColumns - len(fmt.Sprintf("%s [] %s", before, after))
|
||||
currentProgress := int(progress * float64(progressBarSize))
|
||||
|
||||
bar := fmt.Sprintf("[%s%s]",
|
||||
strings.Repeat("=", currentProgress),
|
||||
strings.Repeat(" ", progressBarSize-currentProgress))
|
||||
return fmt.Sprintf("%s %s %s", before, bar, after)
|
||||
}
|
2
vendor/github.com/coreos/pkg/test
generated
vendored
2
vendor/github.com/coreos/pkg/test
generated
vendored
@ -14,7 +14,7 @@ COVER=${COVER:-"-cover"}
|
||||
|
||||
source ./build
|
||||
|
||||
TESTABLE="cryptoutil flagutil timeutil netutil yamlutil httputil health multierror"
|
||||
TESTABLE="cryptoutil flagutil timeutil netutil yamlutil httputil health multierror dlopen progressutil"
|
||||
FORMATTABLE="$TESTABLE capnslog"
|
||||
|
||||
# user has not provided PKG override
|
||||
|
9
vendor/github.com/davecgh/go-spew/.travis.yml
generated
vendored
9
vendor/github.com/davecgh/go-spew/.travis.yml
generated
vendored
@ -1,9 +1,12 @@
|
||||
language: go
|
||||
go: 1.2
|
||||
go:
|
||||
- 1.5.4
|
||||
- 1.6.3
|
||||
- 1.7
|
||||
install:
|
||||
- go get -v code.google.com/p/go.tools/cmd/cover
|
||||
- go get -v golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- go test -v -tags=disableunsafe ./spew
|
||||
- go test -v -tags=safe ./spew
|
||||
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
|
||||
after_success:
|
||||
- go get -v github.com/mattn/goveralls
|
||||
|
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
@ -1,3 +1,5 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2012-2013 Dave Collins <dave@davec.name>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
|
10
vendor/github.com/davecgh/go-spew/README.md
generated
vendored
10
vendor/github.com/davecgh/go-spew/README.md
generated
vendored
@ -15,7 +15,7 @@ open source or commercial projects.
|
||||
If you're interested in reading about how this package came to life and some
|
||||
of the challenges involved in providing a deep pretty printer, there is a blog
|
||||
post about it
|
||||
[here](https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
|
||||
[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -157,7 +157,7 @@ options. See the ConfigState documentation for more details.
|
||||
which only accept pointer receivers from non-pointer variables. This option
|
||||
relies on access to the unsafe package, so it will not have any effect when
|
||||
running in environments without access to the unsafe package such as Google
|
||||
App Engine or with the "disableunsafe" build tag specified.
|
||||
App Engine or with the "safe" build tag specified.
|
||||
Pointer method invocation is enabled by default.
|
||||
|
||||
* ContinueOnMethod
|
||||
@ -185,9 +185,9 @@ options. See the ConfigState documentation for more details.
|
||||
This package relies on the unsafe package to perform some of the more advanced
|
||||
features, however it also supports a "limited" mode which allows it to work in
|
||||
environments where the unsafe package is not available. By default, it will
|
||||
operate in this mode on Google App Engine. The "disableunsafe" build tag may
|
||||
also be specified to force the package to build without using the unsafe
|
||||
package.
|
||||
operate in this mode on Google App Engine and when compiled with GopherJS. The
|
||||
"safe" build tag may also be specified to force the package to build without
|
||||
using the unsafe package.
|
||||
|
||||
## License
|
||||
|
||||
|
7
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
7
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
@ -13,9 +13,10 @@
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||
// when the code is not running on Google App Engine and "-tags disableunsafe"
|
||||
// is not added to the go build command line.
|
||||
// +build !appengine,!disableunsafe
|
||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build !js,!appengine,!safe,!disableunsafe
|
||||
|
||||
package spew
|
||||
|
||||
|
7
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
7
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
@ -13,9 +13,10 @@
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||
// when either the code is running on Google App Engine or "-tags disableunsafe"
|
||||
// is added to the go build command line.
|
||||
// +build appengine disableunsafe
|
||||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build js appengine safe disableunsafe
|
||||
|
||||
package spew
|
||||
|
||||
|
2
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
2
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
@ -64,7 +64,7 @@ type ConfigState struct {
|
||||
// inside these interface methods. As a result, this option relies on
|
||||
// access to the unsafe package, so it will not have any effect when
|
||||
// running in environments without access to the unsafe package such as
|
||||
// Google App Engine or with the "disableunsafe" build tag specified.
|
||||
// Google App Engine or with the "safe" build tag specified.
|
||||
DisablePointerMethods bool
|
||||
|
||||
// ContinueOnMethod specifies whether or not recursion should continue once
|
||||
|
3
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
generated
vendored
3
vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
generated
vendored
@ -59,10 +59,11 @@ func addCgoDumpTests() {
|
||||
v3Len := fmt.Sprintf("%d", v3l)
|
||||
v3Cap := fmt.Sprintf("%d", v3c)
|
||||
v3t := "[6]testdata._Ctype_unsignedchar"
|
||||
v3t2 := "[6]testdata._Ctype_uchar"
|
||||
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
|
||||
"{\n 00000000 74 65 73 74 33 00 " +
|
||||
" |test3.|\n}"
|
||||
addDumpTest(v3, "("+v3t+") "+v3s+"\n")
|
||||
addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
|
||||
|
||||
// C signed char array.
|
||||
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
|
||||
|
7
vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go
generated
vendored
7
vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go
generated
vendored
@ -13,9 +13,10 @@
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
||||
// when the code is not running on Google App Engine and "-tags disableunsafe"
|
||||
// is not added to the go build command line.
|
||||
// +build !appengine,!disableunsafe
|
||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build !js,!appengine,!safe,!disableunsafe
|
||||
|
||||
/*
|
||||
This test file is part of the spew package rather than than the spew_test
|
||||
|
5
vendor/github.com/fatih/color/.travis.yml
generated
vendored
5
vendor/github.com/fatih/color/.travis.yml
generated
vendored
@ -1,5 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- tip
|
||||
|
20
vendor/github.com/fatih/color/LICENSE.md
generated
vendored
20
vendor/github.com/fatih/color/LICENSE.md
generated
vendored
@ -1,20 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Fatih Arslan
|
||||
|
||||
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.
|
154
vendor/github.com/fatih/color/README.md
generated
vendored
154
vendor/github.com/fatih/color/README.md
generated
vendored
@ -1,154 +0,0 @@
|
||||
# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
|
||||
|
||||
|
||||
|
||||
Color lets you use colorized outputs in terms of [ANSI Escape
|
||||
Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It
|
||||
has support for Windows too! The API can be used in several ways, pick one that
|
||||
suits you.
|
||||
|
||||
|
||||
|
||||
![Color](http://i.imgur.com/c1JI0lA.png)
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/color
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Standard colors
|
||||
|
||||
```go
|
||||
// Print with default helper functions
|
||||
color.Cyan("Prints text in cyan.")
|
||||
|
||||
// A newline will be appended automatically
|
||||
color.Blue("Prints %s in blue.", "text")
|
||||
|
||||
// These are using the default foreground colors
|
||||
color.Red("We have red")
|
||||
color.Magenta("And many others ..")
|
||||
|
||||
```
|
||||
|
||||
### Mix and reuse colors
|
||||
|
||||
```go
|
||||
// Create a new color object
|
||||
c := color.New(color.FgCyan).Add(color.Underline)
|
||||
c.Println("Prints cyan text with an underline.")
|
||||
|
||||
// Or just add them to New()
|
||||
d := color.New(color.FgCyan, color.Bold)
|
||||
d.Printf("This prints bold cyan %s\n", "too!.")
|
||||
|
||||
// Mix up foreground and background colors, create new mixes!
|
||||
red := color.New(color.FgRed)
|
||||
|
||||
boldRed := red.Add(color.Bold)
|
||||
boldRed.Println("This will print text in bold red.")
|
||||
|
||||
whiteBackground := red.Add(color.BgWhite)
|
||||
whiteBackground.Println("Red text with white background.")
|
||||
```
|
||||
|
||||
### Custom print functions (PrintFunc)
|
||||
|
||||
```go
|
||||
// Create a custom print function for convenience
|
||||
red := color.New(color.FgRed).PrintfFunc()
|
||||
red("Warning")
|
||||
red("Error: %s", err)
|
||||
|
||||
// Mix up multiple attributes
|
||||
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
|
||||
notice("Don't forget this...")
|
||||
```
|
||||
|
||||
### Insert into noncolor strings (SprintFunc)
|
||||
|
||||
```go
|
||||
// Create SprintXxx functions to mix strings with other non-colorized strings:
|
||||
yellow := color.New(color.FgYellow).SprintFunc()
|
||||
red := color.New(color.FgRed).SprintFunc()
|
||||
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
|
||||
|
||||
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
|
||||
fmt.Printf("This %s rocks!\n", info("package"))
|
||||
|
||||
// Use helper functions
|
||||
fmt.Printf("This", color.RedString("warning"), "should be not neglected.")
|
||||
fmt.Printf(color.GreenString("Info:"), "an important message." )
|
||||
|
||||
// Windows supported too! Just don't forget to change the output to color.Output
|
||||
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
|
||||
```
|
||||
|
||||
### Plug into existing code
|
||||
|
||||
```go
|
||||
// Use handy standard colors
|
||||
color.Set(color.FgYellow)
|
||||
|
||||
fmt.Println("Existing text will now be in yellow")
|
||||
fmt.Printf("This one %s\n", "too")
|
||||
|
||||
color.Unset() // Don't forget to unset
|
||||
|
||||
// You can mix up parameters
|
||||
color.Set(color.FgMagenta, color.Bold)
|
||||
defer color.Unset() // Use it in your function
|
||||
|
||||
fmt.Println("All text will now be bold magenta.")
|
||||
```
|
||||
|
||||
### Disable color
|
||||
|
||||
There might be a case where you want to disable color output (for example to
|
||||
pipe the standard output of your app to somewhere else). `Color` has support to
|
||||
disable colors both globally and for single color definition. For example
|
||||
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
|
||||
the color output with:
|
||||
|
||||
```go
|
||||
|
||||
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
|
||||
|
||||
if *flagNoColor {
|
||||
color.NoColor = true // disables colorized output
|
||||
}
|
||||
```
|
||||
|
||||
It also has support for single color definitions (local). You can
|
||||
disable/enable color output on the fly:
|
||||
|
||||
```go
|
||||
c := color.New(color.FgCyan)
|
||||
c.Println("Prints cyan text")
|
||||
|
||||
c.DisableColor()
|
||||
c.Println("This is printed without any color")
|
||||
|
||||
c.EnableColor()
|
||||
c.Println("This prints again cyan...")
|
||||
```
|
||||
|
||||
## Todo
|
||||
|
||||
* Save/Return previous values
|
||||
* Evaluate fmt.Formatter interface
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
* [Fatih Arslan](https://github.com/fatih)
|
||||
* Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details
|
||||
|
402
vendor/github.com/fatih/color/color.go
generated
vendored
402
vendor/github.com/fatih/color/color.go
generated
vendored
@ -1,402 +0,0 @@
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NoColor defines if the output is colorized or not. It's dynamically set to
|
||||
// false or true based on the stdout's file descriptor referring to a terminal
|
||||
// or not. This is a global option and affects all colors. For more control
|
||||
// over each color block use the methods DisableColor() individually.
|
||||
var NoColor = !isatty.IsTerminal(os.Stdout.Fd())
|
||||
|
||||
// Color defines a custom color object which is defined by SGR parameters.
|
||||
type Color struct {
|
||||
params []Attribute
|
||||
noColor *bool
|
||||
}
|
||||
|
||||
// Attribute defines a single SGR Code
|
||||
type Attribute int
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
// Base attributes
|
||||
const (
|
||||
Reset Attribute = iota
|
||||
Bold
|
||||
Faint
|
||||
Italic
|
||||
Underline
|
||||
BlinkSlow
|
||||
BlinkRapid
|
||||
ReverseVideo
|
||||
Concealed
|
||||
CrossedOut
|
||||
)
|
||||
|
||||
// Foreground text colors
|
||||
const (
|
||||
FgBlack Attribute = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta
|
||||
FgCyan
|
||||
FgWhite
|
||||
)
|
||||
|
||||
// Foreground Hi-Intensity text colors
|
||||
const (
|
||||
FgHiBlack Attribute = iota + 90
|
||||
FgHiRed
|
||||
FgHiGreen
|
||||
FgHiYellow
|
||||
FgHiBlue
|
||||
FgHiMagenta
|
||||
FgHiCyan
|
||||
FgHiWhite
|
||||
)
|
||||
|
||||
// Background text colors
|
||||
const (
|
||||
BgBlack Attribute = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
)
|
||||
|
||||
// Background Hi-Intensity text colors
|
||||
const (
|
||||
BgHiBlack Attribute = iota + 100
|
||||
BgHiRed
|
||||
BgHiGreen
|
||||
BgHiYellow
|
||||
BgHiBlue
|
||||
BgHiMagenta
|
||||
BgHiCyan
|
||||
BgHiWhite
|
||||
)
|
||||
|
||||
// New returns a newly created color object.
|
||||
func New(value ...Attribute) *Color {
|
||||
c := &Color{params: make([]Attribute, 0)}
|
||||
c.Add(value...)
|
||||
return c
|
||||
}
|
||||
|
||||
// Set sets the given parameters immediately. It will change the color of
|
||||
// output with the given SGR parameters until color.Unset() is called.
|
||||
func Set(p ...Attribute) *Color {
|
||||
c := New(p...)
|
||||
c.Set()
|
||||
return c
|
||||
}
|
||||
|
||||
// Unset resets all escape attributes and clears the output. Usually should
|
||||
// be called after Set().
|
||||
func Unset() {
|
||||
if NoColor {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// Set sets the SGR sequence.
|
||||
func (c *Color) Set() *Color {
|
||||
if c.isNoColorSet() {
|
||||
return c
|
||||
}
|
||||
|
||||
fmt.Fprintf(Output, c.format())
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Color) unset() {
|
||||
if c.isNoColorSet() {
|
||||
return
|
||||
}
|
||||
|
||||
Unset()
|
||||
}
|
||||
|
||||
// Add is used to chain SGR parameters. Use as many as parameters to combine
|
||||
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
|
||||
func (c *Color) Add(value ...Attribute) *Color {
|
||||
c.params = append(c.params, value...)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Color) prepend(value Attribute) {
|
||||
c.params = append(c.params, 0)
|
||||
copy(c.params[1:], c.params[0:])
|
||||
c.params[0] = value
|
||||
}
|
||||
|
||||
// Output defines the standard output of the print functions. By default
|
||||
// os.Stdout is used.
|
||||
var Output = colorable.NewColorableStdout()
|
||||
|
||||
// Print formats using the default formats for its operands and writes to
|
||||
// standard output. Spaces are added between operands when neither is a
|
||||
// string. It returns the number of bytes written and any write error
|
||||
// encountered. This is the standard fmt.Print() method wrapped with the given
|
||||
// color.
|
||||
func (c *Color) Print(a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprint(Output, a...)
|
||||
}
|
||||
|
||||
// Printf formats according to a format specifier and writes to standard output.
|
||||
// It returns the number of bytes written and any write error encountered.
|
||||
// This is the standard fmt.Printf() method wrapped with the given color.
|
||||
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprintf(Output, format, a...)
|
||||
}
|
||||
|
||||
// Println formats using the default formats for its operands and writes to
|
||||
// standard output. Spaces are always added between operands and a newline is
|
||||
// appended. It returns the number of bytes written and any write error
|
||||
// encountered. This is the standard fmt.Print() method wrapped with the given
|
||||
// color.
|
||||
func (c *Color) Println(a ...interface{}) (n int, err error) {
|
||||
c.Set()
|
||||
defer c.unset()
|
||||
|
||||
return fmt.Fprintln(Output, a...)
|
||||
}
|
||||
|
||||
// PrintFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Print().
|
||||
func (c *Color) PrintFunc() func(a ...interface{}) {
|
||||
return func(a ...interface{}) { c.Print(a...) }
|
||||
}
|
||||
|
||||
// PrintfFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Printf().
|
||||
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
|
||||
return func(format string, a ...interface{}) { c.Printf(format, a...) }
|
||||
}
|
||||
|
||||
// PrintlnFunc returns a new function that prints the passed arguments as
|
||||
// colorized with color.Println().
|
||||
func (c *Color) PrintlnFunc() func(a ...interface{}) {
|
||||
return func(a ...interface{}) { c.Println(a...) }
|
||||
}
|
||||
|
||||
// SprintFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprint(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjuction with color.Output, example:
|
||||
//
|
||||
// put := New(FgYellow).SprintFunc()
|
||||
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
|
||||
func (c *Color) SprintFunc() func(a ...interface{}) string {
|
||||
return func(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprint(a...))
|
||||
}
|
||||
}
|
||||
|
||||
// SprintfFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjuction with color.Output.
|
||||
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
|
||||
return func(format string, a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintf(format, a...))
|
||||
}
|
||||
}
|
||||
|
||||
// SprintlnFunc returns a new function that returns colorized strings for the
|
||||
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
|
||||
// string. Windows users should use this in conjuction with color.Output.
|
||||
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
|
||||
return func(a ...interface{}) string {
|
||||
return c.wrap(fmt.Sprintln(a...))
|
||||
}
|
||||
}
|
||||
|
||||
// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m"
|
||||
// an example output might be: "1;36" -> bold cyan
|
||||
func (c *Color) sequence() string {
|
||||
format := make([]string, len(c.params))
|
||||
for i, v := range c.params {
|
||||
format[i] = strconv.Itoa(int(v))
|
||||
}
|
||||
|
||||
return strings.Join(format, ";")
|
||||
}
|
||||
|
||||
// wrap wraps the s string with the colors attributes. The string is ready to
|
||||
// be printed.
|
||||
func (c *Color) wrap(s string) string {
|
||||
if c.isNoColorSet() {
|
||||
return s
|
||||
}
|
||||
|
||||
return c.format() + s + c.unformat()
|
||||
}
|
||||
|
||||
func (c *Color) format() string {
|
||||
return fmt.Sprintf("%s[%sm", escape, c.sequence())
|
||||
}
|
||||
|
||||
func (c *Color) unformat() string {
|
||||
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// DisableColor disables the color output. Useful to not change any existing
|
||||
// code and still being able to output. Can be used for flags like
|
||||
// "--no-color". To enable back use EnableColor() method.
|
||||
func (c *Color) DisableColor() {
|
||||
c.noColor = boolPtr(true)
|
||||
}
|
||||
|
||||
// EnableColor enables the color output. Use it in conjuction with
|
||||
// DisableColor(). Otherwise this method has no side effects.
|
||||
func (c *Color) EnableColor() {
|
||||
c.noColor = boolPtr(false)
|
||||
}
|
||||
|
||||
func (c *Color) isNoColorSet() bool {
|
||||
// check first if we have user setted action
|
||||
if c.noColor != nil {
|
||||
return *c.noColor
|
||||
}
|
||||
|
||||
// if not return the global option, which is disabled by default
|
||||
return NoColor
|
||||
}
|
||||
|
||||
// Equals returns a boolean value indicating whether two colors are equal.
|
||||
func (c *Color) Equals(c2 *Color) bool {
|
||||
if len(c.params) != len(c2.params) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, attr := range c.params {
|
||||
if !c2.attrExists(attr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Color) attrExists(a Attribute) bool {
|
||||
for _, attr := range c.params {
|
||||
if attr == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func boolPtr(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Black is an convenient helper function to print with black foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) }
|
||||
|
||||
// Red is an convenient helper function to print with red foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) }
|
||||
|
||||
// Green is an convenient helper function to print with green foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) }
|
||||
|
||||
// Yellow is an convenient helper function to print with yellow foreground.
|
||||
// A newline is appended to format by default.
|
||||
func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) }
|
||||
|
||||
// Blue is an convenient helper function to print with blue foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) }
|
||||
|
||||
// Magenta is an convenient helper function to print with magenta foreground.
|
||||
// A newline is appended to format by default.
|
||||
func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) }
|
||||
|
||||
// Cyan is an convenient helper function to print with cyan foreground. A
|
||||
// newline is appended to format by default.
|
||||
func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) }
|
||||
|
||||
// White is an convenient helper function to print with white foreground. A
|
||||
// newline is appended to format by default.
|
||||
func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) }
|
||||
|
||||
func printColor(format string, p Attribute, a ...interface{}) {
|
||||
if !strings.HasSuffix(format, "\n") {
|
||||
format += "\n"
|
||||
}
|
||||
|
||||
c := &Color{params: []Attribute{p}}
|
||||
c.Printf(format, a...)
|
||||
}
|
||||
|
||||
// BlackString is an convenient helper function to return a string with black
|
||||
// foreground.
|
||||
func BlackString(format string, a ...interface{}) string {
|
||||
return New(FgBlack).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// RedString is an convenient helper function to return a string with red
|
||||
// foreground.
|
||||
func RedString(format string, a ...interface{}) string {
|
||||
return New(FgRed).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// GreenString is an convenient helper function to return a string with green
|
||||
// foreground.
|
||||
func GreenString(format string, a ...interface{}) string {
|
||||
return New(FgGreen).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// YellowString is an convenient helper function to return a string with yellow
|
||||
// foreground.
|
||||
func YellowString(format string, a ...interface{}) string {
|
||||
return New(FgYellow).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// BlueString is an convenient helper function to return a string with blue
|
||||
// foreground.
|
||||
func BlueString(format string, a ...interface{}) string {
|
||||
return New(FgBlue).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// MagentaString is an convenient helper function to return a string with magenta
|
||||
// foreground.
|
||||
func MagentaString(format string, a ...interface{}) string {
|
||||
return New(FgMagenta).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// CyanString is an convenient helper function to return a string with cyan
|
||||
// foreground.
|
||||
func CyanString(format string, a ...interface{}) string {
|
||||
return New(FgCyan).SprintfFunc()(format, a...)
|
||||
}
|
||||
|
||||
// WhiteString is an convenient helper function to return a string with white
|
||||
// foreground.
|
||||
func WhiteString(format string, a ...interface{}) string {
|
||||
return New(FgWhite).SprintfFunc()(format, a...)
|
||||
}
|
226
vendor/github.com/fatih/color/color_test.go
generated
vendored
226
vendor/github.com/fatih/color/color_test.go
generated
vendored
@ -1,226 +0,0 @@
|
||||
package color
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
// Testing colors is kinda different. First we test for given colors and their
|
||||
// escaped formatted results. Next we create some visual tests to be tested.
|
||||
// Each visual test includes the color name to be compared.
|
||||
func TestColor(t *testing.T) {
|
||||
rb := new(bytes.Buffer)
|
||||
Output = rb
|
||||
|
||||
NoColor = false
|
||||
|
||||
testColors := []struct {
|
||||
text string
|
||||
code Attribute
|
||||
}{
|
||||
{text: "black", code: FgBlack},
|
||||
{text: "red", code: FgRed},
|
||||
{text: "green", code: FgGreen},
|
||||
{text: "yellow", code: FgYellow},
|
||||
{text: "blue", code: FgBlue},
|
||||
{text: "magent", code: FgMagenta},
|
||||
{text: "cyan", code: FgCyan},
|
||||
{text: "white", code: FgWhite},
|
||||
{text: "hblack", code: FgHiBlack},
|
||||
{text: "hred", code: FgHiRed},
|
||||
{text: "hgreen", code: FgHiGreen},
|
||||
{text: "hyellow", code: FgHiYellow},
|
||||
{text: "hblue", code: FgHiBlue},
|
||||
{text: "hmagent", code: FgHiMagenta},
|
||||
{text: "hcyan", code: FgHiCyan},
|
||||
{text: "hwhite", code: FgHiWhite},
|
||||
}
|
||||
|
||||
for _, c := range testColors {
|
||||
New(c.code).Print(c.text)
|
||||
|
||||
line, _ := rb.ReadString('\n')
|
||||
scannedLine := fmt.Sprintf("%q", line)
|
||||
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
|
||||
escapedForm := fmt.Sprintf("%q", colored)
|
||||
|
||||
fmt.Printf("%s\t: %s\n", c.text, line)
|
||||
|
||||
if scannedLine != escapedForm {
|
||||
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestColorEquals(t *testing.T) {
|
||||
fgblack1 := New(FgBlack)
|
||||
fgblack2 := New(FgBlack)
|
||||
bgblack := New(BgBlack)
|
||||
fgbgblack := New(FgBlack, BgBlack)
|
||||
fgblackbgred := New(FgBlack, BgRed)
|
||||
fgred := New(FgRed)
|
||||
bgred := New(BgRed)
|
||||
|
||||
if !fgblack1.Equals(fgblack2) {
|
||||
t.Error("Two black colors are not equal")
|
||||
}
|
||||
|
||||
if fgblack1.Equals(bgblack) {
|
||||
t.Error("Fg and bg black colors are equal")
|
||||
}
|
||||
|
||||
if fgblack1.Equals(fgbgblack) {
|
||||
t.Error("Fg black equals fg/bg black color")
|
||||
}
|
||||
|
||||
if fgblack1.Equals(fgred) {
|
||||
t.Error("Fg black equals Fg red")
|
||||
}
|
||||
|
||||
if fgblack1.Equals(bgred) {
|
||||
t.Error("Fg black equals Bg red")
|
||||
}
|
||||
|
||||
if fgblack1.Equals(fgblackbgred) {
|
||||
t.Error("Fg black equals fg black bg red")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoColor(t *testing.T) {
|
||||
rb := new(bytes.Buffer)
|
||||
Output = rb
|
||||
|
||||
testColors := []struct {
|
||||
text string
|
||||
code Attribute
|
||||
}{
|
||||
{text: "black", code: FgBlack},
|
||||
{text: "red", code: FgRed},
|
||||
{text: "green", code: FgGreen},
|
||||
{text: "yellow", code: FgYellow},
|
||||
{text: "blue", code: FgBlue},
|
||||
{text: "magent", code: FgMagenta},
|
||||
{text: "cyan", code: FgCyan},
|
||||
{text: "white", code: FgWhite},
|
||||
{text: "hblack", code: FgHiBlack},
|
||||
{text: "hred", code: FgHiRed},
|
||||
{text: "hgreen", code: FgHiGreen},
|
||||
{text: "hyellow", code: FgHiYellow},
|
||||
{text: "hblue", code: FgHiBlue},
|
||||
{text: "hmagent", code: FgHiMagenta},
|
||||
{text: "hcyan", code: FgHiCyan},
|
||||
{text: "hwhite", code: FgHiWhite},
|
||||
}
|
||||
|
||||
for _, c := range testColors {
|
||||
p := New(c.code)
|
||||
p.DisableColor()
|
||||
p.Print(c.text)
|
||||
|
||||
line, _ := rb.ReadString('\n')
|
||||
if line != c.text {
|
||||
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
|
||||
}
|
||||
}
|
||||
|
||||
// global check
|
||||
NoColor = true
|
||||
defer func() {
|
||||
NoColor = false
|
||||
}()
|
||||
for _, c := range testColors {
|
||||
p := New(c.code)
|
||||
p.Print(c.text)
|
||||
|
||||
line, _ := rb.ReadString('\n')
|
||||
if line != c.text {
|
||||
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestColorVisual(t *testing.T) {
|
||||
// First Visual Test
|
||||
Output = colorable.NewColorableStdout()
|
||||
|
||||
New(FgRed).Printf("red\t")
|
||||
New(BgRed).Print(" ")
|
||||
New(FgRed, Bold).Println(" red")
|
||||
|
||||
New(FgGreen).Printf("green\t")
|
||||
New(BgGreen).Print(" ")
|
||||
New(FgGreen, Bold).Println(" green")
|
||||
|
||||
New(FgYellow).Printf("yellow\t")
|
||||
New(BgYellow).Print(" ")
|
||||
New(FgYellow, Bold).Println(" yellow")
|
||||
|
||||
New(FgBlue).Printf("blue\t")
|
||||
New(BgBlue).Print(" ")
|
||||
New(FgBlue, Bold).Println(" blue")
|
||||
|
||||
New(FgMagenta).Printf("magenta\t")
|
||||
New(BgMagenta).Print(" ")
|
||||
New(FgMagenta, Bold).Println(" magenta")
|
||||
|
||||
New(FgCyan).Printf("cyan\t")
|
||||
New(BgCyan).Print(" ")
|
||||
New(FgCyan, Bold).Println(" cyan")
|
||||
|
||||
New(FgWhite).Printf("white\t")
|
||||
New(BgWhite).Print(" ")
|
||||
New(FgWhite, Bold).Println(" white")
|
||||
fmt.Println("")
|
||||
|
||||
// Second Visual test
|
||||
Black("black")
|
||||
Red("red")
|
||||
Green("green")
|
||||
Yellow("yellow")
|
||||
Blue("blue")
|
||||
Magenta("magenta")
|
||||
Cyan("cyan")
|
||||
White("white")
|
||||
|
||||
// Third visual test
|
||||
fmt.Println()
|
||||
Set(FgBlue)
|
||||
fmt.Println("is this blue?")
|
||||
Unset()
|
||||
|
||||
Set(FgMagenta)
|
||||
fmt.Println("and this magenta?")
|
||||
Unset()
|
||||
|
||||
// Fourth Visual test
|
||||
fmt.Println()
|
||||
blue := New(FgBlue).PrintlnFunc()
|
||||
blue("blue text with custom print func")
|
||||
|
||||
red := New(FgRed).PrintfFunc()
|
||||
red("red text with a printf func: %d\n", 123)
|
||||
|
||||
put := New(FgYellow).SprintFunc()
|
||||
warn := New(FgRed).SprintFunc()
|
||||
|
||||
fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
|
||||
|
||||
info := New(FgWhite, BgGreen).SprintFunc()
|
||||
fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
|
||||
|
||||
// Fifth Visual Test
|
||||
fmt.Println()
|
||||
|
||||
fmt.Fprintln(Output, BlackString("black"))
|
||||
fmt.Fprintln(Output, RedString("red"))
|
||||
fmt.Fprintln(Output, GreenString("green"))
|
||||
fmt.Fprintln(Output, YellowString("yellow"))
|
||||
fmt.Fprintln(Output, BlueString("blue"))
|
||||
fmt.Fprintln(Output, MagentaString("magenta"))
|
||||
fmt.Fprintln(Output, CyanString("cyan"))
|
||||
fmt.Fprintln(Output, WhiteString("white"))
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user