mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #5305 from vmarmol/cadvisor-dep
Add HTTP cAdvisor dependencies.
This commit is contained in:
		
							
								
								
									
										77
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										77
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							@@ -54,6 +54,10 @@
 | 
			
		||||
			"Comment": "v0.6.2-10-g51fe59a",
 | 
			
		||||
			"Rev": "51fe59aca108dc5680109e7b2051cbdcfa5a253c"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/abbot/go-http-auth",
 | 
			
		||||
			"Rev": "c0ef4539dfab4d21c8ef20ba2924f9fc6f186d35"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/beorn7/perks/quantile",
 | 
			
		||||
			"Rev": "b965b613227fddccbfffe13eae360ed3fa822f8d"
 | 
			
		||||
@@ -179,60 +183,85 @@
 | 
			
		||||
			"ImportPath": "github.com/golang/protobuf/proto",
 | 
			
		||||
			"Rev": "7f07925444bb51fa4cf9dfe6f7661876f8852275"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/api",
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/client",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/container",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/events",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/fs",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/healthz",
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/http",
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/info/v1",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/info/v2",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/manager",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/pages",
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/storage",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/summary",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/utils",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/validate",
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/cadvisor/version",
 | 
			
		||||
			"Comment": "0.10.1-36-g62a1788",
 | 
			
		||||
			"Rev": "62a1788621f4adee2dbf08c26060ed7fb8c0297d"
 | 
			
		||||
			"Comment": "0.10.1-42-g4e2479b",
 | 
			
		||||
			"Rev": "4e2479bcabe7af08825066f5ece2122553562b34"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/google/gofuzz",
 | 
			
		||||
@@ -264,10 +293,6 @@
 | 
			
		||||
			"ImportPath": "github.com/mitchellh/goamz/ec2",
 | 
			
		||||
			"Rev": "703cfb45985762869e465f37ed030ff01615ff1e"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/mitchellh/goamz/elb",
 | 
			
		||||
			"Rev": "703cfb45985762869e465f37ed030ff01615ff1e"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/mitchellh/mapstructure",
 | 
			
		||||
			"Rev": "740c764bc6149d3f1806231418adb9f52c11bcbf"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
*~
 | 
			
		||||
*.a
 | 
			
		||||
*.6
 | 
			
		||||
*.out
 | 
			
		||||
_testmain.go
 | 
			
		||||
							
								
								
									
										178
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
 | 
			
		||||
                                 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:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) 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
 | 
			
		||||
 | 
			
		||||
      (d) 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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
include $(GOROOT)/src/Make.inc
 | 
			
		||||
 | 
			
		||||
TARG=auth_digest
 | 
			
		||||
GOFILES=\
 | 
			
		||||
	auth.go\
 | 
			
		||||
	digest.go\
 | 
			
		||||
	basic.go\
 | 
			
		||||
	misc.go\
 | 
			
		||||
	md5crypt.go\
 | 
			
		||||
	users.go\
 | 
			
		||||
 | 
			
		||||
include $(GOROOT)/src/Make.pkg
 | 
			
		||||
							
								
								
									
										70
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
HTTP Authentication implementation in Go
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
This is an implementation of HTTP Basic and HTTP Digest authentication
 | 
			
		||||
in Go language. It is designed as a simple wrapper for
 | 
			
		||||
http.RequestHandler functions.
 | 
			
		||||
 | 
			
		||||
Features
 | 
			
		||||
--------
 | 
			
		||||
 
 | 
			
		||||
 * Supports HTTP Basic and HTTP Digest authentication.
 | 
			
		||||
 * Supports htpasswd and htdigest formatted files.
 | 
			
		||||
 * Automatic reloading of password files.
 | 
			
		||||
 * Pluggable interface for user/password storage.
 | 
			
		||||
 * Supports MD5 and SHA1 for Basic authentication password storage.
 | 
			
		||||
 * Configurable Digest nonce cache size with expiration.
 | 
			
		||||
 * Wrapper for legacy http handlers (http.HandlerFunc interface)
 | 
			
		||||
 
 | 
			
		||||
Example usage
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
This is a complete working example for Basic auth:
 | 
			
		||||
 | 
			
		||||
    package main
 | 
			
		||||
 | 
			
		||||
    import (
 | 
			
		||||
            auth "github.com/abbot/go-http-auth"
 | 
			
		||||
            "fmt"
 | 
			
		||||
            "net/http"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    func Secret(user, realm string) string {
 | 
			
		||||
            if user == "john" {
 | 
			
		||||
                    // password is "hello"
 | 
			
		||||
                    return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
 | 
			
		||||
            }
 | 
			
		||||
            return ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
            fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func main() {
 | 
			
		||||
            authenticator := auth.NewBasicAuthenticator("example.com", Secret)
 | 
			
		||||
            http.HandleFunc("/", authenticator.Wrap(handle))
 | 
			
		||||
            http.ListenAndServe(":8080", nil)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
See more examples in the "examples" directory.
 | 
			
		||||
 | 
			
		||||
Legal
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
This module is developed under Apache 2.0 license, and can be used for
 | 
			
		||||
open and proprietary projects.
 | 
			
		||||
 | 
			
		||||
Copyright 2012-2013 Lev Shamardin
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License"); you
 | 
			
		||||
may not use this file or any other part of this project 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.
 | 
			
		||||
							
								
								
									
										48
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "net/http"
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 Request handlers must take AuthenticatedRequest instead of http.Request
 | 
			
		||||
*/
 | 
			
		||||
type AuthenticatedRequest struct {
 | 
			
		||||
	http.Request
 | 
			
		||||
	/* 
 | 
			
		||||
	 Authenticated user name. Current API implies that Username is
 | 
			
		||||
	 never empty, which means that authentication is always done
 | 
			
		||||
	 before calling the request handler.
 | 
			
		||||
	*/
 | 
			
		||||
	Username string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 AuthenticatedHandlerFunc is like http.HandlerFunc, but takes
 | 
			
		||||
 AuthenticatedRequest instead of http.Request
 | 
			
		||||
*/
 | 
			
		||||
type AuthenticatedHandlerFunc func(http.ResponseWriter, *AuthenticatedRequest)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Authenticator wraps an AuthenticatedHandlerFunc with
 | 
			
		||||
 authentication-checking code.
 | 
			
		||||
 | 
			
		||||
 Typical Authenticator usage is something like:
 | 
			
		||||
 | 
			
		||||
   authenticator := SomeAuthenticator(...)
 | 
			
		||||
   http.HandleFunc("/", authenticator(my_handler))
 | 
			
		||||
 | 
			
		||||
 Authenticator wrapper checks the user authentication and calls the
 | 
			
		||||
 wrapped function only after authentication has succeeded. Otherwise,
 | 
			
		||||
 it returns a handler which initiates the authentication procedure.
 | 
			
		||||
*/
 | 
			
		||||
type Authenticator func(AuthenticatedHandlerFunc) http.HandlerFunc
 | 
			
		||||
 | 
			
		||||
type AuthenticatorInterface interface {
 | 
			
		||||
	Wrap(AuthenticatedHandlerFunc) http.HandlerFunc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func JustCheck(auth AuthenticatorInterface, wrapped http.HandlerFunc) http.HandlerFunc {
 | 
			
		||||
	return auth.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
 | 
			
		||||
		ar.Header.Set("X-Authenticated-Username", ar.Username)
 | 
			
		||||
		wrapped(w, &ar.Request)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BasicAuth struct {
 | 
			
		||||
	Realm   string
 | 
			
		||||
	Secrets SecretProvider
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Checks the username/password combination from the request. Returns
 | 
			
		||||
 either an empty string (authentication failed) or the name of the
 | 
			
		||||
 authenticated user.
 | 
			
		||||
 | 
			
		||||
 Supports MD5 and SHA1 password entries
 | 
			
		||||
*/
 | 
			
		||||
func (a *BasicAuth) CheckAuth(r *http.Request) string {
 | 
			
		||||
	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
 | 
			
		||||
	if len(s) != 2 || s[0] != "Basic" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b, err := base64.StdEncoding.DecodeString(s[1])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	pair := strings.SplitN(string(b), ":", 2)
 | 
			
		||||
	if len(pair) != 2 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	passwd := a.Secrets(pair[0], a.Realm)
 | 
			
		||||
	if passwd == "" {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	if strings.HasPrefix(passwd, "{SHA}") {
 | 
			
		||||
		d := sha1.New()
 | 
			
		||||
		d.Write([]byte(pair[1]))
 | 
			
		||||
		if passwd[5:] != base64.StdEncoding.EncodeToString(d.Sum(nil)) {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		e := NewMD5Entry(passwd)
 | 
			
		||||
		if e == nil {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
		if passwd != string(MD5Crypt([]byte(pair[1]), e.Salt, e.Magic)) {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return pair[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 http.Handler for BasicAuth which initiates the authentication process
 | 
			
		||||
 (or requires reauthentication).
 | 
			
		||||
*/
 | 
			
		||||
func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	w.Header().Set("WWW-Authenticate", `Basic realm="`+a.Realm+`"`)
 | 
			
		||||
	w.WriteHeader(401)
 | 
			
		||||
	w.Write([]byte("401 Unauthorized\n"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 BasicAuthenticator returns a function, which wraps an
 | 
			
		||||
 AuthenticatedHandlerFunc converting it to http.HandlerFunc. This
 | 
			
		||||
 wrapper function checks the authentication and either sends back
 | 
			
		||||
 required authentication headers, or calls the wrapped function with
 | 
			
		||||
 authenticated username in the AuthenticatedRequest.
 | 
			
		||||
*/
 | 
			
		||||
func (a *BasicAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if username := a.CheckAuth(r); username == "" {
 | 
			
		||||
			a.RequireAuth(w, r)
 | 
			
		||||
		} else {
 | 
			
		||||
			ar := &AuthenticatedRequest{Request: *r, Username: username}
 | 
			
		||||
			wrapped(w, ar)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewBasicAuthenticator(realm string, secrets SecretProvider) *BasicAuth {
 | 
			
		||||
	return &BasicAuth{Realm: realm, Secrets: secrets}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/basic_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/basic_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAuthBasic(t *testing.T) {
 | 
			
		||||
	secrets := HtpasswdFileProvider("test.htpasswd")
 | 
			
		||||
	a := &BasicAuth{Realm: "example.com", Secrets: secrets}
 | 
			
		||||
	r := &http.Request{}
 | 
			
		||||
	r.Method = "GET"
 | 
			
		||||
	if a.CheckAuth(r) != "" {
 | 
			
		||||
		t.Fatal("CheckAuth passed on empty headers")
 | 
			
		||||
	}
 | 
			
		||||
	r.Header = http.Header(make(map[string][]string))
 | 
			
		||||
	r.Header.Set("Authorization", "Digest blabla ololo")
 | 
			
		||||
	if a.CheckAuth(r) != "" {
 | 
			
		||||
		t.Fatal("CheckAuth passed on bad headers")
 | 
			
		||||
	}
 | 
			
		||||
	r.Header.Set("Authorization", "Basic !@#")
 | 
			
		||||
	if a.CheckAuth(r) != "" {
 | 
			
		||||
		t.Fatal("CheckAuth passed on bad base64 data")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := [][]string{
 | 
			
		||||
		{"test", "hello"},
 | 
			
		||||
		{"test2", "hello2"},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range data {
 | 
			
		||||
		auth := base64.StdEncoding.EncodeToString([]byte(tc[0] + ":" + tc[1]))
 | 
			
		||||
		r.Header.Set("Authorization", "Basic "+auth)
 | 
			
		||||
		if a.CheckAuth(r) != tc[0] {
 | 
			
		||||
			t.Fatalf("CheckAuth failed for user '%s'", tc[0])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										226
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/digest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/digest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type digest_client struct {
 | 
			
		||||
	nc        uint64
 | 
			
		||||
	last_seen int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DigestAuth struct {
 | 
			
		||||
	Realm            string
 | 
			
		||||
	Opaque           string
 | 
			
		||||
	Secrets          SecretProvider
 | 
			
		||||
	PlainTextSecrets bool
 | 
			
		||||
 | 
			
		||||
	/* 
 | 
			
		||||
	 Approximate size of Client's Cache. When actual number of
 | 
			
		||||
	 tracked client nonces exceeds
 | 
			
		||||
	 ClientCacheSize+ClientCacheTolerance, ClientCacheTolerance*2
 | 
			
		||||
	 older entries are purged.
 | 
			
		||||
	*/
 | 
			
		||||
	ClientCacheSize      int
 | 
			
		||||
	ClientCacheTolerance int
 | 
			
		||||
 | 
			
		||||
	clients map[string]*digest_client
 | 
			
		||||
	mutex   sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type digest_cache_entry struct {
 | 
			
		||||
	nonce     string
 | 
			
		||||
	last_seen int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type digest_cache []digest_cache_entry
 | 
			
		||||
 | 
			
		||||
func (c digest_cache) Less(i, j int) bool {
 | 
			
		||||
	return c[i].last_seen < c[j].last_seen
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c digest_cache) Len() int {
 | 
			
		||||
	return len(c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c digest_cache) Swap(i, j int) {
 | 
			
		||||
	c[i], c[j] = c[j], c[i]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Remove count oldest entries from DigestAuth.clients
 | 
			
		||||
*/
 | 
			
		||||
func (a *DigestAuth) Purge(count int) {
 | 
			
		||||
	entries := make([]digest_cache_entry, 0, len(a.clients))
 | 
			
		||||
	for nonce, client := range a.clients {
 | 
			
		||||
		entries = append(entries, digest_cache_entry{nonce, client.last_seen})
 | 
			
		||||
	}
 | 
			
		||||
	cache := digest_cache(entries)
 | 
			
		||||
	sort.Sort(cache)
 | 
			
		||||
	for _, client := range cache[:count] {
 | 
			
		||||
		delete(a.clients, client.nonce)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 http.Handler for DigestAuth which initiates the authentication process
 | 
			
		||||
 (or requires reauthentication).
 | 
			
		||||
*/
 | 
			
		||||
func (a *DigestAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if len(a.clients) > a.ClientCacheSize+a.ClientCacheTolerance {
 | 
			
		||||
		a.Purge(a.ClientCacheTolerance * 2)
 | 
			
		||||
	}
 | 
			
		||||
	nonce := RandomKey()
 | 
			
		||||
	a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
 | 
			
		||||
	w.Header().Set("WWW-Authenticate",
 | 
			
		||||
		fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
 | 
			
		||||
			a.Realm, nonce, a.Opaque))
 | 
			
		||||
	w.WriteHeader(401)
 | 
			
		||||
	w.Write([]byte("401 Unauthorized\n"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Parse Authorization header from the http.Request. Returns a map of
 | 
			
		||||
 auth parameters or nil if the header is not a valid parsable Digest
 | 
			
		||||
 auth header.
 | 
			
		||||
*/
 | 
			
		||||
func DigestAuthParams(r *http.Request) map[string]string {
 | 
			
		||||
	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
 | 
			
		||||
	if len(s) != 2 || s[0] != "Digest" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := map[string]string{}
 | 
			
		||||
	for _, kv := range strings.Split(s[1], ",") {
 | 
			
		||||
		parts := strings.SplitN(kv, "=", 2)
 | 
			
		||||
		if len(parts) != 2 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		result[strings.Trim(parts[0], "\" ")] = strings.Trim(parts[1], "\" ")
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 Check if request contains valid authentication data. Returns a pair
 | 
			
		||||
 of username, authinfo where username is the name of the authenticated
 | 
			
		||||
 user or an empty string and authinfo is the contents for the optional
 | 
			
		||||
 Authentication-Info response header.
 | 
			
		||||
*/
 | 
			
		||||
func (da *DigestAuth) CheckAuth(r *http.Request) (username string, authinfo *string) {
 | 
			
		||||
	da.mutex.Lock()
 | 
			
		||||
	defer da.mutex.Unlock()
 | 
			
		||||
	username = ""
 | 
			
		||||
	authinfo = nil
 | 
			
		||||
	auth := DigestAuthParams(r)
 | 
			
		||||
	if auth == nil || da.Opaque != auth["opaque"] || auth["algorithm"] != "MD5" || auth["qop"] != "auth" {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the requested URI matches auth header
 | 
			
		||||
	switch u, err := url.Parse(auth["uri"]); {
 | 
			
		||||
	case err != nil:
 | 
			
		||||
		return
 | 
			
		||||
	case r.URL == nil:
 | 
			
		||||
		return
 | 
			
		||||
	case len(u.Path) > len(r.URL.Path):
 | 
			
		||||
		return
 | 
			
		||||
	case !strings.HasPrefix(r.URL.Path, u.Path):
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HA1 := da.Secrets(auth["username"], da.Realm)
 | 
			
		||||
	if da.PlainTextSecrets {
 | 
			
		||||
		HA1 = H(auth["username"] + ":" + da.Realm + ":" + HA1)
 | 
			
		||||
	}
 | 
			
		||||
	HA2 := H(r.Method + ":" + auth["uri"])
 | 
			
		||||
	KD := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], HA2}, ":"))
 | 
			
		||||
 | 
			
		||||
	if KD != auth["response"] {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// At this point crypto checks are completed and validated.
 | 
			
		||||
	// Now check if the session is valid.
 | 
			
		||||
 | 
			
		||||
	nc, err := strconv.ParseUint(auth["nc"], 16, 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if client, ok := da.clients[auth["nonce"]]; !ok {
 | 
			
		||||
		return
 | 
			
		||||
	} else {
 | 
			
		||||
		if client.nc != 0 && client.nc >= nc {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		client.nc = nc
 | 
			
		||||
		client.last_seen = time.Now().UnixNano()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp_HA2 := H(":" + auth["uri"])
 | 
			
		||||
	rspauth := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], resp_HA2}, ":"))
 | 
			
		||||
 | 
			
		||||
	info := fmt.Sprintf(`qop="auth", rspauth="%s", cnonce="%s", nc="%s"`, rspauth, auth["cnonce"], auth["nc"])
 | 
			
		||||
	return auth["username"], &info
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Default values for ClientCacheSize and ClientCacheTolerance for DigestAuth
 | 
			
		||||
*/
 | 
			
		||||
const DefaultClientCacheSize = 1000
 | 
			
		||||
const DefaultClientCacheTolerance = 100
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 Wrap returns an Authenticator which uses HTTP Digest
 | 
			
		||||
 authentication. Arguments:
 | 
			
		||||
 | 
			
		||||
 realm: The authentication realm.
 | 
			
		||||
 | 
			
		||||
 secrets: SecretProvider which must return HA1 digests for the same
 | 
			
		||||
 realm as above.
 | 
			
		||||
*/
 | 
			
		||||
func (a *DigestAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if username, authinfo := a.CheckAuth(r); username == "" {
 | 
			
		||||
			a.RequireAuth(w, r)
 | 
			
		||||
		} else {
 | 
			
		||||
			ar := &AuthenticatedRequest{Request: *r, Username: username}
 | 
			
		||||
			if authinfo != nil {
 | 
			
		||||
				w.Header().Set("Authentication-Info", *authinfo)
 | 
			
		||||
			}
 | 
			
		||||
			wrapped(w, ar)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 JustCheck returns function which converts an http.HandlerFunc into a
 | 
			
		||||
 http.HandlerFunc which requires authentication. Username is passed as
 | 
			
		||||
 an extra X-Authenticated-Username header.
 | 
			
		||||
*/
 | 
			
		||||
func (a *DigestAuth) JustCheck(wrapped http.HandlerFunc) http.HandlerFunc {
 | 
			
		||||
	return a.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
 | 
			
		||||
		ar.Header.Set("X-Authenticated-Username", ar.Username)
 | 
			
		||||
		wrapped(w, &ar.Request)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewDigestAuthenticator(realm string, secrets SecretProvider) *DigestAuth {
 | 
			
		||||
	da := &DigestAuth{
 | 
			
		||||
		Opaque:               RandomKey(),
 | 
			
		||||
		Realm:                realm,
 | 
			
		||||
		Secrets:              secrets,
 | 
			
		||||
		PlainTextSecrets:     false,
 | 
			
		||||
		ClientCacheSize:      DefaultClientCacheSize,
 | 
			
		||||
		ClientCacheTolerance: DefaultClientCacheTolerance,
 | 
			
		||||
		clients:              map[string]*digest_client{}}
 | 
			
		||||
	return da
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										57
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/digest_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/digest_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAuthDigest(t *testing.T) {
 | 
			
		||||
	secrets := HtdigestFileProvider("test.htdigest")
 | 
			
		||||
	da := &DigestAuth{Opaque: "U7H+ier3Ae8Skd/g",
 | 
			
		||||
		Realm:   "example.com",
 | 
			
		||||
		Secrets: secrets,
 | 
			
		||||
		clients: map[string]*digest_client{}}
 | 
			
		||||
	r := &http.Request{}
 | 
			
		||||
	r.Method = "GET"
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for empty request header")
 | 
			
		||||
	}
 | 
			
		||||
	r.Header = http.Header(make(map[string][]string))
 | 
			
		||||
	r.Header.Set("Authorization", "Digest blabla")
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for bad request header")
 | 
			
		||||
	}
 | 
			
		||||
	r.Header.Set("Authorization", `Digest username="test", realm="example.com", nonce="Vb9BP/h81n3GpTTB", uri="/t2", cnonce="NjE4MTM2", nc=00000001, qop="auth", response="ffc357c4eba74773c8687e0bc724c9a3", opaque="U7H+ier3Ae8Skd/g", algorithm="MD5"`)
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for unknown client")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.URL, _ = url.Parse("/t2")
 | 
			
		||||
	da.clients["Vb9BP/h81n3GpTTB"] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "test" {
 | 
			
		||||
		t.Fatal("empty auth for legitimate client")
 | 
			
		||||
	}
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for outdated nc")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.URL, _ = url.Parse("/")
 | 
			
		||||
	da.clients["Vb9BP/h81n3GpTTB"] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for bad request path")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.URL, _ = url.Parse("/t3")
 | 
			
		||||
	da.clients["Vb9BP/h81n3GpTTB"] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "" {
 | 
			
		||||
		t.Fatal("non-empty auth for bad request path")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	da.clients["+RbVXSbIoa1SaJk1"] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
 | 
			
		||||
	r.Header.Set("Authorization", `Digest username="test", realm="example.com", nonce="+RbVXSbIoa1SaJk1", uri="/", cnonce="NjE4NDkw", nc=00000001, qop="auth", response="c08918024d7faaabd5424654c4e3ad1c", opaque="U7H+ier3Ae8Skd/g", algorithm="MD5"`)
 | 
			
		||||
	if u, _ := da.CheckAuth(r); u != "test" {
 | 
			
		||||
		t.Fatal("empty auth for valid request in subpath")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/basic.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
// +build ignore
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Example application using Basic auth
 | 
			
		||||
 | 
			
		||||
 Build with:
 | 
			
		||||
 | 
			
		||||
 go build basic.go
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	auth ".."
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Secret(user, realm string) string {
 | 
			
		||||
	if user == "john" {
 | 
			
		||||
		// password is "hello"
 | 
			
		||||
		return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
	fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	authenticator := auth.NewBasicAuthenticator("example.com", Secret)
 | 
			
		||||
	http.HandleFunc("/", authenticator.Wrap(handle))
 | 
			
		||||
	http.ListenAndServe(":8080", nil)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/digest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/digest.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
// +build ignore
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Example application using Digest auth
 | 
			
		||||
 | 
			
		||||
 Build with:
 | 
			
		||||
 | 
			
		||||
 go build digest.go
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	auth ".."
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Secret(user, realm string) string {
 | 
			
		||||
	if user == "john" {
 | 
			
		||||
		// password is "hello"
 | 
			
		||||
		return "b98e16cbc3d01734b264adba7baa3bf9"
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
	fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	authenticator := auth.NewDigestAuthenticator("example.com", Secret)
 | 
			
		||||
	http.HandleFunc("/", authenticator.Wrap(handle))
 | 
			
		||||
	http.ListenAndServe(":8080", nil)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/wrapped.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/examples/wrapped.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
// +build ignore
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Example demonstrating how to wrap an application which is unaware of
 | 
			
		||||
 authenticated requests with a "pass-through" authentication
 | 
			
		||||
 | 
			
		||||
 Build with:
 | 
			
		||||
 | 
			
		||||
 go build wrapped.go
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	auth ".."
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Secret(user, realm string) string {
 | 
			
		||||
	if user == "john" {
 | 
			
		||||
		// password is "hello"
 | 
			
		||||
		return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func regular_handler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	fmt.Fprintf(w, "<html><body><h1>This application is unaware of authentication</h1></body></html>")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	authenticator := auth.NewBasicAuthenticator("example.com", Secret)
 | 
			
		||||
	http.HandleFunc("/", auth.JustCheck(authenticator, regular_handler))
 | 
			
		||||
	http.ListenAndServe(":8080", nil)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/md5crypt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/md5crypt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "crypto/md5"
 | 
			
		||||
import "strings"
 | 
			
		||||
 | 
			
		||||
const itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
 | 
			
		||||
 | 
			
		||||
var md5_crypt_swaps = [16]int{12, 6, 0, 13, 7, 1, 14, 8, 2, 15, 9, 3, 5, 10, 4, 11}
 | 
			
		||||
 | 
			
		||||
type MD5Entry struct {
 | 
			
		||||
	Magic, Salt, Hash []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMD5Entry(e string) *MD5Entry {
 | 
			
		||||
	parts := strings.SplitN(e, "$", 4)
 | 
			
		||||
	if len(parts) != 4 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return &MD5Entry{
 | 
			
		||||
		Magic: []byte("$" + parts[1] + "$"),
 | 
			
		||||
		Salt:  []byte(parts[2]),
 | 
			
		||||
		Hash:  []byte(parts[3]),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 MD5 password crypt implementation
 | 
			
		||||
*/
 | 
			
		||||
func MD5Crypt(password, salt, magic []byte) []byte {
 | 
			
		||||
	d := md5.New()
 | 
			
		||||
 | 
			
		||||
	d.Write(password)
 | 
			
		||||
	d.Write(magic)
 | 
			
		||||
	d.Write(salt)
 | 
			
		||||
 | 
			
		||||
	d2 := md5.New()
 | 
			
		||||
	d2.Write(password)
 | 
			
		||||
	d2.Write(salt)
 | 
			
		||||
	d2.Write(password)
 | 
			
		||||
 | 
			
		||||
	for i, mixin := 0, d2.Sum(nil); i < len(password); i++ {
 | 
			
		||||
		d.Write([]byte{mixin[i%16]})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := len(password); i != 0; i >>= 1 {
 | 
			
		||||
		if i&1 == 0 {
 | 
			
		||||
			d.Write([]byte{password[0]})
 | 
			
		||||
		} else {
 | 
			
		||||
			d.Write([]byte{0})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	final := d.Sum(nil)
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < 1000; i++ {
 | 
			
		||||
		d2 := md5.New()
 | 
			
		||||
		if i&1 == 0 {
 | 
			
		||||
			d2.Write(final)
 | 
			
		||||
		} else {
 | 
			
		||||
			d2.Write(password)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i%3 != 0 {
 | 
			
		||||
			d2.Write(salt)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i%7 != 0 {
 | 
			
		||||
			d2.Write(password)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if i&1 == 0 {
 | 
			
		||||
			d2.Write(password)
 | 
			
		||||
		} else {
 | 
			
		||||
			d2.Write(final)
 | 
			
		||||
		}
 | 
			
		||||
		final = d2.Sum(nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := make([]byte, 0, 22)
 | 
			
		||||
	v := uint(0)
 | 
			
		||||
	bits := uint(0)
 | 
			
		||||
	for _, i := range md5_crypt_swaps {
 | 
			
		||||
		v |= (uint(final[i]) << bits)
 | 
			
		||||
		for bits = bits + 8; bits > 6; bits -= 6 {
 | 
			
		||||
			result = append(result, itoa64[v&0x3f])
 | 
			
		||||
			v >>= 6
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result = append(result, itoa64[v&0x3f])
 | 
			
		||||
 | 
			
		||||
	return append(append(append(magic, salt...), '$'), result...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/md5crypt_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/md5crypt_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "testing"
 | 
			
		||||
 | 
			
		||||
func Test_MD5Crypt(t *testing.T) {
 | 
			
		||||
	test_cases := [][]string{
 | 
			
		||||
		{"apache", "$apr1$J.w5a/..$IW9y6DR0oO/ADuhlMF5/X1"},
 | 
			
		||||
		{"pass", "$1$YeNsbWdH$wvOF8JdqsoiLix754LTW90"},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range test_cases {
 | 
			
		||||
		e := NewMD5Entry(tc[1])
 | 
			
		||||
		result := MD5Crypt([]byte(tc[0]), e.Salt, e.Magic)
 | 
			
		||||
		if string(result) != tc[1] {
 | 
			
		||||
			t.Fatalf("MD5Crypt returned '%s' instead of '%s'", string(result), tc[1])
 | 
			
		||||
		}
 | 
			
		||||
		t.Logf("MD5Crypt: '%s' (%s%s$) -> %s", tc[0], e.Magic, e.Salt, result)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/misc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/misc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "encoding/base64"
 | 
			
		||||
import "crypto/md5"
 | 
			
		||||
import "crypto/rand"
 | 
			
		||||
import "fmt"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Return a random 16-byte base64 alphabet string
 | 
			
		||||
*/
 | 
			
		||||
func RandomKey() string {
 | 
			
		||||
	k := make([]byte, 12)
 | 
			
		||||
	for bytes := 0; bytes < len(k); {
 | 
			
		||||
		n, err := rand.Read(k[bytes:])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic("rand.Read() failed")
 | 
			
		||||
		}
 | 
			
		||||
		bytes += n
 | 
			
		||||
	}
 | 
			
		||||
	return base64.StdEncoding.EncodeToString(k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 H function for MD5 algorithm (returns a lower-case hex MD5 digest)
 | 
			
		||||
*/
 | 
			
		||||
func H(data string) string {
 | 
			
		||||
	digest := md5.New()
 | 
			
		||||
	digest.Write([]byte(data))
 | 
			
		||||
	return fmt.Sprintf("%x", digest.Sum(nil))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/misc_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/misc_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "testing"
 | 
			
		||||
 | 
			
		||||
func TestH(t *testing.T) {
 | 
			
		||||
	const hello = "Hello, world!"
 | 
			
		||||
	const hello_md5 = "6cd3556deb0da54bca060b4c39479839"
 | 
			
		||||
	h := H(hello)
 | 
			
		||||
	if h != hello_md5 {
 | 
			
		||||
		t.Fatal("Incorrect digest for test string:", h, "instead of", hello_md5)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/test.htdigest
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/test.htdigest
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
test:example.com:aa78524fceb0e50fd8ca96dd818b8cf9
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/test.htpasswd
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/test.htpasswd
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
test:{SHA}qvTGHdzF6KLavt4PO0gs2a6pQ00=
 | 
			
		||||
test2:$apr1$a0j62R97$mYqFkloXH0/UOaUnAiV2b0
 | 
			
		||||
							
								
								
									
										136
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/users.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/users.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import "encoding/csv"
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 SecretProvider is used by authenticators. Takes user name and realm
 | 
			
		||||
 as an argument, returns secret required for authentication (HA1 for
 | 
			
		||||
 digest authentication, properly encrypted password for basic).
 | 
			
		||||
*/
 | 
			
		||||
type SecretProvider func(user, realm string) string
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Common functions for file auto-reloading
 | 
			
		||||
*/
 | 
			
		||||
type File struct {
 | 
			
		||||
	Path string
 | 
			
		||||
	Info os.FileInfo
 | 
			
		||||
	/* must be set in inherited types during initialization */
 | 
			
		||||
	Reload func()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *File) ReloadIfNeeded() {
 | 
			
		||||
	info, err := os.Stat(f.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	if f.Info == nil || f.Info.ModTime() != info.ModTime() {
 | 
			
		||||
		f.Info = info
 | 
			
		||||
		f.Reload()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Structure used for htdigest file authentication. Users map realms to
 | 
			
		||||
 maps of users to their HA1 digests.
 | 
			
		||||
*/
 | 
			
		||||
type HtdigestFile struct {
 | 
			
		||||
	File
 | 
			
		||||
	Users map[string]map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reload_htdigest(hf *HtdigestFile) {
 | 
			
		||||
	r, err := os.Open(hf.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	csv_reader := csv.NewReader(r)
 | 
			
		||||
	csv_reader.Comma = ':'
 | 
			
		||||
	csv_reader.Comment = '#'
 | 
			
		||||
	csv_reader.TrimLeadingSpace = true
 | 
			
		||||
 | 
			
		||||
	records, err := csv_reader.ReadAll()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hf.Users = make(map[string]map[string]string)
 | 
			
		||||
	for _, record := range records {
 | 
			
		||||
		_, exists := hf.Users[record[1]]
 | 
			
		||||
		if !exists {
 | 
			
		||||
			hf.Users[record[1]] = make(map[string]string)
 | 
			
		||||
		}
 | 
			
		||||
		hf.Users[record[1]][record[0]] = record[2]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 SecretProvider implementation based on htdigest-formated files. Will
 | 
			
		||||
 reload htdigest file on changes. Will panic on syntax errors in
 | 
			
		||||
 htdigest files.
 | 
			
		||||
*/
 | 
			
		||||
func HtdigestFileProvider(filename string) SecretProvider {
 | 
			
		||||
	hf := &HtdigestFile{File: File{Path: filename}}
 | 
			
		||||
	hf.Reload = func() { reload_htdigest(hf) }
 | 
			
		||||
	return func(user, realm string) string {
 | 
			
		||||
		hf.ReloadIfNeeded()
 | 
			
		||||
		_, exists := hf.Users[realm]
 | 
			
		||||
		if !exists {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
		digest, exists := hf.Users[realm][user]
 | 
			
		||||
		if !exists {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
		return digest
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 Structure used for htdigest file authentication. Users map users to
 | 
			
		||||
 their salted encrypted password
 | 
			
		||||
*/
 | 
			
		||||
type HtpasswdFile struct {
 | 
			
		||||
	File
 | 
			
		||||
	Users map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reload_htpasswd(h *HtpasswdFile) {
 | 
			
		||||
	r, err := os.Open(h.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	csv_reader := csv.NewReader(r)
 | 
			
		||||
	csv_reader.Comma = ':'
 | 
			
		||||
	csv_reader.Comment = '#'
 | 
			
		||||
	csv_reader.TrimLeadingSpace = true
 | 
			
		||||
 | 
			
		||||
	records, err := csv_reader.ReadAll()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h.Users = make(map[string]string)
 | 
			
		||||
	for _, record := range records {
 | 
			
		||||
		h.Users[record[0]] = record[1]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 SecretProvider implementation based on htpasswd-formated files. Will
 | 
			
		||||
 reload htpasswd file on changes. Will panic on syntax errors in
 | 
			
		||||
 htpasswd files. Realm argument of the SecretProvider is ignored.
 | 
			
		||||
*/
 | 
			
		||||
func HtpasswdFileProvider(filename string) SecretProvider {
 | 
			
		||||
	h := &HtpasswdFile{File: File{Path: filename}}
 | 
			
		||||
	h.Reload = func() { reload_htpasswd(h) }
 | 
			
		||||
	return func(user, realm string) string {
 | 
			
		||||
		h.ReloadIfNeeded()
 | 
			
		||||
		password, exists := h.Users[user]
 | 
			
		||||
		if !exists {
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
		return password
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/users_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Godeps/_workspace/src/github.com/abbot/go-http-auth/users_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestHtdigestFile(t *testing.T) {
 | 
			
		||||
	secrets := HtdigestFileProvider("test.htdigest")
 | 
			
		||||
	digest := secrets("test", "example.com")
 | 
			
		||||
	if digest != "aa78524fceb0e50fd8ca96dd818b8cf9" {
 | 
			
		||||
		t.Fatal("Incorrect digest for test user:", digest)
 | 
			
		||||
	}
 | 
			
		||||
	digest = secrets("test", "example1.com")
 | 
			
		||||
	if digest != "" {
 | 
			
		||||
		t.Fatal("Got digest for user in non-existant realm:", digest)
 | 
			
		||||
	}
 | 
			
		||||
	digest = secrets("test1", "example.com")
 | 
			
		||||
	if digest != "" {
 | 
			
		||||
		t.Fatal("Got digest for non-existant user:", digest)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHtpasswdFile(t *testing.T) {
 | 
			
		||||
	secrets := HtpasswdFileProvider("test.htpasswd")
 | 
			
		||||
	passwd := secrets("test", "blah")
 | 
			
		||||
	if passwd != "{SHA}qvTGHdzF6KLavt4PO0gs2a6pQ00=" {
 | 
			
		||||
		t.Fatal("Incorrect passwd for test user:", passwd)
 | 
			
		||||
	}
 | 
			
		||||
	passwd = secrets("test3", "blah")
 | 
			
		||||
	if passwd != "" {
 | 
			
		||||
		t.Fatal("Got passwd for non-existant user:", passwd)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										251
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 api provides a handler for /api/
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/google/cadvisor/events"
 | 
			
		||||
	httpMux "github.com/google/cadvisor/http/mux"
 | 
			
		||||
	info "github.com/google/cadvisor/info/v1"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	apiResource = "/api/"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func RegisterHandlers(mux httpMux.Mux, m manager.Manager) error {
 | 
			
		||||
	apiVersions := getApiVersions()
 | 
			
		||||
	supportedApiVersions := make(map[string]ApiVersion, len(apiVersions))
 | 
			
		||||
	for _, v := range apiVersions {
 | 
			
		||||
		supportedApiVersions[v.Version()] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mux.HandleFunc(apiResource, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := handleRequest(supportedApiVersions, m, w, r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, err.Error(), 500)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Captures the API version, requestType [optional], and remaining request [optional].
 | 
			
		||||
var apiRegexp = regexp.MustCompile("/api/([^/]+)/?([^/]+)?(.*)")
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	apiVersion = iota + 1
 | 
			
		||||
	apiRequestType
 | 
			
		||||
	apiRequestArgs
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func handleRequest(supportedApiVersions map[string]ApiVersion, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	start := time.Now()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		glog.V(2).Infof("Request took %s", time.Since(start))
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	request := r.URL.Path
 | 
			
		||||
 | 
			
		||||
	const apiPrefix = "/api"
 | 
			
		||||
	if !strings.HasPrefix(request, apiPrefix) {
 | 
			
		||||
		return fmt.Errorf("incomplete API request %q", request)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the request doesn't have an API version, list those.
 | 
			
		||||
	if request == apiPrefix || request == apiResource {
 | 
			
		||||
		versions := make([]string, 0, len(supportedApiVersions))
 | 
			
		||||
		for v := range supportedApiVersions {
 | 
			
		||||
			versions = append(versions, v)
 | 
			
		||||
		}
 | 
			
		||||
		sort.Strings(versions)
 | 
			
		||||
		fmt.Fprintf(w, "Supported API versions: %s", strings.Join(versions, ","))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Verify that we have all the elements we expect:
 | 
			
		||||
	// /<version>/<request type>[/<args...>]
 | 
			
		||||
	requestElements := apiRegexp.FindStringSubmatch(request)
 | 
			
		||||
	if len(requestElements) == 0 {
 | 
			
		||||
		return fmt.Errorf("malformed request %q", request)
 | 
			
		||||
	}
 | 
			
		||||
	version := requestElements[apiVersion]
 | 
			
		||||
	requestType := requestElements[apiRequestType]
 | 
			
		||||
	requestArgs := strings.Split(requestElements[apiRequestArgs], "/")
 | 
			
		||||
 | 
			
		||||
	// Check supported versions.
 | 
			
		||||
	versionHandler, ok := supportedApiVersions[version]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("unsupported API version %q", version)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If no request type, list possible request types.
 | 
			
		||||
	if requestType == "" {
 | 
			
		||||
		requestTypes := versionHandler.SupportedRequestTypes()
 | 
			
		||||
		sort.Strings(requestTypes)
 | 
			
		||||
		fmt.Fprintf(w, "Supported request types: %q", strings.Join(requestTypes, ","))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Trim the first empty element from the request.
 | 
			
		||||
	if len(requestArgs) > 0 && requestArgs[0] == "" {
 | 
			
		||||
		requestArgs = requestArgs[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return versionHandler.HandleRequest(requestType, requestArgs, m, w, r)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeResult(res interface{}, w http.ResponseWriter) error {
 | 
			
		||||
	out, err := json.Marshal(res)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to marshall response %+v with error: %s", res, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.Header().Set("Content-Type", "application/json")
 | 
			
		||||
	w.Write(out)
 | 
			
		||||
	return nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func streamResults(results chan *events.Event, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	cn, ok := w.(http.CloseNotifier)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("could not access http.CloseNotifier")
 | 
			
		||||
	}
 | 
			
		||||
	flusher, ok := w.(http.Flusher)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("could not access http.Flusher")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.Header().Set("Transfer-Encoding", "chunked")
 | 
			
		||||
	w.WriteHeader(http.StatusOK)
 | 
			
		||||
	flusher.Flush()
 | 
			
		||||
 | 
			
		||||
	enc := json.NewEncoder(w)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-cn.CloseNotify():
 | 
			
		||||
			glog.Infof("Client stopped listening")
 | 
			
		||||
			return nil
 | 
			
		||||
		case ev := <-results:
 | 
			
		||||
			err := enc.Encode(ev)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				glog.Errorf("error encoding message %+v for result stream: %v", ev, err)
 | 
			
		||||
			}
 | 
			
		||||
			flusher.Flush()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getContainerInfoRequest(body io.ReadCloser) (*info.ContainerInfoRequest, error) {
 | 
			
		||||
	var query info.ContainerInfoRequest
 | 
			
		||||
 | 
			
		||||
	// Default stats and samples is 64.
 | 
			
		||||
	query.NumStats = 64
 | 
			
		||||
 | 
			
		||||
	decoder := json.NewDecoder(body)
 | 
			
		||||
	err := decoder.Decode(&query)
 | 
			
		||||
	if err != nil && err != io.EOF {
 | 
			
		||||
		return nil, fmt.Errorf("unable to decode the json value: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &query, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The user can set any or none of the following arguments in any order
 | 
			
		||||
// with any twice defined arguments being assigned the first value.
 | 
			
		||||
// If the value type for the argument is wrong the field will be assumed to be
 | 
			
		||||
// unassigned
 | 
			
		||||
// bools: historical, subcontainers, oom_events, creation_events, deletion_events
 | 
			
		||||
// ints: max_events, start_time (unix timestamp), end_time (unix timestamp)
 | 
			
		||||
// example r.URL: http://localhost:8080/api/v1.3/events?oom_events=true&historical=true&max_events=10
 | 
			
		||||
func getEventRequest(r *http.Request) (*events.Request, bool, error) {
 | 
			
		||||
	query := events.NewRequest()
 | 
			
		||||
	getHistoricalEvents := false
 | 
			
		||||
 | 
			
		||||
	urlMap := r.URL.Query()
 | 
			
		||||
 | 
			
		||||
	if val, ok := urlMap["historical"]; ok {
 | 
			
		||||
		newBool, err := strconv.ParseBool(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			getHistoricalEvents = newBool
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["subcontainers"]; ok {
 | 
			
		||||
		newBool, err := strconv.ParseBool(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.IncludeSubcontainers = newBool
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["oom_events"]; ok {
 | 
			
		||||
		newBool, err := strconv.ParseBool(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.EventType[events.TypeOom] = newBool
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["creation_events"]; ok {
 | 
			
		||||
		newBool, err := strconv.ParseBool(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.EventType[events.TypeContainerCreation] = newBool
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["deletion_events"]; ok {
 | 
			
		||||
		newBool, err := strconv.ParseBool(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.EventType[events.TypeContainerDeletion] = newBool
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["max_events"]; ok {
 | 
			
		||||
		newInt, err := strconv.Atoi(val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.MaxEventsReturned = int(newInt)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["start_time"]; ok {
 | 
			
		||||
		newTime, err := time.Parse(time.RFC3339, val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.StartTime = newTime
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if val, ok := urlMap["end_time"]; ok {
 | 
			
		||||
		newTime, err := time.Parse(time.RFC3339, val[0])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			query.EndTime = newTime
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glog.V(2).Infof(
 | 
			
		||||
		"%v was returned in api/handler.go:getEventRequest from the url rawQuery %v",
 | 
			
		||||
		query, r.URL.RawQuery)
 | 
			
		||||
	return query, getHistoricalEvents, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getContainerName(request []string) string {
 | 
			
		||||
	return path.Join("/", strings.Join(request, "/"))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										348
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/versions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/versions.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,348 @@
 | 
			
		||||
// Copyright 2015 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/google/cadvisor/events"
 | 
			
		||||
	info "github.com/google/cadvisor/info/v1"
 | 
			
		||||
	"github.com/google/cadvisor/info/v2"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	containersApi    = "containers"
 | 
			
		||||
	subcontainersApi = "subcontainers"
 | 
			
		||||
	machineApi       = "machine"
 | 
			
		||||
	dockerApi        = "docker"
 | 
			
		||||
	summaryApi       = "summary"
 | 
			
		||||
	specApi          = "spec"
 | 
			
		||||
	eventsApi        = "events"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Interface for a cAdvisor API version
 | 
			
		||||
type ApiVersion interface {
 | 
			
		||||
	// Returns the version string.
 | 
			
		||||
	Version() string
 | 
			
		||||
 | 
			
		||||
	// List of supported API endpoints.
 | 
			
		||||
	SupportedRequestTypes() []string
 | 
			
		||||
 | 
			
		||||
	// Handles a request. The second argument is the parameters after /api/<version>/<endpoint>
 | 
			
		||||
	HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Gets all supported API versions.
 | 
			
		||||
func getApiVersions() []ApiVersion {
 | 
			
		||||
	v1_0 := &version1_0{}
 | 
			
		||||
	v1_1 := newVersion1_1(v1_0)
 | 
			
		||||
	v1_2 := newVersion1_2(v1_1)
 | 
			
		||||
	v1_3 := newVersion1_3(v1_2)
 | 
			
		||||
	v2_0 := newVersion2_0(v1_3)
 | 
			
		||||
 | 
			
		||||
	return []ApiVersion{v1_0, v1_1, v1_2, v1_3, v2_0}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// API v1.0
 | 
			
		||||
 | 
			
		||||
type version1_0 struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_0) Version() string {
 | 
			
		||||
	return "v1.0"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_0) SupportedRequestTypes() []string {
 | 
			
		||||
	return []string{containersApi, machineApi}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	switch requestType {
 | 
			
		||||
	case machineApi:
 | 
			
		||||
		glog.V(2).Infof("Api - Machine")
 | 
			
		||||
 | 
			
		||||
		// Get the MachineInfo
 | 
			
		||||
		machineInfo, err := m.GetMachineInfo()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = writeResult(machineInfo, w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case containersApi:
 | 
			
		||||
		containerName := getContainerName(request)
 | 
			
		||||
		glog.V(2).Infof("Api - Container(%s)", containerName)
 | 
			
		||||
 | 
			
		||||
		// Get the query request.
 | 
			
		||||
		query, err := getContainerInfoRequest(r.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Get the container.
 | 
			
		||||
		cont, err := m.GetContainerInfo(containerName, query)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to get container %q with error: %s", containerName, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Only output the container as JSON.
 | 
			
		||||
		err = writeResult(cont, w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("unknown request type %q", requestType)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// API v1.1
 | 
			
		||||
 | 
			
		||||
type version1_1 struct {
 | 
			
		||||
	baseVersion *version1_0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v1.1 builds on v1.0.
 | 
			
		||||
func newVersion1_1(v *version1_0) *version1_1 {
 | 
			
		||||
	return &version1_1{
 | 
			
		||||
		baseVersion: v,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_1) Version() string {
 | 
			
		||||
	return "v1.1"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_1) SupportedRequestTypes() []string {
 | 
			
		||||
	return append(self.baseVersion.SupportedRequestTypes(), subcontainersApi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_1) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	switch requestType {
 | 
			
		||||
	case subcontainersApi:
 | 
			
		||||
		containerName := getContainerName(request)
 | 
			
		||||
		glog.V(2).Infof("Api - Subcontainers(%s)", containerName)
 | 
			
		||||
 | 
			
		||||
		// Get the query request.
 | 
			
		||||
		query, err := getContainerInfoRequest(r.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Get the subcontainers.
 | 
			
		||||
		containers, err := m.SubcontainersInfo(containerName, query)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to get subcontainers for container %q with error: %s", containerName, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Only output the containers as JSON.
 | 
			
		||||
		err = writeResult(containers, w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	default:
 | 
			
		||||
		return self.baseVersion.HandleRequest(requestType, request, m, w, r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// API v1.2
 | 
			
		||||
 | 
			
		||||
type version1_2 struct {
 | 
			
		||||
	baseVersion *version1_1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v1.2 builds on v1.1.
 | 
			
		||||
func newVersion1_2(v *version1_1) *version1_2 {
 | 
			
		||||
	return &version1_2{
 | 
			
		||||
		baseVersion: v,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_2) Version() string {
 | 
			
		||||
	return "v1.2"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_2) SupportedRequestTypes() []string {
 | 
			
		||||
	return append(self.baseVersion.SupportedRequestTypes(), dockerApi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_2) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	switch requestType {
 | 
			
		||||
	case dockerApi:
 | 
			
		||||
		glog.V(2).Infof("Api - Docker(%v)", request)
 | 
			
		||||
 | 
			
		||||
		// Get the query request.
 | 
			
		||||
		query, err := getContainerInfoRequest(r.Body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var containers map[string]info.ContainerInfo
 | 
			
		||||
		// map requests for "docker/" to "docker"
 | 
			
		||||
		if len(request) == 1 && len(request[0]) == 0 {
 | 
			
		||||
			request = request[:0]
 | 
			
		||||
		}
 | 
			
		||||
		switch len(request) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			// Get all Docker containers.
 | 
			
		||||
			containers, err = m.AllDockerContainers(query)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("failed to get all Docker containers with error: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		case 1:
 | 
			
		||||
			// Get one Docker container.
 | 
			
		||||
			var cont info.ContainerInfo
 | 
			
		||||
			cont, err = m.DockerContainer(request[0], query)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("failed to get Docker container %q with error: %v", request[0], err)
 | 
			
		||||
			}
 | 
			
		||||
			containers = map[string]info.ContainerInfo{
 | 
			
		||||
				cont.Name: cont,
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("unknown request for Docker container %v", request)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Only output the containers as JSON.
 | 
			
		||||
		err = writeResult(containers, w)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	default:
 | 
			
		||||
		return self.baseVersion.HandleRequest(requestType, request, m, w, r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// API v1.3
 | 
			
		||||
 | 
			
		||||
type version1_3 struct {
 | 
			
		||||
	baseVersion *version1_2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v1.3 builds on v1.2.
 | 
			
		||||
func newVersion1_3(v *version1_2) *version1_3 {
 | 
			
		||||
	return &version1_3{
 | 
			
		||||
		baseVersion: v,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_3) Version() string {
 | 
			
		||||
	return "v1.3"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_3) SupportedRequestTypes() []string {
 | 
			
		||||
	return append(self.baseVersion.SupportedRequestTypes(), eventsApi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version1_3) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	switch requestType {
 | 
			
		||||
	case eventsApi:
 | 
			
		||||
		query, eventsFromAllTime, err := getEventRequest(r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		glog.V(2).Infof("Api - Events(%v)", query)
 | 
			
		||||
		if eventsFromAllTime {
 | 
			
		||||
			pastEvents, err := m.GetPastEvents(query)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			return writeResult(pastEvents, w)
 | 
			
		||||
		}
 | 
			
		||||
		eventsChannel := make(chan *events.Event, 10)
 | 
			
		||||
		err = m.WatchForEvents(query, eventsChannel)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return streamResults(eventsChannel, w, r)
 | 
			
		||||
	default:
 | 
			
		||||
		return self.baseVersion.HandleRequest(requestType, request, m, w, r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// API v2.0
 | 
			
		||||
 | 
			
		||||
// v2.0 builds on v1.3
 | 
			
		||||
type version2_0 struct {
 | 
			
		||||
	baseVersion *version1_3
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newVersion2_0(v *version1_3) *version2_0 {
 | 
			
		||||
	return &version2_0{
 | 
			
		||||
		baseVersion: v,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version2_0) Version() string {
 | 
			
		||||
	return "v2.0"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version2_0) SupportedRequestTypes() []string {
 | 
			
		||||
	return append(self.baseVersion.SupportedRequestTypes(), summaryApi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	switch requestType {
 | 
			
		||||
	case summaryApi:
 | 
			
		||||
		containerName := getContainerName(request)
 | 
			
		||||
		glog.V(2).Infof("Api - Summary(%v)", containerName)
 | 
			
		||||
 | 
			
		||||
		stats, err := m.GetContainerDerivedStats(containerName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return writeResult(stats, w)
 | 
			
		||||
	case specApi:
 | 
			
		||||
		containerName := getContainerName(request)
 | 
			
		||||
		glog.V(2).Infof("Api - Spec(%v)", containerName)
 | 
			
		||||
		spec, err := m.GetContainerSpec(containerName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		specV2 := convertSpec(spec)
 | 
			
		||||
		return writeResult(specV2, w)
 | 
			
		||||
	default:
 | 
			
		||||
		return self.baseVersion.HandleRequest(requestType, request, m, w, r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert container spec from v1 to v2.
 | 
			
		||||
func convertSpec(specV1 info.ContainerSpec) v2.ContainerSpec {
 | 
			
		||||
	specV2 := v2.ContainerSpec{
 | 
			
		||||
		CreationTime: specV1.CreationTime,
 | 
			
		||||
		HasCpu:       specV1.HasCpu,
 | 
			
		||||
		HasMemory:    specV1.HasMemory,
 | 
			
		||||
	}
 | 
			
		||||
	if specV1.HasCpu {
 | 
			
		||||
		specV2.Cpu.Limit = specV1.Cpu.Limit
 | 
			
		||||
		specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit
 | 
			
		||||
		specV2.Cpu.Mask = specV1.Cpu.Mask
 | 
			
		||||
	}
 | 
			
		||||
	if specV1.HasMemory {
 | 
			
		||||
		specV2.Memory.Limit = specV1.Memory.Limit
 | 
			
		||||
		specV2.Memory.Reservation = specV1.Memory.Reservation
 | 
			
		||||
		specV2.Memory.SwapLimit = specV1.Memory.SwapLimit
 | 
			
		||||
	}
 | 
			
		||||
	return specV2
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/versions_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/api/versions_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
// Copyright 2015 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/cadvisor/events"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// returns an http.Request pointer for an input url test string
 | 
			
		||||
func makeHTTPRequest(requestURL string, t *testing.T) *http.Request {
 | 
			
		||||
	dummyReader, _ := io.Pipe()
 | 
			
		||||
	r, err := http.NewRequest("GET", requestURL, dummyReader)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetEventRequestBasicRequest(t *testing.T) {
 | 
			
		||||
	r := makeHTTPRequest("http://localhost:8080/api/v1.3/events?oom_events=true&historical=true&max_events=10", t)
 | 
			
		||||
	expectedQuery := &events.Request{
 | 
			
		||||
		EventType: map[events.EventType]bool{
 | 
			
		||||
			events.TypeOom: true,
 | 
			
		||||
		},
 | 
			
		||||
		MaxEventsReturned: 10,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	receivedQuery, getHistoricalEvents, err := getEventRequest(r)
 | 
			
		||||
 | 
			
		||||
	if !reflect.DeepEqual(expectedQuery, receivedQuery) {
 | 
			
		||||
		t.Errorf("expected %v but received %v", expectedQuery, receivedQuery)
 | 
			
		||||
	}
 | 
			
		||||
	assert.True(t, getHistoricalEvents)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetEventEmptyRequest(t *testing.T) {
 | 
			
		||||
	r := makeHTTPRequest("", t)
 | 
			
		||||
	expectedQuery := events.NewRequest()
 | 
			
		||||
 | 
			
		||||
	receivedQuery, getHistoricalEvents, err := getEventRequest(r)
 | 
			
		||||
 | 
			
		||||
	if !reflect.DeepEqual(expectedQuery, receivedQuery) {
 | 
			
		||||
		t.Errorf("expected %v but received %v", expectedQuery, receivedQuery)
 | 
			
		||||
	}
 | 
			
		||||
	assert.False(t, getHistoricalEvents)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetEventRequestDoubleArgument(t *testing.T) {
 | 
			
		||||
	r := makeHTTPRequest("http://localhost:8080/api/v1.3/events?historical=true&oom_events=true&oom_events=false", t)
 | 
			
		||||
	expectedQuery := &events.Request{
 | 
			
		||||
		EventType: map[events.EventType]bool{
 | 
			
		||||
			events.TypeOom: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	receivedQuery, getHistoricalEvents, err := getEventRequest(r)
 | 
			
		||||
 | 
			
		||||
	if !reflect.DeepEqual(expectedQuery, receivedQuery) {
 | 
			
		||||
		t.Errorf("expected %v but received %v", expectedQuery, receivedQuery)
 | 
			
		||||
	}
 | 
			
		||||
	assert.True(t, getHistoricalEvents)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/healthz/healthz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/healthz/healthz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 healthz
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	httpMux "github.com/google/cadvisor/http/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func handleHealthz(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	w.WriteHeader(http.StatusOK)
 | 
			
		||||
	w.Write([]byte("ok"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Register simple HTTP /healthz handler to return "ok".
 | 
			
		||||
func RegisterHandler(mux httpMux.Mux) error {
 | 
			
		||||
	mux.HandleFunc("/healthz", handleHealthz)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/http/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/http/handlers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
// Copyright 2015 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 http
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	auth "github.com/abbot/go-http-auth"
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/google/cadvisor/api"
 | 
			
		||||
	"github.com/google/cadvisor/healthz"
 | 
			
		||||
	httpMux "github.com/google/cadvisor/http/mux"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
	"github.com/google/cadvisor/pages"
 | 
			
		||||
	"github.com/google/cadvisor/pages/static"
 | 
			
		||||
	"github.com/google/cadvisor/validate"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func RegisterHandlers(mux httpMux.Mux, containerManager manager.Manager, httpAuthFile, httpAuthRealm, httpDigestFile, httpDigestRealm string) error {
 | 
			
		||||
	// Basic health handler.
 | 
			
		||||
	if err := healthz.RegisterHandler(mux); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to register healthz handler: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validation/Debug handler.
 | 
			
		||||
	mux.HandleFunc(validate.ValidatePage, func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := validate.HandleRequest(w, containerManager)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Register API handler.
 | 
			
		||||
	if err := api.RegisterHandlers(mux, containerManager); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to register API handlers: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Redirect / to containers page.
 | 
			
		||||
	mux.Handle("/", http.RedirectHandler(pages.ContainersPage, http.StatusTemporaryRedirect))
 | 
			
		||||
 | 
			
		||||
	var authenticated bool = false
 | 
			
		||||
 | 
			
		||||
	// Setup the authenticator object
 | 
			
		||||
	if httpAuthFile != "" {
 | 
			
		||||
		glog.Infof("Using auth file %s", httpAuthFile)
 | 
			
		||||
		secrets := auth.HtpasswdFileProvider(httpAuthFile)
 | 
			
		||||
		authenticator := auth.NewBasicAuthenticator(httpAuthRealm, secrets)
 | 
			
		||||
		mux.HandleFunc(static.StaticResource, authenticator.Wrap(staticHandler))
 | 
			
		||||
		if err := pages.RegisterHandlersBasic(mux, containerManager, authenticator); err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to register pages auth handlers: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
		authenticated = true
 | 
			
		||||
	}
 | 
			
		||||
	if httpAuthFile == "" && httpDigestFile != "" {
 | 
			
		||||
		glog.Infof("Using digest file %s", httpDigestFile)
 | 
			
		||||
		secrets := auth.HtdigestFileProvider(httpDigestFile)
 | 
			
		||||
		authenticator := auth.NewDigestAuthenticator(httpDigestRealm, secrets)
 | 
			
		||||
		mux.HandleFunc(static.StaticResource, authenticator.Wrap(staticHandler))
 | 
			
		||||
		if err := pages.RegisterHandlersDigest(mux, containerManager, authenticator); err != nil {
 | 
			
		||||
			fmt.Errorf("failed to register pages digest handlers: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
		authenticated = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Change handler based on authenticator initalization
 | 
			
		||||
	if !authenticated {
 | 
			
		||||
		mux.HandleFunc(static.StaticResource, staticHandlerNoAuth)
 | 
			
		||||
		if err := pages.RegisterHandlersBasic(mux, containerManager, nil); err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to register pages handlers: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func staticHandlerNoAuth(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	err := static.HandleRequest(w, r.URL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(w, "%s", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func staticHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
	err := static.HandleRequest(w, r.URL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(w, "%s", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/http/mux/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/http/mux/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
// Copyright 2015 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 mux
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Mux interface expected by cAdvisor components.
 | 
			
		||||
type Mux interface {
 | 
			
		||||
	HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
 | 
			
		||||
	Handler(r *http.Request) (http.Handler, string)
 | 
			
		||||
	Handle(pattern string, handler http.Handler)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/manager/manager.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -127,7 +127,7 @@ func New(memoryStorage *memory.InMemoryStorage, sysfs sysfs.SysFs) (Manager, err
 | 
			
		||||
	// Register the raw driver.
 | 
			
		||||
	err = raw.Register(newManager)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("registration of the raw container factory failed: %v", err)
 | 
			
		||||
		glog.Errorf("Registration of the raw container factory failed: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newManager, nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										247
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/containers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/containers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,247 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// Page for /containers/
 | 
			
		||||
package pages
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"math"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	info "github.com/google/cadvisor/info/v1"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ContainersPage = "/containers/"
 | 
			
		||||
 | 
			
		||||
// from http://golang.org/doc/effective_go.html#constants
 | 
			
		||||
type ByteSize float64
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	_ = iota
 | 
			
		||||
	// KB - kilobyte
 | 
			
		||||
	KB ByteSize = 1 << (10 * iota)
 | 
			
		||||
	// MB - megabyte
 | 
			
		||||
	MB
 | 
			
		||||
	// GB - gigabyte
 | 
			
		||||
	GB
 | 
			
		||||
	// TB - terabyte
 | 
			
		||||
	TB
 | 
			
		||||
	// PB - petabyte
 | 
			
		||||
	PB
 | 
			
		||||
	// EB - exabyte
 | 
			
		||||
	EB
 | 
			
		||||
	// ZB - zettabyte
 | 
			
		||||
	ZB
 | 
			
		||||
	// YB - yottabyte
 | 
			
		||||
	YB
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (b ByteSize) Size() string {
 | 
			
		||||
	for _, i := range [...]ByteSize{YB, ZB, EB, PB, TB, GB, MB, KB} {
 | 
			
		||||
		if b >= i {
 | 
			
		||||
			return fmt.Sprintf("%.2f", b/i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%.2f", b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b ByteSize) Unit() string {
 | 
			
		||||
	switch {
 | 
			
		||||
	case b >= YB:
 | 
			
		||||
		return "YB"
 | 
			
		||||
	case b >= ZB:
 | 
			
		||||
		return "ZB"
 | 
			
		||||
	case b >= EB:
 | 
			
		||||
		return "EB"
 | 
			
		||||
	case b >= PB:
 | 
			
		||||
		return "PB"
 | 
			
		||||
	case b >= TB:
 | 
			
		||||
		return "TB"
 | 
			
		||||
	case b >= GB:
 | 
			
		||||
		return "GB"
 | 
			
		||||
	case b >= MB:
 | 
			
		||||
		return "MB"
 | 
			
		||||
	case b >= KB:
 | 
			
		||||
		return "KB"
 | 
			
		||||
	}
 | 
			
		||||
	return "B"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var funcMap = template.FuncMap{
 | 
			
		||||
	"printMask":   printMask,
 | 
			
		||||
	"printCores":  printCores,
 | 
			
		||||
	"printShares": printShares,
 | 
			
		||||
	"printSize":   printSize,
 | 
			
		||||
	"printUnit":   printUnit,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printMask(mask string, numCores int) interface{} {
 | 
			
		||||
	masks := make([]string, numCores)
 | 
			
		||||
	activeCores := getActiveCores(mask)
 | 
			
		||||
	for i := 0; i < numCores; i++ {
 | 
			
		||||
		coreClass := "inactive-cpu"
 | 
			
		||||
		if activeCores[i] {
 | 
			
		||||
			coreClass = "active-cpu"
 | 
			
		||||
		}
 | 
			
		||||
		masks[i] = fmt.Sprintf("<span class=\"%s\">%d</span>", coreClass, i)
 | 
			
		||||
	}
 | 
			
		||||
	return template.HTML(strings.Join(masks, " "))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getActiveCores(mask string) map[int]bool {
 | 
			
		||||
	activeCores := make(map[int]bool)
 | 
			
		||||
	for _, corebits := range strings.Split(mask, ",") {
 | 
			
		||||
		cores := strings.Split(corebits, "-")
 | 
			
		||||
		if len(cores) == 1 {
 | 
			
		||||
			index, err := strconv.Atoi(cores[0])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// Ignore malformed strings.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			activeCores[index] = true
 | 
			
		||||
		} else if len(cores) == 2 {
 | 
			
		||||
			start, err := strconv.Atoi(cores[0])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			end, err := strconv.Atoi(cores[1])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			for i := start; i <= end; i++ {
 | 
			
		||||
				activeCores[i] = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return activeCores
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printCores(millicores *uint64) string {
 | 
			
		||||
	cores := float64(*millicores) / 1000
 | 
			
		||||
	return strconv.FormatFloat(cores, 'f', 3, 64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printShares(shares *uint64) string {
 | 
			
		||||
	return fmt.Sprintf("%d", *shares)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toMegabytes(bytes uint64) float64 {
 | 
			
		||||
	return float64(bytes) / (1 << 20)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printSize(bytes uint64) string {
 | 
			
		||||
	if bytes >= math.MaxInt64 {
 | 
			
		||||
		return "unlimited"
 | 
			
		||||
	}
 | 
			
		||||
	return ByteSize(bytes).Size()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printUnit(bytes uint64) string {
 | 
			
		||||
	if bytes >= math.MaxInt64 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return ByteSize(bytes).Unit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toMemoryPercent(usage uint64, spec *info.ContainerSpec, machine *info.MachineInfo) int {
 | 
			
		||||
	// Saturate limit to the machine size.
 | 
			
		||||
	limit := uint64(spec.Memory.Limit)
 | 
			
		||||
	if limit > uint64(machine.MemoryCapacity) {
 | 
			
		||||
		limit = uint64(machine.MemoryCapacity)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return int((usage * 100) / limit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
 | 
			
		||||
	start := time.Now()
 | 
			
		||||
 | 
			
		||||
	// The container name is the path after the handler
 | 
			
		||||
	containerName := u.Path[len(ContainersPage)-1:]
 | 
			
		||||
 | 
			
		||||
	// Get the container.
 | 
			
		||||
	reqParams := info.ContainerInfoRequest{
 | 
			
		||||
		NumStats: 60,
 | 
			
		||||
	}
 | 
			
		||||
	cont, err := m.GetContainerInfo(containerName, &reqParams)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
 | 
			
		||||
	}
 | 
			
		||||
	displayName := getContainerDisplayName(cont.ContainerReference)
 | 
			
		||||
 | 
			
		||||
	// Get the MachineInfo
 | 
			
		||||
	machineInfo, err := m.GetMachineInfo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Make a list of the parent containers and their links
 | 
			
		||||
	pathParts := strings.Split(string(cont.Name), "/")
 | 
			
		||||
	parentContainers := make([]link, 0, len(pathParts))
 | 
			
		||||
	parentContainers = append(parentContainers, link{
 | 
			
		||||
		Text: "root",
 | 
			
		||||
		Link: ContainersPage,
 | 
			
		||||
	})
 | 
			
		||||
	for i := 1; i < len(pathParts); i++ {
 | 
			
		||||
		// Skip empty parts.
 | 
			
		||||
		if pathParts[i] == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		parentContainers = append(parentContainers, link{
 | 
			
		||||
			Text: pathParts[i],
 | 
			
		||||
			Link: path.Join(ContainersPage, path.Join(pathParts[1:i+1]...)),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Build the links for the subcontainers.
 | 
			
		||||
	subcontainerLinks := make([]link, 0, len(cont.Subcontainers))
 | 
			
		||||
	for _, sub := range cont.Subcontainers {
 | 
			
		||||
		subcontainerLinks = append(subcontainerLinks, link{
 | 
			
		||||
			Text: getContainerDisplayName(sub),
 | 
			
		||||
			Link: path.Join(ContainersPage, sub.Name),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := &pageData{
 | 
			
		||||
		DisplayName:        displayName,
 | 
			
		||||
		ContainerName:      cont.Name,
 | 
			
		||||
		ParentContainers:   parentContainers,
 | 
			
		||||
		Subcontainers:      subcontainerLinks,
 | 
			
		||||
		Spec:               cont.Spec,
 | 
			
		||||
		Stats:              cont.Stats,
 | 
			
		||||
		MachineInfo:        machineInfo,
 | 
			
		||||
		IsRoot:             cont.Name == "/",
 | 
			
		||||
		ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork || cont.Spec.HasFilesystem,
 | 
			
		||||
		CpuAvailable:       cont.Spec.HasCpu,
 | 
			
		||||
		MemoryAvailable:    cont.Spec.HasMemory,
 | 
			
		||||
		NetworkAvailable:   cont.Spec.HasNetwork,
 | 
			
		||||
		FsAvailable:        cont.Spec.HasFilesystem,
 | 
			
		||||
	}
 | 
			
		||||
	err = pageTemplate.Execute(w, data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Errorf("Failed to apply template: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glog.V(1).Infof("Request took %s", time.Since(start))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										186
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/containers_html.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/containers_html.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 pages
 | 
			
		||||
 | 
			
		||||
const containersHtmlTemplate = `
 | 
			
		||||
<html>
 | 
			
		||||
  <head>
 | 
			
		||||
    <title>cAdvisor - {{.DisplayName}}</title>
 | 
			
		||||
    <!-- Latest compiled and minified CSS -->
 | 
			
		||||
    <link rel="stylesheet" href="/static/bootstrap-3.1.1.min.css">
 | 
			
		||||
 | 
			
		||||
    <!-- Optional theme -->
 | 
			
		||||
    <link rel="stylesheet" href="/static/bootstrap-theme-3.1.1.min.css">
 | 
			
		||||
 | 
			
		||||
    <link rel="stylesheet" href="/static/containers.css">
 | 
			
		||||
 | 
			
		||||
    <!-- Latest compiled and minified JavaScript -->
 | 
			
		||||
    <script src="/static/jquery-1.10.2.min.js"></script>
 | 
			
		||||
    <script src="/static/bootstrap-3.1.1.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="/static/google-jsapi.js"></script>
 | 
			
		||||
 | 
			
		||||
    <script type="text/javascript" src="/static/containers.js"></script>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div class="container theme-showcase" >
 | 
			
		||||
      <div class="col-sm-12" id="logo">
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col-sm-12">
 | 
			
		||||
	<div class="page-header">
 | 
			
		||||
	  <h1>{{.DisplayName}}</h1>
 | 
			
		||||
	</div>
 | 
			
		||||
	<ol class="breadcrumb">
 | 
			
		||||
	  {{range $parentContainer := .ParentContainers}}
 | 
			
		||||
	  <li><a href="{{$parentContainer.Link}}">{{$parentContainer.Text}}</a></li>
 | 
			
		||||
	  {{end}}
 | 
			
		||||
	</ol>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{if .IsRoot}}
 | 
			
		||||
      <div class="col-sm-12">
 | 
			
		||||
        <h4><a href="/docker">Docker Containers</a></h4>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{end}}
 | 
			
		||||
      {{if .Subcontainers}}
 | 
			
		||||
      <div class="col-sm-12">
 | 
			
		||||
	<div class="page-header">
 | 
			
		||||
	  <h3>Subcontainers</h3>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="list-group">
 | 
			
		||||
	  {{range $subcontainer := .Subcontainers}}
 | 
			
		||||
	  <a href="{{$subcontainer.Link}}" class="list-group-item">{{$subcontainer.Text}}</a>
 | 
			
		||||
	  {{end}}
 | 
			
		||||
	</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      {{end}}
 | 
			
		||||
      {{if .ResourcesAvailable}}
 | 
			
		||||
      <div class="col-sm-12">
 | 
			
		||||
	<div class="page-header">
 | 
			
		||||
	  <h3>Isolation</h3>
 | 
			
		||||
	</div>
 | 
			
		||||
	{{if .CpuAvailable}}
 | 
			
		||||
	<ul class="list-group">
 | 
			
		||||
          <li class="list-group-item active isolation-title panel-title">CPU</li>
 | 
			
		||||
          {{if .Spec.Cpu.Limit}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Shares</span> {{printShares .Spec.Cpu.Limit}} <span class="unit-label">shares</span></li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
          {{if .Spec.Cpu.MaxLimit}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Max Limit</span> {{printCores .Spec.Cpu.MaxLimit}} <span class="unit-label">cores</span></li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
          {{if .Spec.Cpu.Mask}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Allowed Cores</span> {{printMask .Spec.Cpu.Mask .MachineInfo.NumCores}}</li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
	</ul>
 | 
			
		||||
	{{end}}
 | 
			
		||||
	{{if .MemoryAvailable}}
 | 
			
		||||
	<ul class="list-group">
 | 
			
		||||
          <li class="list-group-item active isolation-title panel-title">Memory</li>
 | 
			
		||||
          {{if .Spec.Memory.Reservation}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Reservation</span> {{printSize .Spec.Memory.Reservation}} <span class="unit-label">{{printUnit .Spec.Memory.Reservation}}</span></li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
          {{if .Spec.Memory.Limit}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Limit</span> {{printSize .Spec.Memory.Limit}} <span class="unit-label">{{printUnit .Spec.Memory.Limit}}</span></li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
          {{if .Spec.Memory.SwapLimit}}
 | 
			
		||||
          <li class="list-group-item"><span class="stat-label">Swap Limit</span> {{printSize .Spec.Memory.SwapLimit}} <span class="unit-label">{{printUnit .Spec.Memory.SwapLimit}}</span></li>
 | 
			
		||||
          {{end}}
 | 
			
		||||
	</ul>
 | 
			
		||||
	{{end}}
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col-sm-12">
 | 
			
		||||
	<div class="page-header">
 | 
			
		||||
	  <h3>Usage</h3>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="panel panel-primary">
 | 
			
		||||
          <div class="panel-heading">
 | 
			
		||||
            <h3 class="panel-title">Overview</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div id="usage-gauge" class="panel-body"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
	{{if .CpuAvailable}}
 | 
			
		||||
	<div class="panel panel-primary">
 | 
			
		||||
          <div class="panel-heading">
 | 
			
		||||
            <h3 class="panel-title">CPU</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="panel-body">
 | 
			
		||||
            <h4>Total Usage</h4>
 | 
			
		||||
	    <div id="cpu-total-usage-chart"></div>
 | 
			
		||||
	    <!-- <h4>CPU Load Average</h4>
 | 
			
		||||
	    <div id="cpu-load-chart"></div> -->
 | 
			
		||||
            <h4>Usage per Core</h4>
 | 
			
		||||
	    <div id="cpu-per-core-usage-chart"></div>
 | 
			
		||||
            <h4>Usage Breakdown</h4>
 | 
			
		||||
	    <div id="cpu-usage-breakdown-chart"></div>
 | 
			
		||||
          </div>
 | 
			
		||||
	</div>
 | 
			
		||||
	{{end}}
 | 
			
		||||
	{{if .MemoryAvailable}}
 | 
			
		||||
	<div class="panel panel-primary">
 | 
			
		||||
          <div class="panel-heading">
 | 
			
		||||
            <h3 class="panel-title">Memory</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="panel-body">
 | 
			
		||||
            <h4>Total Usage</h4>
 | 
			
		||||
	    <div id="memory-usage-chart"></div>
 | 
			
		||||
            <br/>
 | 
			
		||||
            <div class="row col-sm-12">
 | 
			
		||||
              <h4>Usage Breakdown</h4>
 | 
			
		||||
              <div class="col-sm-9">
 | 
			
		||||
		<div class="progress">
 | 
			
		||||
                  <div class="progress-bar progress-bar-danger" id="progress-hot-memory">
 | 
			
		||||
                    <span class="sr-only">Hot Memory</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="progress-bar progress-bar-info" id="progress-cold-memory">
 | 
			
		||||
                    <span class="sr-only">Cold Memory</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
		</div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="col-sm-3" id="memory-text"></div>
 | 
			
		||||
	    </div>
 | 
			
		||||
          </div>
 | 
			
		||||
	</div>
 | 
			
		||||
	{{end}}
 | 
			
		||||
	{{if .NetworkAvailable}}
 | 
			
		||||
	<div class="panel panel-primary">
 | 
			
		||||
	  <div class="panel-heading">
 | 
			
		||||
            <h3 class="panel-title">Network</h3>
 | 
			
		||||
	  </div>
 | 
			
		||||
	  <div class="panel-body">
 | 
			
		||||
            <h4>Throughput</h4>
 | 
			
		||||
            <div id="network-bytes-chart"></div>
 | 
			
		||||
	  </div>
 | 
			
		||||
	  <div class="panel-body">
 | 
			
		||||
            <h4>Errors</h4>
 | 
			
		||||
	    <div id="network-errors-chart"></div>
 | 
			
		||||
	  </div>
 | 
			
		||||
	</div>
 | 
			
		||||
        {{end}}
 | 
			
		||||
	{{if .FsAvailable}}
 | 
			
		||||
	<div class="panel panel-primary">
 | 
			
		||||
          <div class="panel-heading">
 | 
			
		||||
            <h3 class="panel-title">Filesystem</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div id="filesystem-usage" class="panel-body">
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
	{{end}}
 | 
			
		||||
      </div>
 | 
			
		||||
      {{end}}
 | 
			
		||||
    </div>
 | 
			
		||||
    <script type="text/javascript">
 | 
			
		||||
      startPage({{.ContainerName}}, {{.CpuAvailable}}, {{.MemoryAvailable}});
 | 
			
		||||
    </script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
`
 | 
			
		||||
							
								
								
									
										116
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/docker.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/docker.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 pages
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"path"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/google/cadvisor/container/docker"
 | 
			
		||||
	info "github.com/google/cadvisor/info/v1"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const DockerPage = "/docker/"
 | 
			
		||||
 | 
			
		||||
func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
 | 
			
		||||
	start := time.Now()
 | 
			
		||||
 | 
			
		||||
	// The container name is the path after the handler
 | 
			
		||||
	containerName := u.Path[len(DockerPage):]
 | 
			
		||||
 | 
			
		||||
	var data *pageData
 | 
			
		||||
	if containerName == "" {
 | 
			
		||||
		// Get the containers.
 | 
			
		||||
		reqParams := info.ContainerInfoRequest{
 | 
			
		||||
			NumStats: 0,
 | 
			
		||||
		}
 | 
			
		||||
		conts, err := m.AllDockerContainers(&reqParams)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
 | 
			
		||||
		}
 | 
			
		||||
		subcontainers := make([]link, 0, len(conts))
 | 
			
		||||
		for _, cont := range conts {
 | 
			
		||||
			subcontainers = append(subcontainers, link{
 | 
			
		||||
				Text: getContainerDisplayName(cont.ContainerReference),
 | 
			
		||||
				Link: path.Join("/docker", docker.ContainerNameToDockerId(cont.ContainerReference.Name)),
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dockerContainersText := "Docker Containers"
 | 
			
		||||
		data = &pageData{
 | 
			
		||||
			DisplayName: dockerContainersText,
 | 
			
		||||
			ParentContainers: []link{
 | 
			
		||||
				{
 | 
			
		||||
					Text: dockerContainersText,
 | 
			
		||||
					Link: DockerPage,
 | 
			
		||||
				}},
 | 
			
		||||
			Subcontainers: subcontainers,
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// Get the container.
 | 
			
		||||
		reqParams := info.ContainerInfoRequest{
 | 
			
		||||
			NumStats: 60,
 | 
			
		||||
		}
 | 
			
		||||
		cont, err := m.DockerContainer(containerName, &reqParams)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("failed to get container %q with error: %v", containerName, err)
 | 
			
		||||
		}
 | 
			
		||||
		displayName := getContainerDisplayName(cont.ContainerReference)
 | 
			
		||||
 | 
			
		||||
		// Make a list of the parent containers and their links
 | 
			
		||||
		var parentContainers []link
 | 
			
		||||
		parentContainers = append(parentContainers, link{
 | 
			
		||||
			Text: "Docker containers",
 | 
			
		||||
			Link: DockerPage,
 | 
			
		||||
		})
 | 
			
		||||
		parentContainers = append(parentContainers, link{
 | 
			
		||||
			Text: displayName,
 | 
			
		||||
			Link: path.Join(DockerPage, docker.ContainerNameToDockerId(cont.Name)),
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		// Get the MachineInfo
 | 
			
		||||
		machineInfo, err := m.GetMachineInfo()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		data = &pageData{
 | 
			
		||||
			DisplayName:        displayName,
 | 
			
		||||
			ContainerName:      cont.Name,
 | 
			
		||||
			ParentContainers:   parentContainers,
 | 
			
		||||
			Spec:               cont.Spec,
 | 
			
		||||
			Stats:              cont.Stats,
 | 
			
		||||
			MachineInfo:        machineInfo,
 | 
			
		||||
			ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork,
 | 
			
		||||
			CpuAvailable:       cont.Spec.HasCpu,
 | 
			
		||||
			MemoryAvailable:    cont.Spec.HasMemory,
 | 
			
		||||
			NetworkAvailable:   cont.Spec.HasNetwork,
 | 
			
		||||
			FsAvailable:        cont.Spec.HasFilesystem,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := pageTemplate.Execute(w, data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Errorf("Failed to apply template: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glog.V(1).Infof("Request took %s", time.Since(start))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										152
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/pages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/pages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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 pages
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	auth "github.com/abbot/go-http-auth"
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	httpMux "github.com/google/cadvisor/http/mux"
 | 
			
		||||
	info "github.com/google/cadvisor/info/v1"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pageTemplate *template.Template
 | 
			
		||||
 | 
			
		||||
type link struct {
 | 
			
		||||
	// Text to show in the link.
 | 
			
		||||
	Text string
 | 
			
		||||
 | 
			
		||||
	// Web address to link to.
 | 
			
		||||
	Link string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pageData struct {
 | 
			
		||||
	DisplayName        string
 | 
			
		||||
	ContainerName      string
 | 
			
		||||
	ParentContainers   []link
 | 
			
		||||
	Subcontainers      []link
 | 
			
		||||
	Spec               info.ContainerSpec
 | 
			
		||||
	Stats              []*info.ContainerStats
 | 
			
		||||
	MachineInfo        *info.MachineInfo
 | 
			
		||||
	IsRoot             bool
 | 
			
		||||
	ResourcesAvailable bool
 | 
			
		||||
	CpuAvailable       bool
 | 
			
		||||
	MemoryAvailable    bool
 | 
			
		||||
	NetworkAvailable   bool
 | 
			
		||||
	FsAvailable        bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	pageTemplate = template.New("containersTemplate").Funcs(funcMap)
 | 
			
		||||
	_, err := pageTemplate.Parse(containersHtmlTemplate)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		glog.Fatalf("Failed to parse template: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func containerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := serveContainersPage(containerManager, w, r.URL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func containerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
		err := serveContainersPage(containerManager, w, r.URL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dockerHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := serveDockerPage(containerManager, w, r.URL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFunc {
 | 
			
		||||
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
 | 
			
		||||
		err := serveDockerPage(containerManager, w, r.URL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Fprintf(w, "%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Register http handlers
 | 
			
		||||
func RegisterHandlersDigest(mux httpMux.Mux, containerManager manager.Manager, authenticator *auth.DigestAuth) error {
 | 
			
		||||
	// Register the handler for the containers page.
 | 
			
		||||
	if authenticator != nil {
 | 
			
		||||
		mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
 | 
			
		||||
		mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
 | 
			
		||||
	} else {
 | 
			
		||||
		mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
 | 
			
		||||
		mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RegisterHandlersBasic(mux httpMux.Mux, containerManager manager.Manager, authenticator *auth.BasicAuth) error {
 | 
			
		||||
	// Register the handler for the containers and docker age.
 | 
			
		||||
	if authenticator != nil {
 | 
			
		||||
		mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
 | 
			
		||||
		mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
 | 
			
		||||
	} else {
 | 
			
		||||
		mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
 | 
			
		||||
		mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getContainerDisplayName(cont info.ContainerReference) string {
 | 
			
		||||
	// Pick a user-added alias as display name.
 | 
			
		||||
	displayName := ""
 | 
			
		||||
	for _, alias := range cont.Aliases {
 | 
			
		||||
		// ignore container id as alias.
 | 
			
		||||
		if strings.Contains(cont.Name, alias) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// pick shortest display name if multiple aliases are available.
 | 
			
		||||
		if displayName == "" || len(displayName) >= len(alias) {
 | 
			
		||||
			displayName = alias
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if displayName == "" {
 | 
			
		||||
		displayName = cont.Name
 | 
			
		||||
	} else if len(displayName) > 50 {
 | 
			
		||||
		// truncate display name to fit in one line.
 | 
			
		||||
		displayName = displayName[:50] + "..."
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add the full container name to the display name.
 | 
			
		||||
	if displayName != cont.Name {
 | 
			
		||||
		displayName = fmt.Sprintf("%s (%s)", displayName, cont.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return displayName
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_min_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_min_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_min_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_min_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										25
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_theme_min_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/bootstrap_theme_min_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										50
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/containers_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/containers_css.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1918
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/containers_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1918
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/containers_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										57
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/google_jsapi_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/google_jsapi_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/jquery_min_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/jquery_min_js.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										51
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/static.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/pages/static/static.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// Handler for /static content.
 | 
			
		||||
 | 
			
		||||
package static
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const StaticResource = "/static/"
 | 
			
		||||
 | 
			
		||||
var staticFiles = map[string]string{
 | 
			
		||||
	"containers.css":                containersCss,
 | 
			
		||||
	"containers.js":                 containersJs,
 | 
			
		||||
	"bootstrap-3.1.1.min.css":       bootstrapCss,
 | 
			
		||||
	"bootstrap-theme-3.1.1.min.css": bootstrapThemeCss,
 | 
			
		||||
	"jquery-1.10.2.min.js":          jqueryJs,
 | 
			
		||||
	"bootstrap-3.1.1.min.js":        bootstrapJs,
 | 
			
		||||
	"google-jsapi.js":               googleJsapiJs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func HandleRequest(w http.ResponseWriter, u *url.URL) error {
 | 
			
		||||
	if len(u.Path) <= len(StaticResource) {
 | 
			
		||||
		return fmt.Errorf("unknown static resource %q", u.Path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the static content if it exists.
 | 
			
		||||
	resource := u.Path[len(StaticResource):]
 | 
			
		||||
	content, ok := staticFiles[resource]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("unknown static resource %q", resource)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := w.Write([]byte(content))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										318
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/validate/validate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								Godeps/_workspace/src/github.com/google/cadvisor/validate/validate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,318 @@
 | 
			
		||||
// Copyright 2014 Google Inc. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// Handler for /validate content.
 | 
			
		||||
// Validates cadvisor dependencies - kernel, os, docker setup.
 | 
			
		||||
 | 
			
		||||
package validate
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/google/cadvisor/manager"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/libcontainer/cgroups"
 | 
			
		||||
	dclient "github.com/fsouza/go-dockerclient"
 | 
			
		||||
	"github.com/google/cadvisor/container/docker"
 | 
			
		||||
	"github.com/google/cadvisor/utils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ValidatePage  = "/validate/"
 | 
			
		||||
	Supported     = "[Supported, but not recommended]"
 | 
			
		||||
	Unsupported   = "[Unsupported]"
 | 
			
		||||
	Recommended   = "[Supported and recommended]"
 | 
			
		||||
	Unknown       = "[Unknown]"
 | 
			
		||||
	VersionFormat = "%d.%d%s"
 | 
			
		||||
	OutputFormat  = "%s: %s\n\t%s\n\n"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getMajorMinor(version string) (int, int, error) {
 | 
			
		||||
	var major, minor int
 | 
			
		||||
	var ign string
 | 
			
		||||
	n, err := fmt.Sscanf(version, VersionFormat, &major, &minor, &ign)
 | 
			
		||||
	if n != 3 || err != nil {
 | 
			
		||||
		log.Printf("Failed to parse version for %s", version)
 | 
			
		||||
		return -1, -1, err
 | 
			
		||||
	}
 | 
			
		||||
	return major, minor, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateKernelVersion(version string) (string, string) {
 | 
			
		||||
	desc := fmt.Sprintf("Kernel version is %s. Versions >= 2.6 are supported. 3.0+ are recommended.\n", version)
 | 
			
		||||
	major, minor, err := getMajorMinor(version)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		desc = fmt.Sprintf("Could not parse kernel version. %s", desc)
 | 
			
		||||
		return Unknown, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if major < 2 {
 | 
			
		||||
		return Unsupported, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if major == 2 && minor < 6 {
 | 
			
		||||
		return Unsupported, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if major >= 3 {
 | 
			
		||||
		return Recommended, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Supported, desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateDockerVersion(version string) (string, string) {
 | 
			
		||||
	desc := fmt.Sprintf("Docker version is %s. Versions >= 1.0 are supported. 1.2+ are recommended.\n", version)
 | 
			
		||||
	major, minor, err := getMajorMinor(version)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		desc = fmt.Sprintf("Could not parse docker version. %s\n\t", desc)
 | 
			
		||||
		return Unknown, desc
 | 
			
		||||
	}
 | 
			
		||||
	if major < 1 {
 | 
			
		||||
		return Unsupported, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if major == 1 && minor < 2 {
 | 
			
		||||
		return Supported, desc
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Recommended, desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getEnabledCgroups() (map[string]int, error) {
 | 
			
		||||
	out, err := ioutil.ReadFile("/proc/cgroups")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	cgroups := make(map[string]int)
 | 
			
		||||
	for i, line := range strings.Split(string(out), "\n") {
 | 
			
		||||
		var cgroup string
 | 
			
		||||
		var ign, enabled int
 | 
			
		||||
		if i == 0 || line == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		n, err := fmt.Sscanf(line, "%s %d %d %d", &cgroup, &ign, &ign, &enabled)
 | 
			
		||||
		if n != 4 || err != nil {
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				err = fmt.Errorf("failed to parse /proc/cgroup entry %s", line)
 | 
			
		||||
			}
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		cgroups[cgroup] = enabled
 | 
			
		||||
	}
 | 
			
		||||
	return cgroups, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func areCgroupsPresent(available map[string]int, desired []string) (bool, string) {
 | 
			
		||||
	for _, cgroup := range desired {
 | 
			
		||||
		enabled, ok := available[cgroup]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			reason := fmt.Sprintf("Missing cgroup %s. Available cgroups: %v\n", cgroup, available)
 | 
			
		||||
			return false, reason
 | 
			
		||||
		}
 | 
			
		||||
		if enabled != 1 {
 | 
			
		||||
			reason := fmt.Sprintf("Cgroup %s not enabled. Available cgroups: %v\n", cgroup, available)
 | 
			
		||||
			return false, reason
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateMemoryAccounting(available_cgroups map[string]int) string {
 | 
			
		||||
	ok, _ := areCgroupsPresent(available_cgroups, []string{"memory"})
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n"
 | 
			
		||||
	}
 | 
			
		||||
	mnt, err := cgroups.FindCgroupMountpoint("memory")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n"
 | 
			
		||||
	}
 | 
			
		||||
	hier, err := ioutil.ReadFile(path.Join(mnt, "memory.use_hierarchy"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "\tHierarchical memory accounting status unknown: hierarchy interface unavailable.\n"
 | 
			
		||||
	}
 | 
			
		||||
	var enabled int
 | 
			
		||||
	n, err := fmt.Sscanf(string(hier), "%d", &enabled)
 | 
			
		||||
	if err != nil || n != 1 {
 | 
			
		||||
		return "\tHierarchical memory accounting status unknown: hierarchy interface unreadable.\n"
 | 
			
		||||
	}
 | 
			
		||||
	if enabled == 1 {
 | 
			
		||||
		return "\tHierarchical memory accounting enabled. Reported memory usage includes memory used by child containers.\n"
 | 
			
		||||
	}
 | 
			
		||||
	return "\tHierarchical memory accounting disabled. Memory usage does not include usage from child containers.\n"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateCgroups() (string, string) {
 | 
			
		||||
	required_cgroups := []string{"cpu", "cpuacct"}
 | 
			
		||||
	recommended_cgroups := []string{"memory", "blkio", "cpuset", "devices", "freezer"}
 | 
			
		||||
	available_cgroups, err := getEnabledCgroups()
 | 
			
		||||
	desc := fmt.Sprintf("\tFollowing cgroups are required: %v\n\tFollowing other cgroups are recommended: %v\n", required_cgroups, recommended_cgroups)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		desc = fmt.Sprintf("Could not parse /proc/cgroups.\n%s", desc)
 | 
			
		||||
		return Unknown, desc
 | 
			
		||||
	}
 | 
			
		||||
	ok, out := areCgroupsPresent(available_cgroups, required_cgroups)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Unsupported, out
 | 
			
		||||
	}
 | 
			
		||||
	ok, out = areCgroupsPresent(available_cgroups, recommended_cgroups)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		// supported, but not recommended.
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Supported, out
 | 
			
		||||
	}
 | 
			
		||||
	out = fmt.Sprintf("Available cgroups: %v\n", available_cgroups)
 | 
			
		||||
	out += desc
 | 
			
		||||
	out += validateMemoryAccounting(available_cgroups)
 | 
			
		||||
	return Recommended, out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateDockerInfo() (string, string) {
 | 
			
		||||
	client, err := dclient.NewClient(*docker.ArgDockerEndpoint)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		info, err := client.Info()
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			execDriver := info.Get("ExecutionDriver")
 | 
			
		||||
			storageDriver := info.Get("Driver")
 | 
			
		||||
			desc := fmt.Sprintf("Docker exec driver is %s. Storage driver is %s.\n", execDriver, storageDriver)
 | 
			
		||||
			if docker.UseSystemd() {
 | 
			
		||||
				desc += "\tsystemd is being used to create cgroups.\n"
 | 
			
		||||
			} else {
 | 
			
		||||
				desc += "\tCgroups are being created through cgroup filesystem.\n"
 | 
			
		||||
			}
 | 
			
		||||
			if strings.Contains(execDriver, "native") {
 | 
			
		||||
				stateFile := docker.DockerStateDir()
 | 
			
		||||
				if !utils.FileExists(stateFile) {
 | 
			
		||||
					desc += fmt.Sprintf("\tDocker container state directory %q is not accessible.\n", stateFile)
 | 
			
		||||
					return Unsupported, desc
 | 
			
		||||
				}
 | 
			
		||||
				desc += fmt.Sprintf("\tDocker container state directory is at %q and is accessible.\n", stateFile)
 | 
			
		||||
				return Recommended, desc
 | 
			
		||||
			} else if strings.Contains(execDriver, "lxc") {
 | 
			
		||||
				return Supported, desc
 | 
			
		||||
			}
 | 
			
		||||
			return Unknown, desc
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return Unknown, "Docker remote API not reachable\n\t"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateCgroupMounts() (string, string) {
 | 
			
		||||
	const recommendedMount = "/sys/fs/cgroup"
 | 
			
		||||
	desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount)
 | 
			
		||||
	mnt, err := cgroups.FindCgroupMountpoint("cpu")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		out := "Could not locate cgroup mount point.\n"
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Unknown, out
 | 
			
		||||
	}
 | 
			
		||||
	mnt = path.Dir(mnt)
 | 
			
		||||
	if !utils.FileExists(mnt) {
 | 
			
		||||
		out := fmt.Sprintf("Cgroup mount directory %s inaccessible.\n", mnt)
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Unsupported, out
 | 
			
		||||
	}
 | 
			
		||||
	mounts, err := ioutil.ReadDir(mnt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		out := fmt.Sprintf("Could not read cgroup mount directory %s.\n", mnt)
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Unsupported, out
 | 
			
		||||
	}
 | 
			
		||||
	mountNames := "\tCgroup mount directories: "
 | 
			
		||||
	for _, mount := range mounts {
 | 
			
		||||
		mountNames += mount.Name() + " "
 | 
			
		||||
	}
 | 
			
		||||
	mountNames += "\n"
 | 
			
		||||
	out := fmt.Sprintf("Cgroups are mounted at %s.\n", mnt)
 | 
			
		||||
	out += mountNames
 | 
			
		||||
	out += desc
 | 
			
		||||
	info, err := ioutil.ReadFile("/proc/mounts")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		out := fmt.Sprintf("Could not read /proc/mounts.\n")
 | 
			
		||||
		out += desc
 | 
			
		||||
		return Unsupported, out
 | 
			
		||||
	}
 | 
			
		||||
	out += "\tCgroup mounts:\n"
 | 
			
		||||
	for _, line := range strings.Split(string(info), "\n") {
 | 
			
		||||
		if strings.Contains(line, " cgroup ") {
 | 
			
		||||
			out += "\t" + line + "\n"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if mnt == recommendedMount {
 | 
			
		||||
		return Recommended, out
 | 
			
		||||
	}
 | 
			
		||||
	return Supported, out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateIoScheduler(containerManager manager.Manager) (string, string) {
 | 
			
		||||
	var desc string
 | 
			
		||||
	mi, err := containerManager.GetMachineInfo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Unknown, "Machine info not available\n\t"
 | 
			
		||||
	}
 | 
			
		||||
	cfq := false
 | 
			
		||||
	for _, disk := range mi.DiskMap {
 | 
			
		||||
		desc += fmt.Sprintf("\t Disk %q Scheduler type %q.\n", disk.Name, disk.Scheduler)
 | 
			
		||||
		if disk.Scheduler == "cfq" {
 | 
			
		||||
			cfq = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Since we get lot of random block devices, report recommended if
 | 
			
		||||
	// at least one of them is on cfq. Report Supported otherwise.
 | 
			
		||||
	if cfq {
 | 
			
		||||
		desc = "At least one device supports 'cfq' I/O scheduler. Some disk stats can be reported.\n" + desc
 | 
			
		||||
		return Recommended, desc
 | 
			
		||||
	}
 | 
			
		||||
	desc = "None of the devices support 'cfq' I/O scheduler. No disk stats can be reported.\n" + desc
 | 
			
		||||
	return Supported, desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func HandleRequest(w http.ResponseWriter, containerManager manager.Manager) error {
 | 
			
		||||
	// Get cAdvisor version Info.
 | 
			
		||||
	versionInfo, err := containerManager.GetVersionInfo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out := fmt.Sprintf("cAdvisor version: %s\n\n", versionInfo.CadvisorVersion)
 | 
			
		||||
 | 
			
		||||
	// No OS is preferred or unsupported as of now.
 | 
			
		||||
	out += fmt.Sprintf("OS version: %s\n\n", versionInfo.ContainerOsVersion)
 | 
			
		||||
 | 
			
		||||
	kernelValidation, desc := validateKernelVersion(versionInfo.KernelVersion)
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Kernel version", kernelValidation, desc)
 | 
			
		||||
 | 
			
		||||
	cgroupValidation, desc := validateCgroups()
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Cgroup setup", cgroupValidation, desc)
 | 
			
		||||
 | 
			
		||||
	mountsValidation, desc := validateCgroupMounts()
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Cgroup mount setup", mountsValidation, desc)
 | 
			
		||||
 | 
			
		||||
	dockerValidation, desc := validateDockerVersion(versionInfo.DockerVersion)
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Docker version", dockerValidation, desc)
 | 
			
		||||
 | 
			
		||||
	dockerInfoValidation, desc := validateDockerInfo()
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Docker driver setup", dockerInfoValidation, desc)
 | 
			
		||||
 | 
			
		||||
	ioSchedulerValidation, desc := validateIoScheduler(containerManager)
 | 
			
		||||
	out += fmt.Sprintf(OutputFormat, "Block device setup", ioSchedulerValidation, desc)
 | 
			
		||||
	_, err = w.Write([]byte(out))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										575
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										575
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,575 +0,0 @@
 | 
			
		||||
// The elb package provides types and functions for interaction with the AWS
 | 
			
		||||
// Elastic Load Balancing service (ELB)
 | 
			
		||||
package elb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/mitchellh/goamz/aws"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The ELB type encapsulates operations operations with the elb endpoint.
 | 
			
		||||
type ELB struct {
 | 
			
		||||
	aws.Auth
 | 
			
		||||
	aws.Region
 | 
			
		||||
	httpClient *http.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const APIVersion = "2012-06-01"
 | 
			
		||||
 | 
			
		||||
// New creates a new ELB instance.
 | 
			
		||||
func New(auth aws.Auth, region aws.Region) *ELB {
 | 
			
		||||
	return NewWithClient(auth, region, aws.RetryingClient)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewWithClient(auth aws.Auth, region aws.Region, httpClient *http.Client) *ELB {
 | 
			
		||||
	return &ELB{auth, region, httpClient}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) query(params map[string]string, resp interface{}) error {
 | 
			
		||||
	params["Version"] = APIVersion
 | 
			
		||||
	params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
 | 
			
		||||
 | 
			
		||||
	endpoint, err := url.Parse(elb.Region.ELBEndpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sign(elb.Auth, "GET", "/", params, endpoint.Host)
 | 
			
		||||
	endpoint.RawQuery = multimap(params).Encode()
 | 
			
		||||
	r, err := elb.httpClient.Get(endpoint.String())
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer r.Body.Close()
 | 
			
		||||
	if r.StatusCode > 200 {
 | 
			
		||||
		return buildError(r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	decoder := xml.NewDecoder(r.Body)
 | 
			
		||||
	decodedBody := decoder.Decode(resp)
 | 
			
		||||
 | 
			
		||||
	return decodedBody
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func buildError(r *http.Response) error {
 | 
			
		||||
	var (
 | 
			
		||||
		err    Error
 | 
			
		||||
		errors xmlErrors
 | 
			
		||||
	)
 | 
			
		||||
	xml.NewDecoder(r.Body).Decode(&errors)
 | 
			
		||||
	if len(errors.Errors) > 0 {
 | 
			
		||||
		err = errors.Errors[0]
 | 
			
		||||
	}
 | 
			
		||||
	err.StatusCode = r.StatusCode
 | 
			
		||||
	if err.Message == "" {
 | 
			
		||||
		err.Message = r.Status
 | 
			
		||||
	}
 | 
			
		||||
	return &err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func multimap(p map[string]string) url.Values {
 | 
			
		||||
	q := make(url.Values, len(p))
 | 
			
		||||
	for k, v := range p {
 | 
			
		||||
		q[k] = []string{v}
 | 
			
		||||
	}
 | 
			
		||||
	return q
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeParams(action string) map[string]string {
 | 
			
		||||
	params := make(map[string]string)
 | 
			
		||||
	params["Action"] = action
 | 
			
		||||
	return params
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// ELB objects
 | 
			
		||||
 | 
			
		||||
// A listener attaches to an elb
 | 
			
		||||
type Listener struct {
 | 
			
		||||
	InstancePort     int64  `xml:"Listener>InstancePort"`
 | 
			
		||||
	InstanceProtocol string `xml:"Listener>InstanceProtocol"`
 | 
			
		||||
	SSLCertificateId string `xml:"Listener>SSLCertificateId"`
 | 
			
		||||
	LoadBalancerPort int64  `xml:"Listener>LoadBalancerPort"`
 | 
			
		||||
	Protocol         string `xml:"Listener>Protocol"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An Instance attaches to an elb
 | 
			
		||||
type Instance struct {
 | 
			
		||||
	InstanceId string `xml:"InstanceId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A tag attached to an elb
 | 
			
		||||
type Tag struct {
 | 
			
		||||
	Key   string `xml:"Key"`
 | 
			
		||||
	Value string `xml:"Value"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An InstanceState from an elb health query
 | 
			
		||||
type InstanceState struct {
 | 
			
		||||
	InstanceId  string `xml:"InstanceId"`
 | 
			
		||||
	Description string `xml:"Description"`
 | 
			
		||||
	State       string `xml:"State"`
 | 
			
		||||
	ReasonCode  string `xml:"ReasonCode"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// AddTags
 | 
			
		||||
 | 
			
		||||
type AddTags struct {
 | 
			
		||||
	LoadBalancerNames []string
 | 
			
		||||
	Tags              []Tag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AddTagsResp struct {
 | 
			
		||||
	RequestId string `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) AddTags(options *AddTags) (resp *AddTagsResp, err error) {
 | 
			
		||||
	params := makeParams("AddTags")
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.LoadBalancerNames {
 | 
			
		||||
		params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Tags {
 | 
			
		||||
		params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v.Key
 | 
			
		||||
		params["Tags.member."+strconv.Itoa(i+1)+".Value"] = v.Value
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &AddTagsResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	return resp, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// RemoveTags
 | 
			
		||||
 | 
			
		||||
type RemoveTags struct {
 | 
			
		||||
	LoadBalancerNames []string
 | 
			
		||||
	TagKeys           []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RemoveTagsResp struct {
 | 
			
		||||
	RequestId string `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) RemoveTags(options *RemoveTags) (resp *RemoveTagsResp, err error) {
 | 
			
		||||
	params := makeParams("RemoveTags")
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.LoadBalancerNames {
 | 
			
		||||
		params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.TagKeys {
 | 
			
		||||
		params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &RemoveTagsResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	return resp, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Create
 | 
			
		||||
 | 
			
		||||
// The CreateLoadBalancer request parameters
 | 
			
		||||
type CreateLoadBalancer struct {
 | 
			
		||||
	AvailZone        []string
 | 
			
		||||
	Listeners        []Listener
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
	Internal         bool // true for vpc elbs
 | 
			
		||||
	SecurityGroups   []string
 | 
			
		||||
	Subnets          []string
 | 
			
		||||
	Tags             []Tag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateLoadBalancerResp struct {
 | 
			
		||||
	DNSName   string `xml:"CreateLoadBalancerResult>DNSName"`
 | 
			
		||||
	RequestId string `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) CreateLoadBalancer(options *CreateLoadBalancer) (resp *CreateLoadBalancerResp, err error) {
 | 
			
		||||
	params := makeParams("CreateLoadBalancer")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.AvailZone {
 | 
			
		||||
		params["AvailabilityZones.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.SecurityGroups {
 | 
			
		||||
		params["SecurityGroups.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Subnets {
 | 
			
		||||
		params["Subnets.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Listeners {
 | 
			
		||||
		params["Listeners.member."+strconv.Itoa(i+1)+".LoadBalancerPort"] = strconv.FormatInt(v.LoadBalancerPort, 10)
 | 
			
		||||
		params["Listeners.member."+strconv.Itoa(i+1)+".InstancePort"] = strconv.FormatInt(v.InstancePort, 10)
 | 
			
		||||
		params["Listeners.member."+strconv.Itoa(i+1)+".Protocol"] = v.Protocol
 | 
			
		||||
		params["Listeners.member."+strconv.Itoa(i+1)+".InstanceProtocol"] = v.InstanceProtocol
 | 
			
		||||
		params["Listeners.member."+strconv.Itoa(i+1)+".SSLCertificateId"] = v.SSLCertificateId
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Tags {
 | 
			
		||||
		params["Tags.member."+strconv.Itoa(i+1)+".Key"] = v.Key
 | 
			
		||||
		params["Tags.member."+strconv.Itoa(i+1)+".Value"] = v.Value
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if options.Internal {
 | 
			
		||||
		params["Scheme"] = "internal"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &CreateLoadBalancerResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Destroy
 | 
			
		||||
 | 
			
		||||
// The DestroyLoadBalancer request parameters
 | 
			
		||||
type DeleteLoadBalancer struct {
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) DeleteLoadBalancer(options *DeleteLoadBalancer) (resp *SimpleResp, err error) {
 | 
			
		||||
	params := makeParams("DeleteLoadBalancer")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
 | 
			
		||||
	resp = &SimpleResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Describe
 | 
			
		||||
 | 
			
		||||
// An individual load balancer
 | 
			
		||||
type LoadBalancer struct {
 | 
			
		||||
	LoadBalancerName  string      `xml:"LoadBalancerName"`
 | 
			
		||||
	Listeners         []Listener  `xml:"ListenerDescriptions>member"`
 | 
			
		||||
	Instances         []Instance  `xml:"Instances>member"`
 | 
			
		||||
	HealthCheck       HealthCheck `xml:"HealthCheck"`
 | 
			
		||||
	AvailabilityZones []string    `xml:"AvailabilityZones>member"`
 | 
			
		||||
	HostedZoneNameID  string      `xml:"CanonicalHostedZoneNameID"`
 | 
			
		||||
	DNSName           string      `xml:"DNSName"`
 | 
			
		||||
	SecurityGroups    []string    `xml:"SecurityGroups>member"`
 | 
			
		||||
	Scheme            string      `xml:"Scheme"`
 | 
			
		||||
	Subnets           []string    `xml:"Subnets>member"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DescribeLoadBalancer request params
 | 
			
		||||
type DescribeLoadBalancer struct {
 | 
			
		||||
	Names []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DescribeLoadBalancersResp struct {
 | 
			
		||||
	RequestId     string         `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
	LoadBalancers []LoadBalancer `xml:"DescribeLoadBalancersResult>LoadBalancerDescriptions>member"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) DescribeLoadBalancers(options *DescribeLoadBalancer) (resp *DescribeLoadBalancersResp, err error) {
 | 
			
		||||
	params := makeParams("DescribeLoadBalancers")
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Names {
 | 
			
		||||
		params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &DescribeLoadBalancersResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Attributes
 | 
			
		||||
 | 
			
		||||
type AccessLog struct {
 | 
			
		||||
	EmitInterval   int64
 | 
			
		||||
	Enabled        bool
 | 
			
		||||
	S3BucketName   string
 | 
			
		||||
	S3BucketPrefix string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ConnectionDraining struct {
 | 
			
		||||
	Enabled bool
 | 
			
		||||
	Timeout int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LoadBalancerAttributes struct {
 | 
			
		||||
	CrossZoneLoadBalancingEnabled bool
 | 
			
		||||
	ConnectionSettingsIdleTimeout int64
 | 
			
		||||
	ConnectionDraining            ConnectionDraining
 | 
			
		||||
	AccessLog                     AccessLog
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ModifyLoadBalancerAttributes struct {
 | 
			
		||||
	LoadBalancerName       string
 | 
			
		||||
	LoadBalancerAttributes LoadBalancerAttributes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) ModifyLoadBalancerAttributes(options *ModifyLoadBalancerAttributes) (resp *SimpleResp, err error) {
 | 
			
		||||
	params := makeParams("ModifyLoadBalancerAttributes")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
	params["LoadBalancerAttributes.CrossZoneLoadBalancing.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.CrossZoneLoadBalancingEnabled)
 | 
			
		||||
	if options.LoadBalancerAttributes.ConnectionSettingsIdleTimeout > 0 {
 | 
			
		||||
		params["LoadBalancerAttributes.ConnectionSettings.IdleTimeout"] = strconv.Itoa(int(options.LoadBalancerAttributes.ConnectionSettingsIdleTimeout))
 | 
			
		||||
	}
 | 
			
		||||
	if options.LoadBalancerAttributes.ConnectionDraining.Timeout > 0 {
 | 
			
		||||
		params["LoadBalancerAttributes.ConnectionDraining.Timeout"] = strconv.Itoa(int(options.LoadBalancerAttributes.ConnectionDraining.Timeout))
 | 
			
		||||
	}
 | 
			
		||||
	params["LoadBalancerAttributes.ConnectionDraining.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.ConnectionDraining.Enabled)
 | 
			
		||||
	params["LoadBalancerAttributes.AccessLog.Enabled"] = strconv.FormatBool(options.LoadBalancerAttributes.AccessLog.Enabled)
 | 
			
		||||
	if options.LoadBalancerAttributes.AccessLog.Enabled {
 | 
			
		||||
		params["LoadBalancerAttributes.AccessLog.EmitInterval"] = strconv.Itoa(int(options.LoadBalancerAttributes.AccessLog.EmitInterval))
 | 
			
		||||
		params["LoadBalancerAttributes.AccessLog.S3BucketName"] = options.LoadBalancerAttributes.AccessLog.S3BucketName
 | 
			
		||||
		params["LoadBalancerAttributes.AccessLog.S3BucketPrefix"] = options.LoadBalancerAttributes.AccessLog.S3BucketPrefix
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &SimpleResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Instance Registration / deregistration
 | 
			
		||||
 | 
			
		||||
// The RegisterInstancesWithLoadBalancer request parameters
 | 
			
		||||
type RegisterInstancesWithLoadBalancer struct {
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
	Instances        []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterInstancesWithLoadBalancerResp struct {
 | 
			
		||||
	Instances []Instance `xml:"RegisterInstancesWithLoadBalancerResult>Instances>member"`
 | 
			
		||||
	RequestId string     `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) RegisterInstancesWithLoadBalancer(options *RegisterInstancesWithLoadBalancer) (resp *RegisterInstancesWithLoadBalancerResp, err error) {
 | 
			
		||||
	params := makeParams("RegisterInstancesWithLoadBalancer")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Instances {
 | 
			
		||||
		params["Instances.member."+strconv.Itoa(i+1)+".InstanceId"] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &RegisterInstancesWithLoadBalancerResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The DeregisterInstancesFromLoadBalancer request parameters
 | 
			
		||||
type DeregisterInstancesFromLoadBalancer struct {
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
	Instances        []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DeregisterInstancesFromLoadBalancerResp struct {
 | 
			
		||||
	Instances []Instance `xml:"DeregisterInstancesFromLoadBalancerResult>Instances>member"`
 | 
			
		||||
	RequestId string     `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) DeregisterInstancesFromLoadBalancer(options *DeregisterInstancesFromLoadBalancer) (resp *DeregisterInstancesFromLoadBalancerResp, err error) {
 | 
			
		||||
	params := makeParams("DeregisterInstancesFromLoadBalancer")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.Instances {
 | 
			
		||||
		params["Instances.member."+strconv.Itoa(i+1)+".InstanceId"] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &DeregisterInstancesFromLoadBalancerResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// DescribeTags
 | 
			
		||||
 | 
			
		||||
type DescribeTags struct {
 | 
			
		||||
	LoadBalancerNames []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type LoadBalancerTag struct {
 | 
			
		||||
	Tags             []Tag  `xml:"Tags>member"`
 | 
			
		||||
	LoadBalancerName string `xml:"LoadBalancerName"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DescribeTagsResp struct {
 | 
			
		||||
	LoadBalancerTags []LoadBalancerTag `xml:"DescribeTagsResult>TagDescriptions>member"`
 | 
			
		||||
	NextToken        string            `xml:"DescribeTagsResult>NextToken"`
 | 
			
		||||
	RequestId        string            `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) DescribeTags(options *DescribeTags) (resp *DescribeTagsResp, err error) {
 | 
			
		||||
	params := makeParams("DescribeTags")
 | 
			
		||||
 | 
			
		||||
	for i, v := range options.LoadBalancerNames {
 | 
			
		||||
		params["LoadBalancerNames.member."+strconv.Itoa(i+1)] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp = &DescribeTagsResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Health Checks
 | 
			
		||||
 | 
			
		||||
type HealthCheck struct {
 | 
			
		||||
	HealthyThreshold   int64  `xml:"HealthyThreshold"`
 | 
			
		||||
	UnhealthyThreshold int64  `xml:"UnhealthyThreshold"`
 | 
			
		||||
	Interval           int64  `xml:"Interval"`
 | 
			
		||||
	Target             string `xml:"Target"`
 | 
			
		||||
	Timeout            int64  `xml:"Timeout"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ConfigureHealthCheck struct {
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
	Check            HealthCheck
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ConfigureHealthCheckResp struct {
 | 
			
		||||
	Check     HealthCheck `xml:"ConfigureHealthCheckResult>HealthCheck"`
 | 
			
		||||
	RequestId string      `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) ConfigureHealthCheck(options *ConfigureHealthCheck) (resp *ConfigureHealthCheckResp, err error) {
 | 
			
		||||
	params := makeParams("ConfigureHealthCheck")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
	params["HealthCheck.HealthyThreshold"] = strconv.Itoa(int(options.Check.HealthyThreshold))
 | 
			
		||||
	params["HealthCheck.UnhealthyThreshold"] = strconv.Itoa(int(options.Check.UnhealthyThreshold))
 | 
			
		||||
	params["HealthCheck.Interval"] = strconv.Itoa(int(options.Check.Interval))
 | 
			
		||||
	params["HealthCheck.Target"] = options.Check.Target
 | 
			
		||||
	params["HealthCheck.Timeout"] = strconv.Itoa(int(options.Check.Timeout))
 | 
			
		||||
 | 
			
		||||
	resp = &ConfigureHealthCheckResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Instance Health
 | 
			
		||||
 | 
			
		||||
// The DescribeInstanceHealth request parameters
 | 
			
		||||
type DescribeInstanceHealth struct {
 | 
			
		||||
	LoadBalancerName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DescribeInstanceHealthResp struct {
 | 
			
		||||
	InstanceStates []InstanceState `xml:"DescribeInstanceHealthResult>InstanceStates>member"`
 | 
			
		||||
	RequestId      string          `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (elb *ELB) DescribeInstanceHealth(options *DescribeInstanceHealth) (resp *DescribeInstanceHealthResp, err error) {
 | 
			
		||||
	params := makeParams("DescribeInstanceHealth")
 | 
			
		||||
 | 
			
		||||
	params["LoadBalancerName"] = options.LoadBalancerName
 | 
			
		||||
 | 
			
		||||
	resp = &DescribeInstanceHealthResp{}
 | 
			
		||||
 | 
			
		||||
	err = elb.query(params, resp)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		resp = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Responses
 | 
			
		||||
 | 
			
		||||
type SimpleResp struct {
 | 
			
		||||
	RequestId string `xml:"ResponseMetadata>RequestId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type xmlErrors struct {
 | 
			
		||||
	Errors []Error `xml:"Error"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error encapsulates an elb error.
 | 
			
		||||
type Error struct {
 | 
			
		||||
	// HTTP status code of the error.
 | 
			
		||||
	StatusCode int
 | 
			
		||||
 | 
			
		||||
	// AWS code of the error.
 | 
			
		||||
	Code string
 | 
			
		||||
 | 
			
		||||
	// Message explaining the error.
 | 
			
		||||
	Message string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Error) Error() string {
 | 
			
		||||
	var prefix string
 | 
			
		||||
	if e.Code != "" {
 | 
			
		||||
		prefix = e.Code + ": "
 | 
			
		||||
	}
 | 
			
		||||
	if prefix == "" && e.StatusCode > 0 {
 | 
			
		||||
		prefix = strconv.Itoa(e.StatusCode) + ": "
 | 
			
		||||
	}
 | 
			
		||||
	return prefix + e.Message
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										235
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										235
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/elb_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,235 +0,0 @@
 | 
			
		||||
package elb_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/mitchellh/goamz/aws"
 | 
			
		||||
	"github.com/mitchellh/goamz/elb"
 | 
			
		||||
	"github.com/mitchellh/goamz/testutil"
 | 
			
		||||
	. "github.com/motain/gocheck"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Test(t *testing.T) {
 | 
			
		||||
	TestingT(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type S struct {
 | 
			
		||||
	elb *elb.ELB
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ = Suite(&S{})
 | 
			
		||||
 | 
			
		||||
var testServer = testutil.NewHTTPServer()
 | 
			
		||||
 | 
			
		||||
func (s *S) SetUpSuite(c *C) {
 | 
			
		||||
	testServer.Start()
 | 
			
		||||
	auth := aws.Auth{"abc", "123", ""}
 | 
			
		||||
	s.elb = elb.NewWithClient(auth, aws.Region{ELBEndpoint: testServer.URL}, testutil.DefaultClient)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TearDownTest(c *C) {
 | 
			
		||||
	testServer.Flush()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestAddTags(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, AddTagsExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.AddTags{
 | 
			
		||||
		LoadBalancerNames: []string{"foobar"},
 | 
			
		||||
		Tags: []elb.Tag{
 | 
			
		||||
			{
 | 
			
		||||
				Key:   "hello",
 | 
			
		||||
				Value: "world",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.AddTags(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"AddTags"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerNames.member.1"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(req.Form["Tags.member.1.Key"], DeepEquals, []string{"hello"})
 | 
			
		||||
	c.Assert(req.Form["Tags.member.1.Value"], DeepEquals, []string{"world"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "360e81f7-1100-11e4-b6ed-0f30EXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestRemoveTags(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, RemoveTagsExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.RemoveTags{
 | 
			
		||||
		LoadBalancerNames: []string{"foobar"},
 | 
			
		||||
		TagKeys:           []string{"hello"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.RemoveTags(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"RemoveTags"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerNames.member.1"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(req.Form["Tags.member.1.Key"], DeepEquals, []string{"hello"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestCreateLoadBalancer(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, CreateLoadBalancerExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.CreateLoadBalancer{
 | 
			
		||||
		AvailZone: []string{"us-east-1a"},
 | 
			
		||||
		Listeners: []elb.Listener{elb.Listener{
 | 
			
		||||
			InstancePort:     80,
 | 
			
		||||
			InstanceProtocol: "http",
 | 
			
		||||
			SSLCertificateId: "needToAddASSLCertToYourAWSAccount",
 | 
			
		||||
			LoadBalancerPort: 80,
 | 
			
		||||
			Protocol:         "http",
 | 
			
		||||
		},
 | 
			
		||||
		},
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
		Internal:         false,
 | 
			
		||||
		SecurityGroups:   []string{"sg1"},
 | 
			
		||||
		Subnets:          []string{"sn1"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.CreateLoadBalancer(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"CreateLoadBalancer"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestDeleteLoadBalancer(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, DeleteLoadBalancerExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.DeleteLoadBalancer{
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.DeleteLoadBalancer(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteLoadBalancer"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestDescribeLoadBalancers(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, DescribeLoadBalancersExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.DescribeLoadBalancer{
 | 
			
		||||
		Names: []string{"foobar"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.DescribeLoadBalancers(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeLoadBalancers"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].LoadBalancerName, Equals, "MyLoadBalancer")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].Listeners[0].Protocol, Equals, "HTTP")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].Instances[0].InstanceId, Equals, "i-e4cbe38d")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].AvailabilityZones[0].AvailabilityZone, Equals, "us-east-1a")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].Scheme, Equals, "internet-facing")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].DNSName, Equals, "MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].HealthCheck.HealthyThreshold, Equals, int64(2))
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].HealthCheck.UnhealthyThreshold, Equals, int64(10))
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].HealthCheck.Interval, Equals, int64(90))
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].HealthCheck.Target, Equals, "HTTP:80/")
 | 
			
		||||
	c.Assert(resp.LoadBalancers[0].HealthCheck.Timeout, Equals, int64(60))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestRegisterInstancesWithLoadBalancer(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, RegisterInstancesWithLoadBalancerExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.RegisterInstancesWithLoadBalancer{
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
		Instances:        []string{"instance-1", "instance-2"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.RegisterInstancesWithLoadBalancer(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"RegisterInstancesWithLoadBalancer"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(req.Form["Instances.member.1.InstanceId"], DeepEquals, []string{"instance-1"})
 | 
			
		||||
	c.Assert(req.Form["Instances.member.2.InstanceId"], DeepEquals, []string{"instance-2"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
 | 
			
		||||
	c.Assert(resp.Instances[0].InstanceId, Equals, "i-315b7e51")
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestDeregisterInstancesFromLoadBalancer(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, DeregisterInstancesFromLoadBalancerExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.DeregisterInstancesFromLoadBalancer{
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
		Instances:        []string{"instance-1", "instance-2"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.DeregisterInstancesFromLoadBalancer(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"DeregisterInstancesFromLoadBalancer"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(req.Form["Instances.member.1.InstanceId"], DeepEquals, []string{"instance-1"})
 | 
			
		||||
	c.Assert(req.Form["Instances.member.2.InstanceId"], DeepEquals, []string{"instance-2"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
 | 
			
		||||
	c.Assert(resp.Instances[0].InstanceId, Equals, "i-6ec63d59")
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestConfigureHealthCheck(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, ConfigureHealthCheckExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.ConfigureHealthCheck{
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
		Check: elb.HealthCheck{
 | 
			
		||||
			HealthyThreshold:   2,
 | 
			
		||||
			UnhealthyThreshold: 2,
 | 
			
		||||
			Interval:           30,
 | 
			
		||||
			Target:             "HTTP:80/ping",
 | 
			
		||||
			Timeout:            3,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.ConfigureHealthCheck(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"ConfigureHealthCheck"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
 | 
			
		||||
	c.Assert(resp.Check.HealthyThreshold, Equals, int64(2))
 | 
			
		||||
	c.Assert(resp.Check.UnhealthyThreshold, Equals, int64(2))
 | 
			
		||||
	c.Assert(resp.Check.Interval, Equals, int64(30))
 | 
			
		||||
	c.Assert(resp.Check.Target, Equals, "HTTP:80/ping")
 | 
			
		||||
	c.Assert(resp.Check.Timeout, Equals, int64(3))
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12EXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *S) TestDescribeInstanceHealth(c *C) {
 | 
			
		||||
	testServer.Response(200, nil, DescribeInstanceHealthExample)
 | 
			
		||||
 | 
			
		||||
	options := elb.DescribeInstanceHealth{
 | 
			
		||||
		LoadBalancerName: "foobar",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := s.elb.DescribeInstanceHealth(&options)
 | 
			
		||||
	req := testServer.WaitRequest()
 | 
			
		||||
 | 
			
		||||
	c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstanceHealth"})
 | 
			
		||||
	c.Assert(req.Form["LoadBalancerName"], DeepEquals, []string{"foobar"})
 | 
			
		||||
	c.Assert(err, IsNil)
 | 
			
		||||
 | 
			
		||||
	c.Assert(resp.InstanceStates[0].InstanceId, Equals, "i-90d8c2a5")
 | 
			
		||||
	c.Assert(resp.InstanceStates[0].State, Equals, "InService")
 | 
			
		||||
	c.Assert(resp.InstanceStates[1].InstanceId, Equals, "i-06ea3e60")
 | 
			
		||||
	c.Assert(resp.InstanceStates[1].State, Equals, "OutOfService")
 | 
			
		||||
	c.Assert(resp.RequestId, Equals, "1549581b-12b7-11e3-895e-1334aEXAMPLE")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										182
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/responses_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										182
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/responses_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,182 +0,0 @@
 | 
			
		||||
package elb_test
 | 
			
		||||
 | 
			
		||||
var ErrorDump = `
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<Response><Errors><Error><Code>UnsupportedOperation</Code>
 | 
			
		||||
<Message></Message>
 | 
			
		||||
</Error></Errors><RequestID>0503f4e9-bbd6-483c-b54f-c4ae9f3b30f4</RequestID></Response>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/OkMdtJ
 | 
			
		||||
var AddTagsExample = `
 | 
			
		||||
<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <AddTagsResult/>
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
    <RequestId>360e81f7-1100-11e4-b6ed-0f30EXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</AddTagsResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/nT2E89
 | 
			
		||||
var RemoveTagsExample = `
 | 
			
		||||
<RemoveTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <RemoveTagsResult/>
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
    <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</RemoveTagsResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/gQRD2H
 | 
			
		||||
var CreateLoadBalancerExample = `
 | 
			
		||||
<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <CreateLoadBalancerResult>
 | 
			
		||||
    <DNSName>MyLoadBalancer-1234567890.us-east-1.elb.amazonaws.com</DNSName>
 | 
			
		||||
  </CreateLoadBalancerResult>
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</CreateLoadBalancerResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/GLZeBN
 | 
			
		||||
var DeleteLoadBalancerExample = `
 | 
			
		||||
<DeleteLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</DeleteLoadBalancerResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/8UgpQ8
 | 
			
		||||
var DescribeLoadBalancersExample = `
 | 
			
		||||
<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <DescribeLoadBalancersResult>
 | 
			
		||||
      <LoadBalancerDescriptions>
 | 
			
		||||
        <member>
 | 
			
		||||
          <SecurityGroups/>
 | 
			
		||||
          <LoadBalancerName>MyLoadBalancer</LoadBalancerName>
 | 
			
		||||
          <CreatedTime>2013-05-24T21:15:31.280Z</CreatedTime>
 | 
			
		||||
          <HealthCheck>
 | 
			
		||||
            <Interval>90</Interval>
 | 
			
		||||
            <Target>HTTP:80/</Target>
 | 
			
		||||
            <HealthyThreshold>2</HealthyThreshold>
 | 
			
		||||
            <Timeout>60</Timeout>
 | 
			
		||||
            <UnhealthyThreshold>10</UnhealthyThreshold>
 | 
			
		||||
          </HealthCheck>
 | 
			
		||||
          <ListenerDescriptions>
 | 
			
		||||
            <member>
 | 
			
		||||
              <PolicyNames/>
 | 
			
		||||
              <Listener>
 | 
			
		||||
                <Protocol>HTTP</Protocol>
 | 
			
		||||
                <LoadBalancerPort>80</LoadBalancerPort>
 | 
			
		||||
                <InstanceProtocol>HTTP</InstanceProtocol>
 | 
			
		||||
                <SSLCertificateId>needToAddASSLCertToYourAWSAccount</SSLCertificateId>
 | 
			
		||||
                <InstancePort>80</InstancePort>
 | 
			
		||||
              </Listener>
 | 
			
		||||
            </member>
 | 
			
		||||
          </ListenerDescriptions>
 | 
			
		||||
          <Instances>
 | 
			
		||||
            <member>
 | 
			
		||||
              <InstanceId>i-e4cbe38d</InstanceId>
 | 
			
		||||
            </member>
 | 
			
		||||
          </Instances>
 | 
			
		||||
          <Policies>
 | 
			
		||||
            <AppCookieStickinessPolicies/>
 | 
			
		||||
            <OtherPolicies/>
 | 
			
		||||
            <LBCookieStickinessPolicies/>
 | 
			
		||||
          </Policies>
 | 
			
		||||
          <AvailabilityZones>
 | 
			
		||||
            <member>us-east-1a</member>
 | 
			
		||||
          </AvailabilityZones>
 | 
			
		||||
          <CanonicalHostedZoneNameID>ZZZZZZZZZZZ123X</CanonicalHostedZoneNameID>
 | 
			
		||||
          <CanonicalHostedZoneName>MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com</CanonicalHostedZoneName>
 | 
			
		||||
          <Scheme>internet-facing</Scheme>
 | 
			
		||||
          <SourceSecurityGroup>
 | 
			
		||||
            <OwnerAlias>amazon-elb</OwnerAlias>
 | 
			
		||||
            <GroupName>amazon-elb-sg</GroupName>
 | 
			
		||||
          </SourceSecurityGroup>
 | 
			
		||||
          <DNSName>MyLoadBalancer-123456789.us-east-1.elb.amazonaws.com</DNSName>
 | 
			
		||||
          <BackendServerDescriptions/>
 | 
			
		||||
          <Subnets/>
 | 
			
		||||
        </member>
 | 
			
		||||
      </LoadBalancerDescriptions>
 | 
			
		||||
    </DescribeLoadBalancersResult>
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
      <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</DescribeLoadBalancersResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/Uz1N66
 | 
			
		||||
var RegisterInstancesWithLoadBalancerExample = `
 | 
			
		||||
<RegisterInstancesWithLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <RegisterInstancesWithLoadBalancerResult>
 | 
			
		||||
    <Instances>
 | 
			
		||||
      <member>
 | 
			
		||||
        <InstanceId>i-315b7e51</InstanceId>
 | 
			
		||||
      </member>
 | 
			
		||||
    </Instances>
 | 
			
		||||
  </RegisterInstancesWithLoadBalancerResult>
 | 
			
		||||
<ResponseMetadata>
 | 
			
		||||
    <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
 | 
			
		||||
</ResponseMetadata>
 | 
			
		||||
</RegisterInstancesWithLoadBalancerResponse>
 | 
			
		||||
 `
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/5OMv62
 | 
			
		||||
var DeregisterInstancesFromLoadBalancerExample = `
 | 
			
		||||
<DeregisterInstancesFromLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <DeregisterInstancesFromLoadBalancerResult>
 | 
			
		||||
    <Instances>
 | 
			
		||||
      <member>
 | 
			
		||||
        <InstanceId>i-6ec63d59</InstanceId>
 | 
			
		||||
      </member>
 | 
			
		||||
    </Instances>
 | 
			
		||||
  </DeregisterInstancesFromLoadBalancerResult>
 | 
			
		||||
<ResponseMetadata>
 | 
			
		||||
    <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
 | 
			
		||||
</ResponseMetadata>
 | 
			
		||||
</DeregisterInstancesFromLoadBalancerResponse>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/API_ConfigureHealthCheck.html
 | 
			
		||||
var ConfigureHealthCheckExample = `
 | 
			
		||||
<ConfigureHealthCheckResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
<ConfigureHealthCheckResult>
 | 
			
		||||
    <HealthCheck>
 | 
			
		||||
      <Interval>30</Interval>
 | 
			
		||||
      <Target>HTTP:80/ping</Target>
 | 
			
		||||
      <HealthyThreshold>2</HealthyThreshold>
 | 
			
		||||
      <Timeout>3</Timeout>
 | 
			
		||||
      <UnhealthyThreshold>2</UnhealthyThreshold>
 | 
			
		||||
    </HealthCheck>
 | 
			
		||||
</ConfigureHealthCheckResult>
 | 
			
		||||
<ResponseMetadata>
 | 
			
		||||
    <RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
 | 
			
		||||
</ResponseMetadata>
 | 
			
		||||
</ConfigureHealthCheckResponse>`
 | 
			
		||||
 | 
			
		||||
// http://goo.gl/cGNxfj
 | 
			
		||||
var DescribeInstanceHealthExample = `
 | 
			
		||||
<DescribeInstanceHealthResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
 | 
			
		||||
  <DescribeInstanceHealthResult>
 | 
			
		||||
    <InstanceStates>
 | 
			
		||||
      <member>
 | 
			
		||||
        <Description>N/A</Description>
 | 
			
		||||
        <InstanceId>i-90d8c2a5</InstanceId>
 | 
			
		||||
        <State>InService</State>
 | 
			
		||||
        <ReasonCode>N/A</ReasonCode>
 | 
			
		||||
      </member>
 | 
			
		||||
      <member>
 | 
			
		||||
        <Description>N/A</Description>
 | 
			
		||||
        <InstanceId>i-06ea3e60</InstanceId>
 | 
			
		||||
        <State>OutOfService</State>
 | 
			
		||||
        <ReasonCode>N/A</ReasonCode>
 | 
			
		||||
      </member>
 | 
			
		||||
    </InstanceStates>
 | 
			
		||||
  </DescribeInstanceHealthResult>
 | 
			
		||||
  <ResponseMetadata>
 | 
			
		||||
    <RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
 | 
			
		||||
  </ResponseMetadata>
 | 
			
		||||
</DescribeInstanceHealthResponse>`
 | 
			
		||||
							
								
								
									
										38
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/sign.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								Godeps/_workspace/src/github.com/mitchellh/goamz/elb/sign.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,38 +0,0 @@
 | 
			
		||||
package elb
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/hmac"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"github.com/mitchellh/goamz/aws"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------
 | 
			
		||||
// Version 2 signing (http://goo.gl/RSRp5)
 | 
			
		||||
 | 
			
		||||
var b64 = base64.StdEncoding
 | 
			
		||||
 | 
			
		||||
func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
 | 
			
		||||
	params["AWSAccessKeyId"] = auth.AccessKey
 | 
			
		||||
	params["SignatureVersion"] = "2"
 | 
			
		||||
	params["SignatureMethod"] = "HmacSHA256"
 | 
			
		||||
	if auth.Token != "" {
 | 
			
		||||
		params["SecurityToken"] = auth.Token
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sarray []string
 | 
			
		||||
	for k, v := range params {
 | 
			
		||||
		sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v))
 | 
			
		||||
	}
 | 
			
		||||
	sort.StringSlice(sarray).Sort()
 | 
			
		||||
	joined := strings.Join(sarray, "&")
 | 
			
		||||
	payload := method + "\n" + host + "\n" + path + "\n" + joined
 | 
			
		||||
	hash := hmac.New(sha256.New, []byte(auth.SecretKey))
 | 
			
		||||
	hash.Write([]byte(payload))
 | 
			
		||||
	signature := make([]byte, b64.EncodedLen(hash.Size()))
 | 
			
		||||
	b64.Encode(signature, hash.Sum(nil))
 | 
			
		||||
 | 
			
		||||
	params["Signature"] = string(signature)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user