Codebase list golang-github-coreos-pkg / 3316eb5
"gbp import-orig" merge failed; update gbp.conf & drop upstream files from "master" Dmitry Smirnov 7 years ago
44 changed file(s) with 10 addition(s) and 2661 deletion(s). Raw diff Collapse all Expand all
+0
-1
.gitignore less more
0 .pc
+0
-71
CONTRIBUTING.md less more
0 # How to Contribute
1
2 CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via
3 GitHub pull requests. This document outlines some of the conventions on
4 development workflow, commit message formatting, contact points and other
5 resources to make it easier to get your contribution accepted.
6
7 # Certificate of Origin
8
9 By contributing to this project you agree to the Developer Certificate of
10 Origin (DCO). This document was created by the Linux Kernel community and is a
11 simple statement that you, as a contributor, have the legal right to make the
12 contribution. See the [DCO](DCO) file for details.
13
14 # Email and Chat
15
16 The project currently uses the general CoreOS email list and IRC channel:
17 - Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev)
18 - IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
19
20 Please avoid emailing maintainers found in the MAINTAINERS file directly. They
21 are very busy and read the mailing lists.
22
23 ## Getting Started
24
25 - Fork the repository on GitHub
26 - Read the [README](README.md) for build and test instructions
27 - Play with the project, submit bugs, submit patches!
28
29 ## Contribution Flow
30
31 This is a rough outline of what a contributor's workflow looks like:
32
33 - Create a topic branch from where you want to base your work (usually master).
34 - Make commits of logical units.
35 - Make sure your commit messages are in the proper format (see below).
36 - Push your changes to a topic branch in your fork of the repository.
37 - Make sure the tests pass, and add any new tests as appropriate.
38 - Submit a pull request to the original repository.
39
40 Thanks for your contributions!
41
42 ### Format of the Commit Message
43
44 We follow a rough convention for commit messages that is designed to answer two
45 questions: what changed and why. The subject line should feature the what and
46 the body of the commit should describe the why.
47
48 ```
49 scripts: add the test-cluster command
50
51 this uses tmux to setup a test cluster that you can easily kill and
52 start for debugging.
53
54 Fixes #38
55 ```
56
57 The format can be described more formally as follows:
58
59 ```
60 <subsystem>: <what changed>
61 <BLANK LINE>
62 <why this change was made>
63 <BLANK LINE>
64 <footer>
65 ```
66
67 The first line is the subject and should be no longer than 70 characters, the
68 second line is always blank, and other lines should be wrapped at 80 characters.
69 This allows the message to be easier to read on GitHub as well as in various
70 git tools.
+0
-36
DCO less more
0 Developer Certificate of Origin
1 Version 1.1
2
3 Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
4 660 York Street, Suite 102,
5 San Francisco, CA 94110 USA
6
7 Everyone is permitted to copy and distribute verbatim copies of this
8 license document, but changing it is not allowed.
9
10
11 Developer's Certificate of Origin 1.1
12
13 By making a contribution to this project, I certify that:
14
15 (a) The contribution was created in whole or in part by me and I
16 have the right to submit it under the open source license
17 indicated in the file; or
18
19 (b) The contribution is based upon previous work that, to the best
20 of my knowledge, is covered under an appropriate open source
21 license and I have the right under that license to submit that
22 work with modifications, whether created in whole or in part
23 by me, under the same open source license (unless I am
24 permitted to submit under a different license), as indicated
25 in the file; or
26
27 (c) The contribution was provided directly to me by some other
28 person who certified (a), (b) or (c) and I have not modified
29 it.
30
31 (d) I understand and agree that this project and the contribution
32 are public and that a record of the contribution (including all
33 personal information I submit with it, including my sign-off) is
34 maintained indefinitely and may be redistributed consistent with
35 this project or the open source license(s) involved.
+0
-202
LICENSE less more
0 Apache License
1 Version 2.0, January 2004
2 http://www.apache.org/licenses/
3
4 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
6 1. Definitions.
7
8 "License" shall mean the terms and conditions for use, reproduction,
9 and distribution as defined by Sections 1 through 9 of this document.
10
11 "Licensor" shall mean the copyright owner or entity authorized by
12 the copyright owner that is granting the License.
13
14 "Legal Entity" shall mean the union of the acting entity and all
15 other entities that control, are controlled by, or are under common
16 control with that entity. For the purposes of this definition,
17 "control" means (i) the power, direct or indirect, to cause the
18 direction or management of such entity, whether by contract or
19 otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 outstanding shares, or (iii) beneficial ownership of such entity.
21
22 "You" (or "Your") shall mean an individual or Legal Entity
23 exercising permissions granted by this License.
24
25 "Source" form shall mean the preferred form for making modifications,
26 including but not limited to software source code, documentation
27 source, and configuration files.
28
29 "Object" form shall mean any form resulting from mechanical
30 transformation or translation of a Source form, including but
31 not limited to compiled object code, generated documentation,
32 and conversions to other media types.
33
34 "Work" shall mean the work of authorship, whether in Source or
35 Object form, made available under the License, as indicated by a
36 copyright notice that is included in or attached to the work
37 (an example is provided in the Appendix below).
38
39 "Derivative Works" shall mean any work, whether in Source or Object
40 form, that is based on (or derived from) the Work and for which the
41 editorial revisions, annotations, elaborations, or other modifications
42 represent, as a whole, an original work of authorship. For the purposes
43 of this License, Derivative Works shall not include works that remain
44 separable from, or merely link (or bind by name) to the interfaces of,
45 the Work and Derivative Works thereof.
46
47 "Contribution" shall mean any work of authorship, including
48 the original version of the Work and any modifications or additions
49 to that Work or Derivative Works thereof, that is intentionally
50 submitted to Licensor for inclusion in the Work by the copyright owner
51 or by an individual or Legal Entity authorized to submit on behalf of
52 the copyright owner. For the purposes of this definition, "submitted"
53 means any form of electronic, verbal, or written communication sent
54 to the Licensor or its representatives, including but not limited to
55 communication on electronic mailing lists, source code control systems,
56 and issue tracking systems that are managed by, or on behalf of, the
57 Licensor for the purpose of discussing and improving the Work, but
58 excluding communication that is conspicuously marked or otherwise
59 designated in writing by the copyright owner as "Not a Contribution."
60
61 "Contributor" shall mean Licensor and any individual or Legal Entity
62 on behalf of whom a Contribution has been received by Licensor and
63 subsequently incorporated within the Work.
64
65 2. Grant of Copyright License. Subject to the terms and conditions of
66 this License, each Contributor hereby grants to You a perpetual,
67 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68 copyright license to reproduce, prepare Derivative Works of,
69 publicly display, publicly perform, sublicense, and distribute the
70 Work and such Derivative Works in Source or Object form.
71
72 3. Grant of Patent License. Subject to the terms and conditions of
73 this License, each Contributor hereby grants to You a perpetual,
74 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75 (except as stated in this section) patent license to make, have made,
76 use, offer to sell, sell, import, and otherwise transfer the Work,
77 where such license applies only to those patent claims licensable
78 by such Contributor that are necessarily infringed by their
79 Contribution(s) alone or by combination of their Contribution(s)
80 with the Work to which such Contribution(s) was submitted. If You
81 institute patent litigation against any entity (including a
82 cross-claim or counterclaim in a lawsuit) alleging that the Work
83 or a Contribution incorporated within the Work constitutes direct
84 or contributory patent infringement, then any patent licenses
85 granted to You under this License for that Work shall terminate
86 as of the date such litigation is filed.
87
88 4. Redistribution. You may reproduce and distribute copies of the
89 Work or Derivative Works thereof in any medium, with or without
90 modifications, and in Source or Object form, provided that You
91 meet the following conditions:
92
93 (a) You must give any other recipients of the Work or
94 Derivative Works a copy of this License; and
95
96 (b) You must cause any modified files to carry prominent notices
97 stating that You changed the files; and
98
99 (c) You must retain, in the Source form of any Derivative Works
100 that You distribute, all copyright, patent, trademark, and
101 attribution notices from the Source form of the Work,
102 excluding those notices that do not pertain to any part of
103 the Derivative Works; and
104
105 (d) If the Work includes a "NOTICE" text file as part of its
106 distribution, then any Derivative Works that You distribute must
107 include a readable copy of the attribution notices contained
108 within such NOTICE file, excluding those notices that do not
109 pertain to any part of the Derivative Works, in at least one
110 of the following places: within a NOTICE text file distributed
111 as part of the Derivative Works; within the Source form or
112 documentation, if provided along with the Derivative Works; or,
113 within a display generated by the Derivative Works, if and
114 wherever such third-party notices normally appear. The contents
115 of the NOTICE file are for informational purposes only and
116 do not modify the License. You may add Your own attribution
117 notices within Derivative Works that You distribute, alongside
118 or as an addendum to the NOTICE text from the Work, provided
119 that such additional attribution notices cannot be construed
120 as modifying the License.
121
122 You may add Your own copyright statement to Your modifications and
123 may provide additional or different license terms and conditions
124 for use, reproduction, or distribution of Your modifications, or
125 for any such Derivative Works as a whole, provided Your use,
126 reproduction, and distribution of the Work otherwise complies with
127 the conditions stated in this License.
128
129 5. Submission of Contributions. Unless You explicitly state otherwise,
130 any Contribution intentionally submitted for inclusion in the Work
131 by You to the Licensor shall be under the terms and conditions of
132 this License, without any additional terms or conditions.
133 Notwithstanding the above, nothing herein shall supersede or modify
134 the terms of any separate license agreement you may have executed
135 with Licensor regarding such Contributions.
136
137 6. Trademarks. This License does not grant permission to use the trade
138 names, trademarks, service marks, or product names of the Licensor,
139 except as required for reasonable and customary use in describing the
140 origin of the Work and reproducing the content of the NOTICE file.
141
142 7. Disclaimer of Warranty. Unless required by applicable law or
143 agreed to in writing, Licensor provides the Work (and each
144 Contributor provides its Contributions) on an "AS IS" BASIS,
145 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146 implied, including, without limitation, any warranties or conditions
147 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148 PARTICULAR PURPOSE. You are solely responsible for determining the
149 appropriateness of using or redistributing the Work and assume any
150 risks associated with Your exercise of permissions under this License.
151
152 8. Limitation of Liability. In no event and under no legal theory,
153 whether in tort (including negligence), contract, or otherwise,
154 unless required by applicable law (such as deliberate and grossly
155 negligent acts) or agreed to in writing, shall any Contributor be
156 liable to You for damages, including any direct, indirect, special,
157 incidental, or consequential damages of any character arising as a
158 result of this License or out of the use or inability to use the
159 Work (including but not limited to damages for loss of goodwill,
160 work stoppage, computer failure or malfunction, or any and all
161 other commercial damages or losses), even if such Contributor
162 has been advised of the possibility of such damages.
163
164 9. Accepting Warranty or Additional Liability. While redistributing
165 the Work or Derivative Works thereof, You may choose to offer,
166 and charge a fee for, acceptance of support, warranty, indemnity,
167 or other liability obligations and/or rights consistent with this
168 License. However, in accepting such obligations, You may act only
169 on Your own behalf and on Your sole responsibility, not on behalf
170 of any other Contributor, and only if You agree to indemnify,
171 defend, and hold each Contributor harmless for any liability
172 incurred by, or claims asserted against, such Contributor by reason
173 of your accepting any such warranty or additional liability.
174
175 END OF TERMS AND CONDITIONS
176
177 APPENDIX: How to apply the Apache License to your work.
178
179 To apply the Apache License to your work, attach the following
180 boilerplate notice, with the fields enclosed by brackets "{}"
181 replaced with your own identifying information. (Don't include
182 the brackets!) The text should be enclosed in the appropriate
183 comment syntax for the file format. We also recommend that a
184 file or class name and description of purpose be included on the
185 same "printed page" as the copyright notice for easier
186 identification within third-party archives.
187
188 Copyright {yyyy} {name of copyright owner}
189
190 Licensed under the Apache License, Version 2.0 (the "License");
191 you may not use this file except in compliance with the License.
192 You may obtain a copy of the License at
193
194 http://www.apache.org/licenses/LICENSE-2.0
195
196 Unless required by applicable law or agreed to in writing, software
197 distributed under the License is distributed on an "AS IS" BASIS,
198 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199 See the License for the specific language governing permissions and
200 limitations under the License.
201
+0
-1
MAINTAINERS less more
0 Ed Rooth <ed.rooth@coreos.com> (@sym3tri)
+0
-5
NOTICE less more
0 CoreOS Project
1 Copyright 2014 CoreOS, Inc
2
3 This product includes software developed at CoreOS, Inc.
4 (http://www.coreos.com/).
+0
-3
README.md less more
0 a collection of go utility packages
1
2 [![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)
+0
-3
build less more
0 #!/bin/bash -e
1
2 go build ./...
+0
-39
capnslog/README.md less more
0 # capnslog, the CoreOS logging package
1
2 There are far too many logging packages out there, with varying degrees of licenses, far too many features (colorization, all sorts of log frameworks) or are just a pain to use (lack of `Fatalln()`?).
3 capnslog provides a simple but consistent logging interface suitable for all kinds of projects.
4
5 ### Design Principles
6
7 ##### `package main` is the place where logging gets turned on and routed
8
9 A library should not touch log options, only generate log entries. Libraries are silent until main lets them speak.
10
11 ##### All log options are runtime-configurable.
12
13 Still the job of `main` to expose these configurations. `main` may delegate this to, say, a configuration webhook, but does so explicitly.
14
15 ##### There is one log object per package. It is registered under its repository and package name.
16
17 `main` activates logging for its repository and any dependency repositories it would also like to have output in its logstream. `main` also dictates at which level each subpackage logs.
18
19 ##### There is *one* output stream, and it is an `io.Writer` composed with a formatter.
20
21 Splitting streams is probably not the job of your program, but rather, your log aggregation framework. If you must split output streams, again, `main` configures this and you can write a very simple two-output struct that satisfies io.Writer.
22
23 Fancy colorful formatting and JSON output are beyond the scope of a basic logging framework -- they're application/log-collector dependant. These are, at best, provided as options, but more likely, provided by your application.
24
25 ##### Log objects are an interface
26
27 An object knows best how to print itself. Log objects can collect more interesting metadata if they wish, however, because text isn't going away anytime soon, they must all be marshalable to text. The simplest log object is a string, which returns itself. If you wish to do more fancy tricks for printing your log objects, see also JSON output -- introspect and write a formatter which can handle your advanced log interface. Making strings is the only thing guaranteed.
28
29 ##### Log levels have specific meanings:
30
31 * Critical: Unrecoverable. Must fail.
32 * Error: Data has been lost, a request has failed for a bad reason, or a required resource has been lost
33 * Warning: (Hopefully) Temporary conditions that may cause errors, but may work fine. A replica disappearing (that may reconnect) is a warning.
34 * Notice: Normal, but important (uncommon) log information.
35 * Info: Normal, working log information, everything is fine, but helpful notices for auditing or common operations.
36 * Debug: Everything is still fine, but even common operations may be logged, and less helpful but more quantity of notices.
37 * Trace: Anything goes, from logging every function call as part of a common operation, to tracing execution of a query.
38
+0
-57
capnslog/example/hello_dolly.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package main
15
16 import (
17 "flag"
18 oldlog "log"
19
20 "github.com/coreos/pkg/capnslog"
21 )
22
23 var logLevel = capnslog.INFO
24 var log = capnslog.NewPackageLogger("github.com/coreos/pkg/capnslog/cmd", "main")
25 var dlog = capnslog.NewPackageLogger("github.com/coreos/pkg/capnslog/cmd", "dolly")
26
27 func init() {
28 flag.Var(&logLevel, "log-level", "Global log level.")
29 }
30
31 func main() {
32 rl := capnslog.MustRepoLogger("github.com/coreos/pkg/capnslog/cmd")
33
34 // We can parse the log level configs from the command line
35 flag.Parse()
36 if flag.NArg() > 1 {
37 cfg, err := rl.ParseLogLevelConfig(flag.Arg(1))
38 if err != nil {
39 log.Fatal(err)
40 }
41 rl.SetLogLevel(cfg)
42 log.Infof("Setting output to %s", flag.Arg(1))
43 }
44
45 // Send some messages at different levels to the different packages
46 dlog.Infof("Hello Dolly")
47 dlog.Warningf("Well hello, Dolly")
48 log.Errorf("It's so nice to have you back where you belong")
49 dlog.Debugf("You're looking swell, Dolly")
50 dlog.Tracef("I can tell, Dolly")
51
52 // We also have control over the built-in "log" package.
53 capnslog.SetGlobalLogLevel(logLevel)
54 oldlog.Println("You're still glowin', you're still crowin', you're still lookin' strong")
55 log.Fatalf("Dolly'll never go away again")
56 }
+0
-106
capnslog/formatters.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import (
17 "bufio"
18 "fmt"
19 "io"
20 "runtime"
21 "strings"
22 "time"
23 )
24
25 type Formatter interface {
26 Format(pkg string, level LogLevel, depth int, entries ...interface{})
27 Flush()
28 }
29
30 func NewStringFormatter(w io.Writer) *StringFormatter {
31 return &StringFormatter{
32 w: bufio.NewWriter(w),
33 }
34 }
35
36 type StringFormatter struct {
37 w *bufio.Writer
38 }
39
40 func (s *StringFormatter) Format(pkg string, l LogLevel, i int, entries ...interface{}) {
41 now := time.Now().UTC()
42 s.w.WriteString(now.Format(time.RFC3339))
43 s.w.WriteByte(' ')
44 writeEntries(s.w, pkg, l, i, entries...)
45 s.Flush()
46 }
47
48 func writeEntries(w *bufio.Writer, pkg string, _ LogLevel, _ int, entries ...interface{}) {
49 if pkg != "" {
50 w.WriteString(pkg + ": ")
51 }
52 str := fmt.Sprint(entries...)
53 endsInNL := strings.HasSuffix(str, "\n")
54 w.WriteString(str)
55 if !endsInNL {
56 w.WriteString("\n")
57 }
58 }
59
60 func (s *StringFormatter) Flush() {
61 s.w.Flush()
62 }
63
64 func NewPrettyFormatter(w io.Writer, debug bool) Formatter {
65 return &PrettyFormatter{
66 w: bufio.NewWriter(w),
67 debug: debug,
68 }
69 }
70
71 type PrettyFormatter struct {
72 w *bufio.Writer
73 debug bool
74 }
75
76 func (c *PrettyFormatter) Format(pkg string, l LogLevel, depth int, entries ...interface{}) {
77 now := time.Now()
78 ts := now.Format("2006-01-02 15:04:05")
79 c.w.WriteString(ts)
80 ms := now.Nanosecond() / 1000
81 c.w.WriteString(fmt.Sprintf(".%06d", ms))
82 if c.debug {
83 _, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
84 if !ok {
85 file = "???"
86 line = 1
87 } else {
88 slash := strings.LastIndex(file, "/")
89 if slash >= 0 {
90 file = file[slash+1:]
91 }
92 }
93 if line < 0 {
94 line = 0 // not a real line number
95 }
96 c.w.WriteString(fmt.Sprintf(" [%s:%d]", file, line))
97 }
98 c.w.WriteString(fmt.Sprint(" ", l.Char(), " | "))
99 writeEntries(c.w, pkg, l, depth, entries...)
100 c.Flush()
101 }
102
103 func (c *PrettyFormatter) Flush() {
104 c.w.Flush()
105 }
+0
-96
capnslog/glog_formatter.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import (
17 "bufio"
18 "bytes"
19 "io"
20 "os"
21 "runtime"
22 "strconv"
23 "strings"
24 "time"
25 )
26
27 var pid = os.Getpid()
28
29 type GlogFormatter struct {
30 StringFormatter
31 }
32
33 func NewGlogFormatter(w io.Writer) *GlogFormatter {
34 g := &GlogFormatter{}
35 g.w = bufio.NewWriter(w)
36 return g
37 }
38
39 func (g GlogFormatter) Format(pkg string, level LogLevel, depth int, entries ...interface{}) {
40 g.w.Write(GlogHeader(level, depth+1))
41 g.StringFormatter.Format(pkg, level, depth+1, entries...)
42 }
43
44 func GlogHeader(level LogLevel, depth int) []byte {
45 // Lmmdd hh:mm:ss.uuuuuu threadid file:line]
46 now := time.Now().UTC()
47 _, file, line, ok := runtime.Caller(depth) // It's always the same number of frames to the user's call.
48 if !ok {
49 file = "???"
50 line = 1
51 } else {
52 slash := strings.LastIndex(file, "/")
53 if slash >= 0 {
54 file = file[slash+1:]
55 }
56 }
57 if line < 0 {
58 line = 0 // not a real line number
59 }
60 buf := &bytes.Buffer{}
61 buf.Grow(30)
62 _, month, day := now.Date()
63 hour, minute, second := now.Clock()
64 buf.WriteString(level.Char())
65 twoDigits(buf, int(month))
66 twoDigits(buf, day)
67 buf.WriteByte(' ')
68 twoDigits(buf, hour)
69 buf.WriteByte(':')
70 twoDigits(buf, minute)
71 buf.WriteByte(':')
72 twoDigits(buf, second)
73 buf.WriteByte('.')
74 buf.WriteString(strconv.Itoa(now.Nanosecond() / 1000))
75 buf.WriteByte('Z')
76 buf.WriteByte(' ')
77 buf.WriteString(strconv.Itoa(pid))
78 buf.WriteByte(' ')
79 buf.WriteString(file)
80 buf.WriteByte(':')
81 buf.WriteString(strconv.Itoa(line))
82 buf.WriteByte(']')
83 buf.WriteByte(' ')
84 return buf.Bytes()
85 }
86
87 const digits = "0123456789"
88
89 func twoDigits(b *bytes.Buffer, d int) {
90 c2 := digits[d%10]
91 d /= 10
92 c1 := digits[d%10]
93 b.WriteByte(c1)
94 b.WriteByte(c2)
95 }
+0
-49
capnslog/init.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // +build !windows
15
16 package capnslog
17
18 import (
19 "io"
20 "os"
21 "syscall"
22 )
23
24 // Here's where the opinionation comes in. We need some sensible defaults,
25 // especially after taking over the log package. Your project (whatever it may
26 // be) may see things differently. That's okay; there should be no defaults in
27 // the main package that cannot be controlled or overridden programatically,
28 // otherwise it's a bug. Doing so is creating your own init_log.go file much
29 // like this one.
30
31 func init() {
32 initHijack()
33
34 // Go `log` pacakge uses os.Stderr.
35 SetFormatter(NewDefaultFormatter(os.Stderr))
36 SetGlobalLogLevel(INFO)
37 }
38
39 func NewDefaultFormatter(out io.Writer) Formatter {
40 if syscall.Getppid() == 1 {
41 // We're running under init, which may be systemd.
42 f, err := NewJournaldFormatter()
43 if err == nil {
44 return f
45 }
46 }
47 return NewPrettyFormatter(out, false)
48 }
+0
-25
capnslog/init_windows.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import "os"
17
18 func init() {
19 initHijack()
20
21 // Go `log` package uses os.Stderr.
22 SetFormatter(NewPrettyFormatter(os.Stderr, false))
23 SetGlobalLogLevel(INFO)
24 }
+0
-68
capnslog/journald_formatter.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // +build !windows
15
16 package capnslog
17
18 import (
19 "errors"
20 "fmt"
21 "os"
22 "path/filepath"
23
24 "github.com/coreos/go-systemd/journal"
25 )
26
27 func NewJournaldFormatter() (Formatter, error) {
28 if !journal.Enabled() {
29 return nil, errors.New("No systemd detected")
30 }
31 return &journaldFormatter{}, nil
32 }
33
34 type journaldFormatter struct{}
35
36 func (j *journaldFormatter) Format(pkg string, l LogLevel, _ int, entries ...interface{}) {
37 var pri journal.Priority
38 switch l {
39 case CRITICAL:
40 pri = journal.PriCrit
41 case ERROR:
42 pri = journal.PriErr
43 case WARNING:
44 pri = journal.PriWarning
45 case NOTICE:
46 pri = journal.PriNotice
47 case INFO:
48 pri = journal.PriInfo
49 case DEBUG:
50 pri = journal.PriDebug
51 case TRACE:
52 pri = journal.PriDebug
53 default:
54 panic("Unhandled loglevel")
55 }
56 msg := fmt.Sprint(entries...)
57 tags := map[string]string{
58 "PACKAGE": pkg,
59 "SYSLOG_IDENTIFIER": filepath.Base(os.Args[0]),
60 }
61 err := journal.Send(msg, pri, tags)
62 if err != nil {
63 fmt.Fprintln(os.Stderr, err)
64 }
65 }
66
67 func (j *journaldFormatter) Flush() {}
+0
-39
capnslog/log_hijack.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import (
17 "log"
18 )
19
20 func initHijack() {
21 pkg := NewPackageLogger("log", "")
22 w := packageWriter{pkg}
23 log.SetFlags(0)
24 log.SetPrefix("")
25 log.SetOutput(w)
26 }
27
28 type packageWriter struct {
29 pl *PackageLogger
30 }
31
32 func (p packageWriter) Write(b []byte) (int, error) {
33 if p.pl.level < INFO {
34 return 0, nil
35 }
36 p.pl.internalLog(calldepth+2, INFO, string(b))
37 return len(b), nil
38 }
+0
-240
capnslog/logmap.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import (
17 "errors"
18 "strings"
19 "sync"
20 )
21
22 // LogLevel is the set of all log levels.
23 type LogLevel int8
24
25 const (
26 // CRITICAL is the lowest log level; only errors which will end the program will be propagated.
27 CRITICAL LogLevel = iota - 1
28 // ERROR is for errors that are not fatal but lead to troubling behavior.
29 ERROR
30 // WARNING is for errors which are not fatal and not errors, but are unusual. Often sourced from misconfigurations.
31 WARNING
32 // NOTICE is for normal but significant conditions.
33 NOTICE
34 // INFO is a log level for common, everyday log updates.
35 INFO
36 // DEBUG is the default hidden level for more verbose updates about internal processes.
37 DEBUG
38 // TRACE is for (potentially) call by call tracing of programs.
39 TRACE
40 )
41
42 // Char returns a single-character representation of the log level.
43 func (l LogLevel) Char() string {
44 switch l {
45 case CRITICAL:
46 return "C"
47 case ERROR:
48 return "E"
49 case WARNING:
50 return "W"
51 case NOTICE:
52 return "N"
53 case INFO:
54 return "I"
55 case DEBUG:
56 return "D"
57 case TRACE:
58 return "T"
59 default:
60 panic("Unhandled loglevel")
61 }
62 }
63
64 // String returns a multi-character representation of the log level.
65 func (l LogLevel) String() string {
66 switch l {
67 case CRITICAL:
68 return "CRITICAL"
69 case ERROR:
70 return "ERROR"
71 case WARNING:
72 return "WARNING"
73 case NOTICE:
74 return "NOTICE"
75 case INFO:
76 return "INFO"
77 case DEBUG:
78 return "DEBUG"
79 case TRACE:
80 return "TRACE"
81 default:
82 panic("Unhandled loglevel")
83 }
84 }
85
86 // Update using the given string value. Fulfills the flag.Value interface.
87 func (l *LogLevel) Set(s string) error {
88 value, err := ParseLevel(s)
89 if err != nil {
90 return err
91 }
92
93 *l = value
94 return nil
95 }
96
97 // ParseLevel translates some potential loglevel strings into their corresponding levels.
98 func ParseLevel(s string) (LogLevel, error) {
99 switch s {
100 case "CRITICAL", "C":
101 return CRITICAL, nil
102 case "ERROR", "0", "E":
103 return ERROR, nil
104 case "WARNING", "1", "W":
105 return WARNING, nil
106 case "NOTICE", "2", "N":
107 return NOTICE, nil
108 case "INFO", "3", "I":
109 return INFO, nil
110 case "DEBUG", "4", "D":
111 return DEBUG, nil
112 case "TRACE", "5", "T":
113 return TRACE, nil
114 }
115 return CRITICAL, errors.New("couldn't parse log level " + s)
116 }
117
118 type RepoLogger map[string]*PackageLogger
119
120 type loggerStruct struct {
121 sync.Mutex
122 repoMap map[string]RepoLogger
123 formatter Formatter
124 }
125
126 // logger is the global logger
127 var logger = new(loggerStruct)
128
129 // SetGlobalLogLevel sets the log level for all packages in all repositories
130 // registered with capnslog.
131 func SetGlobalLogLevel(l LogLevel) {
132 logger.Lock()
133 defer logger.Unlock()
134 for _, r := range logger.repoMap {
135 r.setRepoLogLevelInternal(l)
136 }
137 }
138
139 // GetRepoLogger may return the handle to the repository's set of packages' loggers.
140 func GetRepoLogger(repo string) (RepoLogger, error) {
141 logger.Lock()
142 defer logger.Unlock()
143 r, ok := logger.repoMap[repo]
144 if !ok {
145 return nil, errors.New("no packages registered for repo " + repo)
146 }
147 return r, nil
148 }
149
150 // MustRepoLogger returns the handle to the repository's packages' loggers.
151 func MustRepoLogger(repo string) RepoLogger {
152 r, err := GetRepoLogger(repo)
153 if err != nil {
154 panic(err)
155 }
156 return r
157 }
158
159 // SetRepoLogLevel sets the log level for all packages in the repository.
160 func (r RepoLogger) SetRepoLogLevel(l LogLevel) {
161 logger.Lock()
162 defer logger.Unlock()
163 r.setRepoLogLevelInternal(l)
164 }
165
166 func (r RepoLogger) setRepoLogLevelInternal(l LogLevel) {
167 for _, v := range r {
168 v.level = l
169 }
170 }
171
172 // ParseLogLevelConfig parses a comma-separated string of "package=loglevel", in
173 // order, and returns a map of the results, for use in SetLogLevel.
174 func (r RepoLogger) ParseLogLevelConfig(conf string) (map[string]LogLevel, error) {
175 setlist := strings.Split(conf, ",")
176 out := make(map[string]LogLevel)
177 for _, setstring := range setlist {
178 setting := strings.Split(setstring, "=")
179 if len(setting) != 2 {
180 return nil, errors.New("oddly structured `pkg=level` option: " + setstring)
181 }
182 l, err := ParseLevel(setting[1])
183 if err != nil {
184 return nil, err
185 }
186 out[setting[0]] = l
187 }
188 return out, nil
189 }
190
191 // SetLogLevel takes a map of package names within a repository to their desired
192 // loglevel, and sets the levels appropriately. Unknown packages are ignored.
193 // "*" is a special package name that corresponds to all packages, and will be
194 // processed first.
195 func (r RepoLogger) SetLogLevel(m map[string]LogLevel) {
196 logger.Lock()
197 defer logger.Unlock()
198 if l, ok := m["*"]; ok {
199 r.setRepoLogLevelInternal(l)
200 }
201 for k, v := range m {
202 l, ok := r[k]
203 if !ok {
204 continue
205 }
206 l.level = v
207 }
208 }
209
210 // SetFormatter sets the formatting function for all logs.
211 func SetFormatter(f Formatter) {
212 logger.Lock()
213 defer logger.Unlock()
214 logger.formatter = f
215 }
216
217 // NewPackageLogger creates a package logger object.
218 // This should be defined as a global var in your package, referencing your repo.
219 func NewPackageLogger(repo string, pkg string) (p *PackageLogger) {
220 logger.Lock()
221 defer logger.Unlock()
222 if logger.repoMap == nil {
223 logger.repoMap = make(map[string]RepoLogger)
224 }
225 r, rok := logger.repoMap[repo]
226 if !rok {
227 logger.repoMap[repo] = make(RepoLogger)
228 r = logger.repoMap[repo]
229 }
230 p, pok := r[pkg]
231 if !pok {
232 r[pkg] = &PackageLogger{
233 pkg: pkg,
234 level: INFO,
235 }
236 p = r[pkg]
237 }
238 return
239 }
+0
-158
capnslog/pkg_logger.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package capnslog
15
16 import (
17 "fmt"
18 "os"
19 )
20
21 type PackageLogger struct {
22 pkg string
23 level LogLevel
24 }
25
26 const calldepth = 2
27
28 func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...interface{}) {
29 if inLevel != CRITICAL && p.level < inLevel {
30 return
31 }
32 logger.Lock()
33 defer logger.Unlock()
34 if logger.formatter != nil {
35 logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
36 }
37 }
38
39 func (p *PackageLogger) LevelAt(l LogLevel) bool {
40 return p.level >= l
41 }
42
43 // Log a formatted string at any level between ERROR and TRACE
44 func (p *PackageLogger) Logf(l LogLevel, format string, args ...interface{}) {
45 p.internalLog(calldepth, l, fmt.Sprintf(format, args...))
46 }
47
48 // Log a message at any level between ERROR and TRACE
49 func (p *PackageLogger) Log(l LogLevel, args ...interface{}) {
50 p.internalLog(calldepth, l, fmt.Sprint(args...))
51 }
52
53 // log stdlib compatibility
54
55 func (p *PackageLogger) Println(args ...interface{}) {
56 p.internalLog(calldepth, INFO, fmt.Sprintln(args...))
57 }
58
59 func (p *PackageLogger) Printf(format string, args ...interface{}) {
60 p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
61 }
62
63 func (p *PackageLogger) Print(args ...interface{}) {
64 p.internalLog(calldepth, INFO, fmt.Sprint(args...))
65 }
66
67 // Panic and fatal
68
69 func (p *PackageLogger) Panicf(format string, args ...interface{}) {
70 s := fmt.Sprintf(format, args...)
71 p.internalLog(calldepth, CRITICAL, s)
72 panic(s)
73 }
74
75 func (p *PackageLogger) Panic(args ...interface{}) {
76 s := fmt.Sprint(args...)
77 p.internalLog(calldepth, CRITICAL, s)
78 panic(s)
79 }
80
81 func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
82 s := fmt.Sprintf(format, args...)
83 p.internalLog(calldepth, CRITICAL, s)
84 os.Exit(1)
85 }
86
87 func (p *PackageLogger) Fatal(args ...interface{}) {
88 s := fmt.Sprint(args...)
89 p.internalLog(calldepth, CRITICAL, s)
90 os.Exit(1)
91 }
92
93 // Error Functions
94
95 func (p *PackageLogger) Errorf(format string, args ...interface{}) {
96 p.internalLog(calldepth, ERROR, fmt.Sprintf(format, args...))
97 }
98
99 func (p *PackageLogger) Error(entries ...interface{}) {
100 p.internalLog(calldepth, ERROR, entries...)
101 }
102
103 // Warning Functions
104
105 func (p *PackageLogger) Warningf(format string, args ...interface{}) {
106 p.internalLog(calldepth, WARNING, fmt.Sprintf(format, args...))
107 }
108
109 func (p *PackageLogger) Warning(entries ...interface{}) {
110 p.internalLog(calldepth, WARNING, entries...)
111 }
112
113 // Notice Functions
114
115 func (p *PackageLogger) Noticef(format string, args ...interface{}) {
116 p.internalLog(calldepth, NOTICE, fmt.Sprintf(format, args...))
117 }
118
119 func (p *PackageLogger) Notice(entries ...interface{}) {
120 p.internalLog(calldepth, NOTICE, entries...)
121 }
122
123 // Info Functions
124
125 func (p *PackageLogger) Infof(format string, args ...interface{}) {
126 p.internalLog(calldepth, INFO, fmt.Sprintf(format, args...))
127 }
128
129 func (p *PackageLogger) Info(entries ...interface{}) {
130 p.internalLog(calldepth, INFO, entries...)
131 }
132
133 // Debug Functions
134
135 func (p *PackageLogger) Debugf(format string, args ...interface{}) {
136 p.internalLog(calldepth, DEBUG, fmt.Sprintf(format, args...))
137 }
138
139 func (p *PackageLogger) Debug(entries ...interface{}) {
140 p.internalLog(calldepth, DEBUG, entries...)
141 }
142
143 // Trace Functions
144
145 func (p *PackageLogger) Tracef(format string, args ...interface{}) {
146 p.internalLog(calldepth, TRACE, fmt.Sprintf(format, args...))
147 }
148
149 func (p *PackageLogger) Trace(entries ...interface{}) {
150 p.internalLog(calldepth, TRACE, entries...)
151 }
152
153 func (p *PackageLogger) Flush() {
154 logger.Lock()
155 defer logger.Unlock()
156 logger.formatter.Flush()
157 }
+0
-65
capnslog/syslog_formatter.go less more
0 // Copyright 2015 CoreOS, Inc.
1 //
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 //
14 // +build !windows
15
16 package capnslog
17
18 import (
19 "fmt"
20 "log/syslog"
21 )
22
23 func NewSyslogFormatter(w *syslog.Writer) Formatter {
24 return &syslogFormatter{w}
25 }
26
27 func NewDefaultSyslogFormatter(tag string) (Formatter, error) {
28 w, err := syslog.New(syslog.LOG_DEBUG, tag)
29 if err != nil {
30 return nil, err
31 }
32 return NewSyslogFormatter(w), nil
33 }
34
35 type syslogFormatter struct {
36 w *syslog.Writer
37 }
38
39 func (s *syslogFormatter) Format(pkg string, l LogLevel, _ int, entries ...interface{}) {
40 for _, entry := range entries {
41 str := fmt.Sprint(entry)
42 switch l {
43 case CRITICAL:
44 s.w.Crit(str)
45 case ERROR:
46 s.w.Err(str)
47 case WARNING:
48 s.w.Warning(str)
49 case NOTICE:
50 s.w.Notice(str)
51 case INFO:
52 s.w.Info(str)
53 case DEBUG:
54 s.w.Debug(str)
55 case TRACE:
56 s.w.Debug(str)
57 default:
58 panic("Unhandled loglevel")
59 }
60 }
61 }
62
63 func (s *syslogFormatter) Flush() {
64 }
+0
-94
cryptoutil/aes.go less more
0 package cryptoutil
1
2 import (
3 "crypto/aes"
4 "crypto/cipher"
5 "crypto/rand"
6 "errors"
7 )
8
9 // pad uses the PKCS#7 padding scheme to align the a payload to a specific block size
10 func pad(plaintext []byte, bsize int) ([]byte, error) {
11 if bsize >= 256 {
12 return nil, errors.New("bsize must be < 256")
13 }
14 pad := bsize - (len(plaintext) % bsize)
15 if pad == 0 {
16 pad = bsize
17 }
18 for i := 0; i < pad; i++ {
19 plaintext = append(plaintext, byte(pad))
20 }
21 return plaintext, nil
22 }
23
24 // unpad strips the padding previously added using the PKCS#7 padding scheme
25 func unpad(paddedtext []byte) ([]byte, error) {
26 length := len(paddedtext)
27 paddedtext, lbyte := paddedtext[:length-1], paddedtext[length-1]
28 pad := int(lbyte)
29 if pad >= 256 || pad > length {
30 return nil, errors.New("padding malformed")
31 }
32 return paddedtext[:length-(pad)], nil
33 }
34
35 // AESEncrypt encrypts a payload with an AES cipher.
36 // The returned ciphertext has three notable properties:
37 // 1. ciphertext is aligned to the standard AES block size
38 // 2. ciphertext is padded using PKCS#7
39 // 3. IV is prepended to the ciphertext
40 func AESEncrypt(plaintext, key []byte) ([]byte, error) {
41 plaintext, err := pad(plaintext, aes.BlockSize)
42 if err != nil {
43 return nil, err
44 }
45
46 block, err := aes.NewCipher(key)
47 if err != nil {
48 return nil, err
49 }
50
51 ciphertext := make([]byte, aes.BlockSize+len(plaintext))
52 iv := ciphertext[:aes.BlockSize]
53 if _, err := rand.Read(iv); err != nil {
54 return nil, err
55 }
56
57 mode := cipher.NewCBCEncrypter(block, iv)
58 mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
59
60 return ciphertext, nil
61 }
62
63 // AESDecrypt decrypts an encrypted payload with an AES cipher.
64 // The decryption algorithm makes three assumptions:
65 // 1. ciphertext is aligned to the standard AES block size
66 // 2. ciphertext is padded using PKCS#7
67 // 3. the IV is prepended to ciphertext
68 func AESDecrypt(ciphertext, key []byte) ([]byte, error) {
69 if len(ciphertext) < aes.BlockSize {
70 return nil, errors.New("ciphertext too short")
71 }
72
73 iv := ciphertext[:aes.BlockSize]
74 ciphertext = ciphertext[aes.BlockSize:]
75
76 if len(ciphertext)%aes.BlockSize != 0 {
77 return nil, errors.New("ciphertext is not a multiple of the block size")
78 }
79
80 block, err := aes.NewCipher(key)
81 if err != nil {
82 return nil, err
83 }
84
85 mode := cipher.NewCBCDecrypter(block, iv)
86 mode.CryptBlocks(ciphertext, ciphertext)
87
88 if len(ciphertext)%aes.BlockSize != 0 {
89 return nil, errors.New("ciphertext is not a multiple of the block size")
90 }
91
92 return unpad(ciphertext)
93 }
+0
-93
cryptoutil/aes_test.go less more
0 package cryptoutil
1
2 import (
3 "reflect"
4 "testing"
5 )
6
7 func TestPadUnpad(t *testing.T) {
8 tests := []struct {
9 plaintext []byte
10 bsize int
11 padded []byte
12 }{
13 {
14 plaintext: []byte{1, 2, 3, 4},
15 bsize: 7,
16 padded: []byte{1, 2, 3, 4, 3, 3, 3},
17 },
18 {
19 plaintext: []byte{1, 2, 3, 4, 5, 6, 7},
20 bsize: 3,
21 padded: []byte{1, 2, 3, 4, 5, 6, 7, 2, 2},
22 },
23 {
24 plaintext: []byte{9, 9, 9, 9},
25 bsize: 4,
26 padded: []byte{9, 9, 9, 9, 4, 4, 4, 4},
27 },
28 }
29
30 for i, tt := range tests {
31 padded, err := pad(tt.plaintext, tt.bsize)
32 if err != nil {
33 t.Errorf("case %d: unexpected error: %v", i, err)
34 continue
35 }
36 if !reflect.DeepEqual(tt.padded, padded) {
37 t.Errorf("case %d: want=%v got=%v", i, tt.padded, padded)
38 continue
39 }
40
41 plaintext, err := unpad(tt.padded)
42 if err != nil {
43 t.Errorf("case %d: unexpected error: %v", i, err)
44 continue
45 }
46 if !reflect.DeepEqual(tt.plaintext, plaintext) {
47 t.Errorf("case %d: want=%v got=%v", i, tt.plaintext, plaintext)
48 continue
49 }
50 }
51 }
52
53 func TestPadMaxBlockSize(t *testing.T) {
54 _, err := pad([]byte{1, 2, 3}, 256)
55 if err == nil {
56 t.Errorf("Expected non-nil error")
57 }
58 }
59
60 func TestAESEncryptDecrypt(t *testing.T) {
61 message := []byte("Let me worry about blank.")
62 key := append([]byte("shark"), make([]byte, 27)...)
63
64 ciphertext, err := AESEncrypt(message, key)
65 if err != nil {
66 t.Fatalf("Unexpected error: %v", err)
67 }
68 if reflect.DeepEqual(message, ciphertext) {
69 t.Fatal("Encrypted data matches original payload")
70 }
71
72 decrypted, err := AESDecrypt(ciphertext, key)
73 if !reflect.DeepEqual(message, decrypted) {
74 t.Fatalf("Decrypted data does not match original payload: want=%v got=%v", message, decrypted)
75 }
76 }
77
78 func TestAESDecryptWrongKey(t *testing.T) {
79 message := []byte("My bones!")
80 key := append([]byte("shark"), make([]byte, 27)...)
81
82 ciphertext, err := AESEncrypt(message, key)
83 if err != nil {
84 t.Fatalf("Unexpected error: %v", err)
85 }
86
87 wrongKey := append([]byte("sheep"), make([]byte, 27)...)
88 decrypted, _ := AESDecrypt(ciphertext, wrongKey)
89 if reflect.DeepEqual(message, decrypted) {
90 t.Fatalf("Data decrypted with different key matches original payload")
91 }
92 }
0 [DEFAULT]
0 [buildpackage]
1 overlay = True
2 export-dir = ../build-area/
3 tarball-dir = ../
4
5 [dch]
6 id-length = 0
7
8 [import-orig]
19 pristine-tar = True
10 merge = False
+0
-33
flagutil/env.go less more
0 package flagutil
1
2 import (
3 "flag"
4 "fmt"
5 "os"
6 "strings"
7 )
8
9 // SetFlagsFromEnv parses all registered flags in the given flagset,
10 // and if they are not already set it attempts to set their values from
11 // environment variables. Environment variables take the name of the flag but
12 // are UPPERCASE, and any dashes are replaced by underscores. Environment
13 // variables additionally are prefixed by the given string followed by
14 // and underscore. For example, if prefix=PREFIX: some-flag => PREFIX_SOME_FLAG
15 func SetFlagsFromEnv(fs *flag.FlagSet, prefix string) (err error) {
16 alreadySet := make(map[string]bool)
17 fs.Visit(func(f *flag.Flag) {
18 alreadySet[f.Name] = true
19 })
20 fs.VisitAll(func(f *flag.Flag) {
21 if !alreadySet[f.Name] {
22 key := prefix + "_" + strings.ToUpper(strings.Replace(f.Name, "-", "_", -1))
23 val := os.Getenv(key)
24 if val != "" {
25 if serr := fs.Set(f.Name, val); serr != nil {
26 err = fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
27 }
28 }
29 }
30 })
31 return err
32 }
+0
-64
flagutil/env_test.go less more
0 package flagutil
1
2 import (
3 "flag"
4 "os"
5 "testing"
6 )
7
8 func TestSetFlagsFromEnv(t *testing.T) {
9 fs := flag.NewFlagSet("testing", flag.ExitOnError)
10 fs.String("a", "", "")
11 fs.String("b", "", "")
12 fs.String("c", "", "")
13 fs.Parse([]string{})
14
15 os.Clearenv()
16 // flags should be settable using env vars
17 os.Setenv("MYPROJ_A", "foo")
18 // and command-line flags
19 if err := fs.Set("b", "bar"); err != nil {
20 t.Fatal(err)
21 }
22 // command-line flags take precedence over env vars
23 os.Setenv("MYPROJ_C", "woof")
24 if err := fs.Set("c", "quack"); err != nil {
25 t.Fatal(err)
26 }
27
28 // first verify that flags are as expected before reading the env
29 for f, want := range map[string]string{
30 "a": "",
31 "b": "bar",
32 "c": "quack",
33 } {
34 if got := fs.Lookup(f).Value.String(); got != want {
35 t.Fatalf("flag %q=%q, want %q", f, got, want)
36 }
37 }
38
39 // now read the env and verify flags were updated as expected
40 err := SetFlagsFromEnv(fs, "MYPROJ")
41 if err != nil {
42 t.Errorf("err=%v, want nil", err)
43 }
44 for f, want := range map[string]string{
45 "a": "foo",
46 "b": "bar",
47 "c": "quack",
48 } {
49 if got := fs.Lookup(f).Value.String(); got != want {
50 t.Errorf("flag %q=%q, want %q", f, got, want)
51 }
52 }
53 }
54
55 func TestSetFlagsFromEnvBad(t *testing.T) {
56 // now verify that an error is propagated
57 fs := flag.NewFlagSet("testing", flag.ExitOnError)
58 fs.Int("x", 0, "")
59 os.Setenv("MYPROJ_X", "not_a_number")
60 if err := SetFlagsFromEnv(fs, "MYPROJ"); err == nil {
61 t.Errorf("err=nil, want != nil")
62 }
63 }
+0
-44
flagutil/types.go less more
0 package flagutil
1
2 import (
3 "errors"
4 "fmt"
5 "net"
6 "strings"
7 )
8
9 // IPv4Flag parses a string into a net.IP after asserting that it
10 // is an IPv4 address. This type implements the flag.Value interface.
11 type IPv4Flag struct {
12 val net.IP
13 }
14
15 func (f *IPv4Flag) IP() net.IP {
16 return f.val
17 }
18
19 func (f *IPv4Flag) Set(v string) error {
20 ip := net.ParseIP(v)
21 if ip == nil || ip.To4() == nil {
22 return errors.New("not an IPv4 address")
23 }
24 f.val = ip
25 return nil
26 }
27
28 func (f *IPv4Flag) String() string {
29 return f.val.String()
30 }
31
32 // StringSliceFlag parses a comma-delimited list of strings into
33 // a []string. This type implements the flag.Value interface.
34 type StringSliceFlag []string
35
36 func (ss *StringSliceFlag) String() string {
37 return fmt.Sprintf("%+v", *ss)
38 }
39
40 func (ss *StringSliceFlag) Set(v string) error {
41 *ss = strings.Split(v, ",")
42 return nil
43 }
+0
-57
flagutil/types_test.go less more
0 package flagutil
1
2 import (
3 "reflect"
4 "testing"
5 )
6
7 func TestIPv4FlagSetInvalidArgument(t *testing.T) {
8 tests := []string{
9 "",
10 "foo",
11 "::",
12 "127.0.0.1:4328",
13 }
14
15 for i, tt := range tests {
16 var f IPv4Flag
17 if err := f.Set(tt); err == nil {
18 t.Errorf("case %d: expected non-nil error", i)
19 }
20 }
21 }
22
23 func TestIPv4FlagSetValidArgument(t *testing.T) {
24 tests := []string{
25 "127.0.0.1",
26 "0.0.0.0",
27 }
28
29 for i, tt := range tests {
30 var f IPv4Flag
31 if err := f.Set(tt); err != nil {
32 t.Errorf("case %d: err=%v", i, err)
33 }
34 }
35 }
36
37 func TestStringSliceFlag(t *testing.T) {
38 tests := []struct {
39 input string
40 want []string
41 }{
42 {input: "", want: []string{""}},
43 {input: "foo", want: []string{"foo"}},
44 {input: "foo,bar", want: []string{"foo", "bar"}},
45 }
46
47 for i, tt := range tests {
48 var f StringSliceFlag
49 if err := f.Set(tt.input); err != nil {
50 t.Errorf("case %d: err=%v", i, err)
51 }
52 if !reflect.DeepEqual(tt.want, []string(f)) {
53 t.Errorf("case %d: want=%v got=%v", i, tt.want, f)
54 }
55 }
56 }
+0
-11
health/README.md less more
0 health
1 ====
2
3 A simple framework for implementing an HTTP health check endpoint on servers.
4
5 Users implement their `health.Checkable` types, and create a `health.Checker`, from which they can get an `http.HandlerFunc` using `health.Checker.MakeHealthHandlerFunc`.
6
7 ### Documentation
8
9 For more details, visit the docs on [gopkgdoc](http://godoc.org/github.com/coreos/pkg/health)
10
+0
-127
health/health.go less more
0 package health
1
2 import (
3 "expvar"
4 "fmt"
5 "log"
6 "net/http"
7
8 "github.com/coreos/pkg/httputil"
9 )
10
11 // Checkables should return nil when the thing they are checking is healthy, and an error otherwise.
12 type Checkable interface {
13 Healthy() error
14 }
15
16 // Checker provides a way to make an endpoint which can be probed for system health.
17 type Checker struct {
18 // Checks are the Checkables to be checked when probing.
19 Checks []Checkable
20
21 // Unhealthyhandler is called when one or more of the checks are unhealthy.
22 // If not provided DefaultUnhealthyHandler is called.
23 UnhealthyHandler UnhealthyHandler
24
25 // HealthyHandler is called when all checks are healthy.
26 // If not provided, DefaultHealthyHandler is called.
27 HealthyHandler http.HandlerFunc
28 }
29
30 func (c Checker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
31 unhealthyHandler := c.UnhealthyHandler
32 if unhealthyHandler == nil {
33 unhealthyHandler = DefaultUnhealthyHandler
34 }
35
36 successHandler := c.HealthyHandler
37 if successHandler == nil {
38 successHandler = DefaultHealthyHandler
39 }
40
41 if r.Method != "GET" {
42 w.Header().Set("Allow", "GET")
43 w.WriteHeader(http.StatusMethodNotAllowed)
44 return
45 }
46
47 if err := Check(c.Checks); err != nil {
48 unhealthyHandler(w, r, err)
49 return
50 }
51
52 successHandler(w, r)
53 }
54
55 type UnhealthyHandler func(w http.ResponseWriter, r *http.Request, err error)
56
57 type StatusResponse struct {
58 Status string `json:"status"`
59 Details *StatusResponseDetails `json:"details,omitempty"`
60 }
61
62 type StatusResponseDetails struct {
63 Code int `json:"code,omitempty"`
64 Message string `json:"message,omitempty"`
65 }
66
67 func Check(checks []Checkable) (err error) {
68 errs := []error{}
69 for _, c := range checks {
70 if e := c.Healthy(); e != nil {
71 errs = append(errs, e)
72 }
73 }
74
75 switch len(errs) {
76 case 0:
77 err = nil
78 case 1:
79 err = errs[0]
80 default:
81 err = fmt.Errorf("multiple health check failure: %v", errs)
82 }
83
84 return
85 }
86
87 func DefaultHealthyHandler(w http.ResponseWriter, r *http.Request) {
88 err := httputil.WriteJSONResponse(w, http.StatusOK, StatusResponse{
89 Status: "ok",
90 })
91 if err != nil {
92 // TODO(bobbyrullo): replace with logging from new logging pkg,
93 // once it lands.
94 log.Printf("Failed to write JSON response: %v", err)
95 }
96 }
97
98 func DefaultUnhealthyHandler(w http.ResponseWriter, r *http.Request, err error) {
99 writeErr := httputil.WriteJSONResponse(w, http.StatusInternalServerError, StatusResponse{
100 Status: "error",
101 Details: &StatusResponseDetails{
102 Code: http.StatusInternalServerError,
103 Message: err.Error(),
104 },
105 })
106 if writeErr != nil {
107 // TODO(bobbyrullo): replace with logging from new logging pkg,
108 // once it lands.
109 log.Printf("Failed to write JSON response: %v", err)
110 }
111 }
112
113 // ExpvarHandler is copied from https://golang.org/src/expvar/expvar.go, where it's sadly unexported.
114 func ExpvarHandler(w http.ResponseWriter, r *http.Request) {
115 w.Header().Set("Content-Type", "application/json; charset=utf-8")
116 fmt.Fprintf(w, "{\n")
117 first := true
118 expvar.Do(func(kv expvar.KeyValue) {
119 if !first {
120 fmt.Fprintf(w, ",\n")
121 }
122 first = false
123 fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
124 })
125 fmt.Fprintf(w, "\n}\n")
126 }
+0
-198
health/health_test.go less more
0 package health
1
2 import (
3 "encoding/json"
4 "errors"
5 "net/http"
6 "net/http/httptest"
7 "testing"
8
9 "github.com/coreos/pkg/httputil"
10 )
11
12 type boolChecker bool
13
14 func (b boolChecker) Healthy() error {
15 if b {
16 return nil
17 }
18 return errors.New("Unhealthy")
19 }
20
21 func errString(err error) string {
22 if err == nil {
23 return ""
24 }
25 return err.Error()
26 }
27
28 func TestCheck(t *testing.T) {
29 for i, test := range []struct {
30 checks []Checkable
31 expected string
32 }{
33 {[]Checkable{}, ""},
34
35 {[]Checkable{boolChecker(true)}, ""},
36
37 {[]Checkable{boolChecker(true), boolChecker(true)}, ""},
38
39 {[]Checkable{boolChecker(true), boolChecker(false)}, "Unhealthy"},
40
41 {[]Checkable{boolChecker(true), boolChecker(false), boolChecker(false)}, "multiple health check failure: [Unhealthy Unhealthy]"},
42 } {
43 err := Check(test.checks)
44
45 if errString(err) != test.expected {
46 t.Errorf("case %d: want %v, got %v", i, test.expected, errString(err))
47 }
48 }
49 }
50
51 func TestHandlerFunc(t *testing.T) {
52 for i, test := range []struct {
53 checker Checker
54 method string
55 expectedStatus string
56 expectedCode int
57 expectedMessage string
58 }{
59 {
60 Checker{
61 Checks: []Checkable{
62 boolChecker(true),
63 },
64 },
65 "GET",
66 "ok",
67 http.StatusOK,
68 "",
69 },
70
71 // Wrong method.
72 {
73 Checker{
74 Checks: []Checkable{
75 boolChecker(true),
76 },
77 },
78 "POST",
79 "",
80 http.StatusMethodNotAllowed,
81 "GET only acceptable method",
82 },
83
84 // Health check fails.
85 {
86 Checker{
87 Checks: []Checkable{
88 boolChecker(false),
89 },
90 },
91 "GET",
92 "error",
93 http.StatusInternalServerError,
94 "Unhealthy",
95 },
96
97 // Health check fails, with overridden ErrorHandler.
98 {
99 Checker{
100 Checks: []Checkable{
101 boolChecker(false),
102 },
103 UnhealthyHandler: func(w http.ResponseWriter, r *http.Request, err error) {
104 httputil.WriteJSONResponse(w,
105 http.StatusInternalServerError, StatusResponse{
106 Status: "error",
107 Details: &StatusResponseDetails{
108 Code: http.StatusInternalServerError,
109 Message: "Override!",
110 },
111 })
112 },
113 },
114 "GET",
115 "error",
116 http.StatusInternalServerError,
117 "Override!",
118 },
119
120 // Health check succeeds, with overridden SuccessHandler.
121 {
122 Checker{
123 Checks: []Checkable{
124 boolChecker(true),
125 },
126 HealthyHandler: func(w http.ResponseWriter, r *http.Request) {
127 httputil.WriteJSONResponse(w,
128 http.StatusOK, StatusResponse{
129 Status: "okey-dokey",
130 })
131 },
132 },
133 "GET",
134 "okey-dokey",
135 http.StatusOK,
136 "",
137 },
138 } {
139 w := httptest.NewRecorder()
140 r := &http.Request{}
141 r.Method = test.method
142 test.checker.ServeHTTP(w, r)
143 if w.Code != test.expectedCode {
144 t.Errorf("case %d: w.code == %v, want %v", i, w.Code, test.expectedCode)
145 }
146
147 if test.expectedStatus == "" {
148 // This is to handle the wrong-method case, when the
149 // body of the response is empty.
150 continue
151 }
152
153 statusMap := make(map[string]interface{})
154 err := json.Unmarshal(w.Body.Bytes(), &statusMap)
155 if err != nil {
156 t.Fatalf("case %d: failed to Unmarshal response body: %v", i, err)
157 }
158
159 status, ok := statusMap["status"].(string)
160 if !ok {
161 t.Errorf("case %d: status not present or not a string in json: %q", i, w.Body.Bytes())
162 }
163 if status != test.expectedStatus {
164 t.Errorf("case %d: status == %v, want %v", i, status, test.expectedStatus)
165 }
166
167 detailMap, ok := statusMap["details"].(map[string]interface{})
168 if test.expectedMessage != "" {
169 if !ok {
170 t.Fatalf("case %d: could not find/unmarshal detailMap", i)
171 }
172 message, ok := detailMap["message"].(string)
173 if !ok {
174 t.Fatalf("case %d: message not present or not a string in json: %q",
175 i, w.Body.Bytes())
176 }
177 if message != test.expectedMessage {
178 t.Errorf("case %d: message == %v, want %v", i, message, test.expectedMessage)
179 }
180
181 code, ok := detailMap["code"].(float64)
182 if !ok {
183 t.Fatalf("case %d: code not present or not an int in json: %q",
184 i, w.Body.Bytes())
185 }
186 if int(code) != test.expectedCode {
187 t.Errorf("case %d: code == %v, want %v", i, code, test.expectedCode)
188 }
189
190 } else {
191 if ok {
192 t.Errorf("case %d: unwanted detailMap present: %q", i, detailMap)
193 }
194 }
195
196 }
197 }
+0
-13
httputil/README.md less more
0 httputil
1 ====
2
3 Common code for dealing with HTTP.
4
5 Includes:
6
7 * Code for returning JSON responses.
8
9 ### Documentation
10
11 Visit the docs on [gopkgdoc](http://godoc.org/github.com/coreos/pkg/httputil)
12
+0
-21
httputil/cookie.go less more
0 package httputil
1
2 import (
3 "net/http"
4 "time"
5 )
6
7 // DeleteCookies effectively deletes all named cookies
8 // by wiping all data and setting to expire immediately.
9 func DeleteCookies(w http.ResponseWriter, cookieNames ...string) {
10 for _, n := range cookieNames {
11 c := &http.Cookie{
12 Name: n,
13 Value: "",
14 Path: "/",
15 MaxAge: -1,
16 Expires: time.Time{},
17 }
18 http.SetCookie(w, c)
19 }
20 }
+0
-51
httputil/cookie_test.go less more
0 package httputil
1
2 import (
3 "net/http"
4 "net/http/httptest"
5 "testing"
6 "time"
7 )
8
9 func TestDeleteCookies(t *testing.T) {
10 tests := []struct {
11 // cookie names to delete
12 n []string
13 }{
14 // single
15 {
16 n: []string{"foo"},
17 },
18 // multiple
19 {
20 n: []string{"foo", "bar"},
21 },
22 }
23
24 for i, tt := range tests {
25 w := httptest.NewRecorder()
26 DeleteCookies(w, tt.n...)
27 resp := &http.Response{}
28 resp.Header = w.Header()
29 cks := resp.Cookies()
30
31 if len(cks) != len(tt.n) {
32 t.Errorf("case %d: unexpected number of cookies, want: %d, got: %d", i, len(tt.n), len(cks))
33 }
34
35 for _, c := range cks {
36 if c.Value != "" {
37 t.Errorf("case %d: unexpected cookie value, want: %q, got: %q", i, "", c.Value)
38 }
39 if c.Path != "/" {
40 t.Errorf("case %d: unexpected cookie path, want: %q, got: %q", i, "/", c.Path)
41 }
42 if c.MaxAge != -1 {
43 t.Errorf("case %d: unexpected cookie max-age, want: %q, got: %q", i, -1, c.MaxAge)
44 }
45 if !c.Expires.IsZero() {
46 t.Errorf("case %d: unexpected cookie expires, want: %q, got: %q", i, time.Time{}, c.MaxAge)
47 }
48 }
49 }
50 }
+0
-27
httputil/json.go less more
0 package httputil
1
2 import (
3 "encoding/json"
4 "net/http"
5 )
6
7 const (
8 JSONContentType = "application/json"
9 )
10
11 func WriteJSONResponse(w http.ResponseWriter, code int, resp interface{}) error {
12 enc, err := json.Marshal(resp)
13 if err != nil {
14 w.WriteHeader(http.StatusInternalServerError)
15 return err
16 }
17
18 w.Header().Set("Content-Type", JSONContentType)
19 w.WriteHeader(code)
20
21 _, err = w.Write(enc)
22 if err != nil {
23 return err
24 }
25 return nil
26 }
+0
-56
httputil/json_test.go less more
0 package httputil
1
2 import (
3 "net/http/httptest"
4 "testing"
5 )
6
7 func TestWriteJSONResponse(t *testing.T) {
8 for i, test := range []struct {
9 code int
10 resp interface{}
11 expectedJSON string
12 expectErr bool
13 }{
14 {
15 200,
16 struct {
17 A string
18 B string
19 }{A: "foo", B: "bar"},
20 `{"A":"foo","B":"bar"}`,
21 false,
22 },
23 {
24 500,
25 // Something that json.Marshal cannot serialize.
26 make(chan int),
27 "",
28 true,
29 },
30 } {
31 w := httptest.NewRecorder()
32 err := WriteJSONResponse(w, test.code, test.resp)
33
34 if w.Code != test.code {
35 t.Errorf("case %d: w.code == %v, want %v", i, w.Code, test.code)
36 }
37
38 if (err != nil) != test.expectErr {
39 t.Errorf("case %d: (err != nil) == %v, want %v. err: %v", i, err != nil, test.expectErr, err)
40 }
41
42 if string(w.Body.Bytes()) != test.expectedJSON {
43 t.Errorf("case %d: w.Body.Bytes()) == %q, want %q", i,
44 string(w.Body.Bytes()), test.expectedJSON)
45 }
46
47 if !test.expectErr {
48 contentType := w.Header()["Content-Type"][0]
49 if contentType != JSONContentType {
50 t.Errorf("case %d: contentType == %v, want %v", i, contentType, JSONContentType)
51 }
52 }
53 }
54
55 }
+0
-32
multierror/multierror.go less more
0 // Package multierror wraps a slice of errors and implements the error interface.
1 // This can be used to collect a bunch of errors (such as during form validation)
2 // and then return them all together as a single error. To see usage examples
3 // refer to the unit tests.
4 package multierror
5
6 import (
7 "fmt"
8 "strings"
9 )
10
11 type Error []error
12
13 func (me Error) Error() string {
14 if me == nil {
15 return ""
16 }
17
18 strs := make([]string, len(me))
19 for i, err := range me {
20 strs[i] = fmt.Sprintf("[%d] %v", i, err)
21 }
22 return strings.Join(strs, " ")
23 }
24
25 func (me Error) AsError() error {
26 if len([]error(me)) <= 0 {
27 return nil
28 }
29
30 return me
31 }
+0
-59
multierror/multierror_test.go less more
0 package multierror
1
2 import (
3 "errors"
4 "reflect"
5 "testing"
6 )
7
8 func TestAsError(t *testing.T) {
9 tests := []struct {
10 multierr Error
11 want error
12 }{
13 {
14 multierr: Error([]error{errors.New("foo"), errors.New("bar")}),
15 want: Error([]error{errors.New("foo"), errors.New("bar")}),
16 },
17 {
18 multierr: Error([]error{}),
19 want: nil,
20 },
21 {
22 multierr: Error(nil),
23 want: nil,
24 },
25 }
26
27 for i, tt := range tests {
28 got := tt.multierr.AsError()
29 if !reflect.DeepEqual(tt.want, got) {
30 t.Errorf("case %d: incorrect error value: want=%+v got=%+v", i, tt.want, got)
31 }
32 }
33
34 }
35
36 func TestErrorAppend(t *testing.T) {
37 var multierr Error
38 multierr = append(multierr, errors.New("foo"))
39 multierr = append(multierr, errors.New("bar"))
40 multierr = append(multierr, errors.New("baz"))
41 want := Error([]error{errors.New("foo"), errors.New("bar"), errors.New("baz")})
42 got := multierr.AsError()
43 if !reflect.DeepEqual(want, got) {
44 t.Fatalf("incorrect error value: want=%+v got=%+v", want, got)
45 }
46 }
47
48 func TestErrorString(t *testing.T) {
49 var multierr Error
50 multierr = append(multierr, errors.New("foo"))
51 multierr = append(multierr, errors.New("bar"))
52 multierr = append(multierr, errors.New("baz"))
53 got := multierr.Error()
54 want := "[0] foo [1] bar [2] baz"
55 if want != got {
56 t.Fatalf("incorrect output: want=%q got=%q", want, got)
57 }
58 }
+0
-55
netutil/proxy.go less more
0 package netutil
1
2 import (
3 "io"
4 "net"
5 "sync"
6 "time"
7
8 "github.com/coreos/pkg/capnslog"
9 )
10
11 var (
12 log = capnslog.NewPackageLogger("github.com/coreos/pkg/netutil", "main")
13 )
14
15 // ProxyTCP proxies between two TCP connections.
16 // Because TLS connections don't have CloseRead() and CloseWrite() methods, our
17 // temporary solution is to use timeouts.
18 func ProxyTCP(conn1, conn2 net.Conn, tlsWriteDeadline, tlsReadDeadline time.Duration) {
19 var wg sync.WaitGroup
20 wg.Add(2)
21
22 go copyBytes(conn1, conn2, &wg, tlsWriteDeadline, tlsReadDeadline)
23 go copyBytes(conn2, conn1, &wg, tlsWriteDeadline, tlsReadDeadline)
24
25 wg.Wait()
26 conn1.Close()
27 conn2.Close()
28 }
29
30 func copyBytes(dst, src net.Conn, wg *sync.WaitGroup, writeDeadline, readDeadline time.Duration) {
31 defer wg.Done()
32 n, err := io.Copy(dst, src)
33 if err != nil {
34 log.Errorf("proxy i/o error: %v", err)
35 }
36
37 if cr, ok := src.(*net.TCPConn); ok {
38 cr.CloseRead()
39 } else {
40 // For TLS connections.
41 wto := time.Now().Add(writeDeadline)
42 src.SetWriteDeadline(wto)
43 }
44
45 if cw, ok := dst.(*net.TCPConn); ok {
46 cw.CloseWrite()
47 } else {
48 // For TLS connections.
49 rto := time.Now().Add(readDeadline)
50 dst.SetReadDeadline(rto)
51 }
52
53 log.Debugf("proxy copied %d bytes %s -> %s", n, src.RemoteAddr(), dst.RemoteAddr())
54 }
+0
-17
netutil/url.go less more
0 package netutil
1
2 import (
3 "net/url"
4 )
5
6 // MergeQuery appends additional query values to an existing URL.
7 func MergeQuery(u url.URL, q url.Values) url.URL {
8 uv := u.Query()
9 for k, vs := range q {
10 for _, v := range vs {
11 uv.Add(k, v)
12 }
13 }
14 u.RawQuery = uv.Encode()
15 return u
16 }
+0
-86
netutil/url_test.go less more
0 package netutil
1
2 import (
3 "net/url"
4 "reflect"
5 "testing"
6 )
7
8 func TestMergeQuery(t *testing.T) {
9 tests := []struct {
10 u string
11 q url.Values
12 w string
13 }{
14 // No values
15 {
16 u: "http://example.com",
17 q: nil,
18 w: "http://example.com",
19 },
20 // No additional values
21 {
22 u: "http://example.com?foo=bar",
23 q: nil,
24 w: "http://example.com?foo=bar",
25 },
26 // Simple addition
27 {
28 u: "http://example.com",
29 q: url.Values{
30 "foo": []string{"bar"},
31 },
32 w: "http://example.com?foo=bar",
33 },
34 // Addition with existing values
35 {
36 u: "http://example.com?dog=boo",
37 q: url.Values{
38 "foo": []string{"bar"},
39 },
40 w: "http://example.com?dog=boo&foo=bar",
41 },
42 // Merge
43 {
44 u: "http://example.com?dog=boo",
45 q: url.Values{
46 "dog": []string{"elroy"},
47 },
48 w: "http://example.com?dog=boo&dog=elroy",
49 },
50 // Add and merge
51 {
52 u: "http://example.com?dog=boo",
53 q: url.Values{
54 "dog": []string{"elroy"},
55 "foo": []string{"bar"},
56 },
57 w: "http://example.com?dog=boo&dog=elroy&foo=bar",
58 },
59 // Multivalue merge
60 {
61 u: "http://example.com?dog=boo",
62 q: url.Values{
63 "dog": []string{"elroy", "penny"},
64 },
65 w: "http://example.com?dog=boo&dog=elroy&dog=penny",
66 },
67 }
68
69 for i, tt := range tests {
70 ur, err := url.Parse(tt.u)
71 if err != nil {
72 t.Errorf("case %d: failed parsing test url: %v, error: %v", i, tt.u, err)
73 }
74
75 got := MergeQuery(*ur, tt.q)
76 want, err := url.Parse(tt.w)
77 if err != nil {
78 t.Errorf("case %d: failed parsing want url: %v, error: %v", i, tt.w, err)
79 }
80
81 if !reflect.DeepEqual(*want, got) {
82 t.Errorf("case %d: want: %v, got: %v", i, *want, got)
83 }
84 }
85 }
+0
-56
test less more
0 #!/bin/bash -e
1 #
2 # Run all tests (not including functional)
3 # ./test
4 # ./test -v
5 #
6 # Run tests for one package
7 # PKG=./unit ./test
8 # PKG=ssh ./test
9 #
10
11 # Invoke ./cover for HTML output
12 COVER=${COVER:-"-cover"}
13
14 source ./build
15
16 TESTABLE="cryptoutil flagutil timeutil netutil yamlutil httputil health multierror"
17 FORMATTABLE="$TESTABLE capnslog"
18
19 # user has not provided PKG override
20 if [ -z "$PKG" ]; then
21 TEST=$TESTABLE
22 FMT=$FORMATTABLE
23
24 # user has provided PKG override
25 else
26 # strip out slashes and dots from PKG=./foo/
27 TEST=${PKG//\//}
28 TEST=${TEST//./}
29
30 # only run gofmt on packages provided by user
31 FMT="$TEST"
32 fi
33
34 # split TEST into an array and prepend repo path to each local package
35 split=(${TEST// / })
36 TEST=${split[@]/#/github.com/coreos/pkg/}
37
38 echo "Running tests..."
39 go test ${COVER} $@ ${TEST}
40
41 echo "Checking gofmt..."
42 fmtRes=$(gofmt -l $FMT)
43 if [ -n "${fmtRes}" ]; then
44 echo -e "gofmt checking failed:\n${fmtRes}"
45 exit 255
46 fi
47
48 echo "Checking govet..."
49 vetRes=$(go vet $TEST)
50 if [ -n "${vetRes}" ]; then
51 echo -e "govet checking failed:\n${vetRes}"
52 exit 255
53 fi
54
55 echo "Success"
+0
-15
timeutil/backoff.go less more
0 package timeutil
1
2 import (
3 "time"
4 )
5
6 func ExpBackoff(prev, max time.Duration) time.Duration {
7 if prev == 0 {
8 return time.Second
9 }
10 if prev > max/2 {
11 return max
12 }
13 return 2 * prev
14 }
+0
-52
timeutil/backoff_test.go less more
0 package timeutil
1
2 import (
3 "testing"
4 "time"
5 )
6
7 func TestExpBackoff(t *testing.T) {
8 tests := []struct {
9 prev time.Duration
10 max time.Duration
11 want time.Duration
12 }{
13 {
14 prev: time.Duration(0),
15 max: time.Minute,
16 want: time.Second,
17 },
18 {
19 prev: time.Second,
20 max: time.Minute,
21 want: 2 * time.Second,
22 },
23 {
24 prev: 16 * time.Second,
25 max: time.Minute,
26 want: 32 * time.Second,
27 },
28 {
29 prev: 32 * time.Second,
30 max: time.Minute,
31 want: time.Minute,
32 },
33 {
34 prev: time.Minute,
35 max: time.Minute,
36 want: time.Minute,
37 },
38 {
39 prev: 2 * time.Minute,
40 max: time.Minute,
41 want: time.Minute,
42 },
43 }
44
45 for i, tt := range tests {
46 got := ExpBackoff(tt.prev, tt.max)
47 if tt.want != got {
48 t.Errorf("case %d: want=%v got=%v", i, tt.want, got)
49 }
50 }
51 }
+0
-55
yamlutil/yaml.go less more
0 package yamlutil
1
2 import (
3 "flag"
4 "fmt"
5 "strings"
6
7 "gopkg.in/yaml.v1"
8 )
9
10 // SetFlagsFromYaml goes through all registered flags in the given flagset,
11 // and if they are not already set it attempts to set their values from
12 // the YAML config. It will use the key REPLACE(UPPERCASE(flagname), '-', '_')
13 func SetFlagsFromYaml(fs *flag.FlagSet, rawYaml []byte) (err error) {
14 conf := make(map[string]string)
15 if err = yaml.Unmarshal(rawYaml, conf); err != nil {
16 return
17 }
18 alreadySet := map[string]struct{}{}
19 fs.Visit(func(f *flag.Flag) {
20 alreadySet[f.Name] = struct{}{}
21 })
22
23 errs := make([]error, 0)
24 fs.VisitAll(func(f *flag.Flag) {
25 if f.Name == "" {
26 return
27 }
28 if _, ok := alreadySet[f.Name]; ok {
29 return
30 }
31 tag := strings.Replace(strings.ToUpper(f.Name), "-", "_", -1)
32 val, ok := conf[tag]
33 if !ok {
34 return
35 }
36 if serr := fs.Set(f.Name, val); serr != nil {
37 errs = append(errs, fmt.Errorf("invalid value %q for %s: %v", val, tag, serr))
38 }
39 })
40 if len(errs) != 0 {
41 err = ErrorSlice(errs)
42 }
43 return
44 }
45
46 type ErrorSlice []error
47
48 func (e ErrorSlice) Error() string {
49 s := ""
50 for _, err := range e {
51 s += ", " + err.Error()
52 }
53 return "Errors: " + s
54 }
+0
-80
yamlutil/yaml_test.go less more
0 package yamlutil
1
2 import (
3 "flag"
4 "testing"
5 )
6
7 func TestSetFlagsFromYaml(t *testing.T) {
8 config := "A: foo\nC: woof"
9 fs := flag.NewFlagSet("testing", flag.ExitOnError)
10 fs.String("a", "", "")
11 fs.String("b", "", "")
12 fs.String("c", "", "")
13 fs.Parse([]string{})
14
15 // flags should be settable using yaml vars
16 // and command-line flags
17 if err := fs.Set("b", "bar"); err != nil {
18 t.Fatal(err)
19 }
20 // command-line flags take precedence over the file
21 if err := fs.Set("c", "quack"); err != nil {
22 t.Fatal(err)
23 }
24
25 // first verify that flags are as expected before reading the file
26 for f, want := range map[string]string{
27 "a": "",
28 "b": "bar",
29 "c": "quack",
30 } {
31 if got := fs.Lookup(f).Value.String(); got != want {
32 t.Fatalf("flag %q=%q, want %q", f, got, want)
33 }
34 }
35
36 // now read the yaml and verify flags were updated as expected
37 err := SetFlagsFromYaml(fs, []byte(config))
38 if err != nil {
39 t.Errorf("err=%v, want nil", err)
40 }
41 for f, want := range map[string]string{
42 "a": "foo",
43 "b": "bar",
44 "c": "quack",
45 } {
46 if got := fs.Lookup(f).Value.String(); got != want {
47 t.Errorf("flag %q=%q, want %q", f, got, want)
48 }
49 }
50 }
51
52 func TestSetFlagsFromYamlBad(t *testing.T) {
53 // now verify that an error is propagated
54 fs := flag.NewFlagSet("testing", flag.ExitOnError)
55 fs.Int("x", 0, "")
56 badConf := "X: not_a_number"
57 if err := SetFlagsFromYaml(fs, []byte(badConf)); err == nil {
58 t.Errorf("got err=nil, flag x=%q, want err != nil", fs.Lookup("x").Value.String())
59 }
60 }
61
62 func TestSetFlagsFromYamlMultiError(t *testing.T) {
63 fs := flag.NewFlagSet("testing", flag.ExitOnError)
64 fs.Int("x", 0, "")
65 fs.Int("y", 0, "")
66 fs.Int("z", 0, "")
67 conf := "X: foo\nY: bar\nZ: 3"
68 err := SetFlagsFromYaml(fs, []byte(conf))
69 if err == nil {
70 t.Errorf("got err= nil, want err != nil")
71 }
72 es, ok := err.(ErrorSlice)
73 if !ok {
74 t.Errorf("Got ok=false want ok=true")
75 }
76 if len(es) != 2 {
77 t.Errorf("2 errors should be contained in the error, got %d errors", len(es))
78 }
79 }