Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Aaron Lehmann authored on 2017/06/16 03:11:48... | ... |
@@ -191,9 +191,9 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
191 | 191 |
"name": s.File.Name, |
192 | 192 |
"path": fPath, |
193 | 193 |
}).Debug("injecting secret") |
194 |
- secret := c.DependencyStore.Secrets().Get(s.SecretID) |
|
195 |
- if secret == nil { |
|
196 |
- return fmt.Errorf("unable to get secret from secret store") |
|
194 |
+ secret, err := c.DependencyStore.Secrets().Get(s.SecretID) |
|
195 |
+ if err != nil { |
|
196 |
+ return errors.Wrap(err, "unable to get secret from secret store") |
|
197 | 197 |
} |
198 | 198 |
if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil { |
199 | 199 |
return errors.Wrap(err, "error injecting secret") |
... | ... |
@@ -266,9 +266,9 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { |
266 | 266 |
} |
267 | 267 |
|
268 | 268 |
log.Debug("injecting config") |
269 |
- config := c.DependencyStore.Configs().Get(configRef.ConfigID) |
|
270 |
- if config == nil { |
|
271 |
- return fmt.Errorf("unable to get config from config store") |
|
269 |
+ config, err := c.DependencyStore.Configs().Get(configRef.ConfigID) |
|
270 |
+ if err != nil { |
|
271 |
+ return errors.Wrap(err, "unable to get config from config store") |
|
272 | 272 |
} |
273 | 273 |
if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil { |
274 | 274 |
return errors.Wrap(err, "error injecting config") |
... | ... |
@@ -53,9 +53,9 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) { |
53 | 53 |
log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath}) |
54 | 54 |
|
55 | 55 |
log.Debug("injecting config") |
56 |
- config := c.DependencyStore.Configs().Get(configRef.ConfigID) |
|
57 |
- if config == nil { |
|
58 |
- return fmt.Errorf("unable to get config from config store") |
|
56 |
+ config, err := c.DependencyStore.Configs().Get(configRef.ConfigID) |
|
57 |
+ if err != nil { |
|
58 |
+ return errors.Wrap(err, "unable to get config from config store") |
|
59 | 59 |
} |
60 | 60 |
if err := ioutil.WriteFile(fPath, config.Spec.Data, configRef.File.Mode); err != nil { |
61 | 61 |
return errors.Wrap(err, "error injecting config") |
... | ... |
@@ -128,9 +128,9 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) { |
128 | 128 |
"name": s.File.Name, |
129 | 129 |
"path": fPath, |
130 | 130 |
}).Debug("injecting secret") |
131 |
- secret := c.DependencyStore.Secrets().Get(s.SecretID) |
|
132 |
- if secret == nil { |
|
133 |
- return fmt.Errorf("unable to get secret from secret store") |
|
131 |
+ secret, err := c.DependencyStore.Secrets().Get(s.SecretID) |
|
132 |
+ if err != nil { |
|
133 |
+ return errors.Wrap(err, "unable to get secret from secret store") |
|
134 | 134 |
} |
135 | 135 |
if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil { |
136 | 136 |
return errors.Wrap(err, "error injecting secret") |
... | ... |
@@ -104,7 +104,7 @@ github.com/containerd/containerd 3addd840653146c90a254301d6c3a663c7fd6429 |
104 | 104 |
github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4 |
105 | 105 |
|
106 | 106 |
# cluster |
107 |
-github.com/docker/swarmkit a4bf0135f63fb60f0e76ae81579cde87f580db6e |
|
107 |
+github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb |
|
108 | 108 |
github.com/gogo/protobuf v0.4 |
109 | 109 |
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a |
110 | 110 |
github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e |
... | ... |
@@ -1,6 +1,7 @@ |
1 | 1 |
package configs |
2 | 2 |
|
3 | 3 |
import ( |
4 |
+ "fmt" |
|
4 | 5 |
"sync" |
5 | 6 |
|
6 | 7 |
"github.com/docker/swarmkit/agent/exec" |
... | ... |
@@ -22,13 +23,13 @@ func NewManager() exec.ConfigsManager { |
22 | 22 |
} |
23 | 23 |
|
24 | 24 |
// Get returns a config by ID. If the config doesn't exist, returns nil. |
25 |
-func (r *configs) Get(configID string) *api.Config { |
|
25 |
+func (r *configs) Get(configID string) (*api.Config, error) { |
|
26 | 26 |
r.mu.RLock() |
27 | 27 |
defer r.mu.RUnlock() |
28 | 28 |
if r, ok := r.m[configID]; ok { |
29 |
- return r |
|
29 |
+ return r, nil |
|
30 | 30 |
} |
31 |
- return nil |
|
31 |
+ return nil, fmt.Errorf("config %s not found", configID) |
|
32 | 32 |
} |
33 | 33 |
|
34 | 34 |
// Add adds one or more configs to the config map. |
... | ... |
@@ -63,9 +64,9 @@ type taskRestrictedConfigsProvider struct { |
63 | 63 |
configIDs map[string]struct{} // allow list of config ids |
64 | 64 |
} |
65 | 65 |
|
66 |
-func (sp *taskRestrictedConfigsProvider) Get(configID string) *api.Config { |
|
66 |
+func (sp *taskRestrictedConfigsProvider) Get(configID string) (*api.Config, error) { |
|
67 | 67 |
if _, ok := sp.configIDs[configID]; !ok { |
68 |
- return nil |
|
68 |
+ return nil, fmt.Errorf("task not authorized to access config %s", configID) |
|
69 | 69 |
} |
70 | 70 |
|
71 | 71 |
return sp.configs.Get(configID) |
... | ... |
@@ -52,7 +52,7 @@ type DependencyGetter interface { |
52 | 52 |
type SecretGetter interface { |
53 | 53 |
// Get returns the the secret with a specific secret ID, if available. |
54 | 54 |
// When the secret is not available, the return will be nil. |
55 |
- Get(secretID string) *api.Secret |
|
55 |
+ Get(secretID string) (*api.Secret, error) |
|
56 | 56 |
} |
57 | 57 |
|
58 | 58 |
// SecretsManager is the interface for secret storage and updates. |
... | ... |
@@ -68,7 +68,7 @@ type SecretsManager interface { |
68 | 68 |
type ConfigGetter interface { |
69 | 69 |
// Get returns the the config with a specific config ID, if available. |
70 | 70 |
// When the config is not available, the return will be nil. |
71 |
- Get(configID string) *api.Config |
|
71 |
+ Get(configID string) (*api.Config, error) |
|
72 | 72 |
} |
73 | 73 |
|
74 | 74 |
// ConfigsManager is the interface for config storage and updates. |
... | ... |
@@ -1,6 +1,7 @@ |
1 | 1 |
package secrets |
2 | 2 |
|
3 | 3 |
import ( |
4 |
+ "fmt" |
|
4 | 5 |
"sync" |
5 | 6 |
|
6 | 7 |
"github.com/docker/swarmkit/agent/exec" |
... | ... |
@@ -22,13 +23,13 @@ func NewManager() exec.SecretsManager { |
22 | 22 |
} |
23 | 23 |
|
24 | 24 |
// Get returns a secret by ID. If the secret doesn't exist, returns nil. |
25 |
-func (s *secrets) Get(secretID string) *api.Secret { |
|
25 |
+func (s *secrets) Get(secretID string) (*api.Secret, error) { |
|
26 | 26 |
s.mu.RLock() |
27 | 27 |
defer s.mu.RUnlock() |
28 | 28 |
if s, ok := s.m[secretID]; ok { |
29 |
- return s |
|
29 |
+ return s, nil |
|
30 | 30 |
} |
31 |
- return nil |
|
31 |
+ return nil, fmt.Errorf("secret %s not found", secretID) |
|
32 | 32 |
} |
33 | 33 |
|
34 | 34 |
// Add adds one or more secrets to the secret map. |
... | ... |
@@ -63,9 +64,9 @@ type taskRestrictedSecretsProvider struct { |
63 | 63 |
secretIDs map[string]struct{} // allow list of secret ids |
64 | 64 |
} |
65 | 65 |
|
66 |
-func (sp *taskRestrictedSecretsProvider) Get(secretID string) *api.Secret { |
|
66 |
+func (sp *taskRestrictedSecretsProvider) Get(secretID string) (*api.Secret, error) { |
|
67 | 67 |
if _, ok := sp.secretIDs[secretID]; !ok { |
68 |
- return nil |
|
68 |
+ return nil, fmt.Errorf("task not authorized to access secret %s", secretID) |
|
69 | 69 |
} |
70 | 70 |
|
71 | 71 |
return sp.secrets.Get(secretID) |
... | ... |
@@ -760,6 +760,12 @@ type SecretSpec struct { |
760 | 760 |
Annotations Annotations `protobuf:"bytes,1,opt,name=annotations" json:"annotations"` |
761 | 761 |
// Data is the secret payload - the maximum size is 500KB (that is, 500*1024 bytes) |
762 | 762 |
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` |
763 |
+ // Templating controls whether and how to evaluate the secret payload as |
|
764 |
+ // a template. If it is not set, no templating is used. |
|
765 |
+ // |
|
766 |
+ // The currently recognized values are: |
|
767 |
+ // - golang: Go templating |
|
768 |
+ Templating *Driver `protobuf:"bytes,3,opt,name=templating" json:"templating,omitempty"` |
|
763 | 769 |
} |
764 | 770 |
|
765 | 771 |
func (m *SecretSpec) Reset() { *m = SecretSpec{} } |
... | ... |
@@ -773,6 +779,12 @@ type ConfigSpec struct { |
773 | 773 |
// TODO(aaronl): Do we want to revise this to include multiple payloads in a single |
774 | 774 |
// ConfigSpec? Define this to be a tar? etc... |
775 | 775 |
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` |
776 |
+ // Templating controls whether and how to evaluate the secret payload as |
|
777 |
+ // a template. If it is not set, no templating is used. |
|
778 |
+ // |
|
779 |
+ // The currently recognized values are: |
|
780 |
+ // - golang: Go templating |
|
781 |
+ Templating *Driver `protobuf:"bytes,3,opt,name=templating" json:"templating,omitempty"` |
|
776 | 782 |
} |
777 | 783 |
|
778 | 784 |
func (m *ConfigSpec) Reset() { *m = ConfigSpec{} } |
... | ... |
@@ -1224,6 +1236,10 @@ func (m *SecretSpec) CopyFrom(src interface{}) { |
1224 | 1224 |
m.Data = make([]byte, len(o.Data)) |
1225 | 1225 |
copy(m.Data, o.Data) |
1226 | 1226 |
} |
1227 |
+ if o.Templating != nil { |
|
1228 |
+ m.Templating = &Driver{} |
|
1229 |
+ github_com_docker_swarmkit_api_deepcopy.Copy(m.Templating, o.Templating) |
|
1230 |
+ } |
|
1227 | 1231 |
} |
1228 | 1232 |
|
1229 | 1233 |
func (m *ConfigSpec) Copy() *ConfigSpec { |
... | ... |
@@ -1244,6 +1260,10 @@ func (m *ConfigSpec) CopyFrom(src interface{}) { |
1244 | 1244 |
m.Data = make([]byte, len(o.Data)) |
1245 | 1245 |
copy(m.Data, o.Data) |
1246 | 1246 |
} |
1247 |
+ if o.Templating != nil { |
|
1248 |
+ m.Templating = &Driver{} |
|
1249 |
+ github_com_docker_swarmkit_api_deepcopy.Copy(m.Templating, o.Templating) |
|
1250 |
+ } |
|
1247 | 1251 |
} |
1248 | 1252 |
|
1249 | 1253 |
func (m *NodeSpec) Marshal() (dAtA []byte, err error) { |
... | ... |
@@ -2227,6 +2247,16 @@ func (m *SecretSpec) MarshalTo(dAtA []byte) (int, error) { |
2227 | 2227 |
i = encodeVarintSpecs(dAtA, i, uint64(len(m.Data))) |
2228 | 2228 |
i += copy(dAtA[i:], m.Data) |
2229 | 2229 |
} |
2230 |
+ if m.Templating != nil { |
|
2231 |
+ dAtA[i] = 0x1a |
|
2232 |
+ i++ |
|
2233 |
+ i = encodeVarintSpecs(dAtA, i, uint64(m.Templating.Size())) |
|
2234 |
+ n37, err := m.Templating.MarshalTo(dAtA[i:]) |
|
2235 |
+ if err != nil { |
|
2236 |
+ return 0, err |
|
2237 |
+ } |
|
2238 |
+ i += n37 |
|
2239 |
+ } |
|
2230 | 2240 |
return i, nil |
2231 | 2241 |
} |
2232 | 2242 |
|
... | ... |
@@ -2248,17 +2278,27 @@ func (m *ConfigSpec) MarshalTo(dAtA []byte) (int, error) { |
2248 | 2248 |
dAtA[i] = 0xa |
2249 | 2249 |
i++ |
2250 | 2250 |
i = encodeVarintSpecs(dAtA, i, uint64(m.Annotations.Size())) |
2251 |
- n37, err := m.Annotations.MarshalTo(dAtA[i:]) |
|
2251 |
+ n38, err := m.Annotations.MarshalTo(dAtA[i:]) |
|
2252 | 2252 |
if err != nil { |
2253 | 2253 |
return 0, err |
2254 | 2254 |
} |
2255 |
- i += n37 |
|
2255 |
+ i += n38 |
|
2256 | 2256 |
if len(m.Data) > 0 { |
2257 | 2257 |
dAtA[i] = 0x12 |
2258 | 2258 |
i++ |
2259 | 2259 |
i = encodeVarintSpecs(dAtA, i, uint64(len(m.Data))) |
2260 | 2260 |
i += copy(dAtA[i:], m.Data) |
2261 | 2261 |
} |
2262 |
+ if m.Templating != nil { |
|
2263 |
+ dAtA[i] = 0x1a |
|
2264 |
+ i++ |
|
2265 |
+ i = encodeVarintSpecs(dAtA, i, uint64(m.Templating.Size())) |
|
2266 |
+ n39, err := m.Templating.MarshalTo(dAtA[i:]) |
|
2267 |
+ if err != nil { |
|
2268 |
+ return 0, err |
|
2269 |
+ } |
|
2270 |
+ i += n39 |
|
2271 |
+ } |
|
2262 | 2272 |
return i, nil |
2263 | 2273 |
} |
2264 | 2274 |
|
... | ... |
@@ -2685,6 +2725,10 @@ func (m *SecretSpec) Size() (n int) { |
2685 | 2685 |
if l > 0 { |
2686 | 2686 |
n += 1 + l + sovSpecs(uint64(l)) |
2687 | 2687 |
} |
2688 |
+ if m.Templating != nil { |
|
2689 |
+ l = m.Templating.Size() |
|
2690 |
+ n += 1 + l + sovSpecs(uint64(l)) |
|
2691 |
+ } |
|
2688 | 2692 |
return n |
2689 | 2693 |
} |
2690 | 2694 |
|
... | ... |
@@ -2697,6 +2741,10 @@ func (m *ConfigSpec) Size() (n int) { |
2697 | 2697 |
if l > 0 { |
2698 | 2698 |
n += 1 + l + sovSpecs(uint64(l)) |
2699 | 2699 |
} |
2700 |
+ if m.Templating != nil { |
|
2701 |
+ l = m.Templating.Size() |
|
2702 |
+ n += 1 + l + sovSpecs(uint64(l)) |
|
2703 |
+ } |
|
2700 | 2704 |
return n |
2701 | 2705 |
} |
2702 | 2706 |
|
... | ... |
@@ -2973,6 +3021,7 @@ func (this *SecretSpec) String() string { |
2973 | 2973 |
s := strings.Join([]string{`&SecretSpec{`, |
2974 | 2974 |
`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`, |
2975 | 2975 |
`Data:` + fmt.Sprintf("%v", this.Data) + `,`, |
2976 |
+ `Templating:` + strings.Replace(fmt.Sprintf("%v", this.Templating), "Driver", "Driver", 1) + `,`, |
|
2976 | 2977 |
`}`, |
2977 | 2978 |
}, "") |
2978 | 2979 |
return s |
... | ... |
@@ -2984,6 +3033,7 @@ func (this *ConfigSpec) String() string { |
2984 | 2984 |
s := strings.Join([]string{`&ConfigSpec{`, |
2985 | 2985 |
`Annotations:` + strings.Replace(strings.Replace(this.Annotations.String(), "Annotations", "Annotations", 1), `&`, ``, 1) + `,`, |
2986 | 2986 |
`Data:` + fmt.Sprintf("%v", this.Data) + `,`, |
2987 |
+ `Templating:` + strings.Replace(fmt.Sprintf("%v", this.Templating), "Driver", "Driver", 1) + `,`, |
|
2987 | 2988 |
`}`, |
2988 | 2989 |
}, "") |
2989 | 2990 |
return s |
... | ... |
@@ -5800,6 +5850,39 @@ func (m *SecretSpec) Unmarshal(dAtA []byte) error { |
5800 | 5800 |
m.Data = []byte{} |
5801 | 5801 |
} |
5802 | 5802 |
iNdEx = postIndex |
5803 |
+ case 3: |
|
5804 |
+ if wireType != 2 { |
|
5805 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Templating", wireType) |
|
5806 |
+ } |
|
5807 |
+ var msglen int |
|
5808 |
+ for shift := uint(0); ; shift += 7 { |
|
5809 |
+ if shift >= 64 { |
|
5810 |
+ return ErrIntOverflowSpecs |
|
5811 |
+ } |
|
5812 |
+ if iNdEx >= l { |
|
5813 |
+ return io.ErrUnexpectedEOF |
|
5814 |
+ } |
|
5815 |
+ b := dAtA[iNdEx] |
|
5816 |
+ iNdEx++ |
|
5817 |
+ msglen |= (int(b) & 0x7F) << shift |
|
5818 |
+ if b < 0x80 { |
|
5819 |
+ break |
|
5820 |
+ } |
|
5821 |
+ } |
|
5822 |
+ if msglen < 0 { |
|
5823 |
+ return ErrInvalidLengthSpecs |
|
5824 |
+ } |
|
5825 |
+ postIndex := iNdEx + msglen |
|
5826 |
+ if postIndex > l { |
|
5827 |
+ return io.ErrUnexpectedEOF |
|
5828 |
+ } |
|
5829 |
+ if m.Templating == nil { |
|
5830 |
+ m.Templating = &Driver{} |
|
5831 |
+ } |
|
5832 |
+ if err := m.Templating.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { |
|
5833 |
+ return err |
|
5834 |
+ } |
|
5835 |
+ iNdEx = postIndex |
|
5803 | 5836 |
default: |
5804 | 5837 |
iNdEx = preIndex |
5805 | 5838 |
skippy, err := skipSpecs(dAtA[iNdEx:]) |
... | ... |
@@ -5911,6 +5994,39 @@ func (m *ConfigSpec) Unmarshal(dAtA []byte) error { |
5911 | 5911 |
m.Data = []byte{} |
5912 | 5912 |
} |
5913 | 5913 |
iNdEx = postIndex |
5914 |
+ case 3: |
|
5915 |
+ if wireType != 2 { |
|
5916 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Templating", wireType) |
|
5917 |
+ } |
|
5918 |
+ var msglen int |
|
5919 |
+ for shift := uint(0); ; shift += 7 { |
|
5920 |
+ if shift >= 64 { |
|
5921 |
+ return ErrIntOverflowSpecs |
|
5922 |
+ } |
|
5923 |
+ if iNdEx >= l { |
|
5924 |
+ return io.ErrUnexpectedEOF |
|
5925 |
+ } |
|
5926 |
+ b := dAtA[iNdEx] |
|
5927 |
+ iNdEx++ |
|
5928 |
+ msglen |= (int(b) & 0x7F) << shift |
|
5929 |
+ if b < 0x80 { |
|
5930 |
+ break |
|
5931 |
+ } |
|
5932 |
+ } |
|
5933 |
+ if msglen < 0 { |
|
5934 |
+ return ErrInvalidLengthSpecs |
|
5935 |
+ } |
|
5936 |
+ postIndex := iNdEx + msglen |
|
5937 |
+ if postIndex > l { |
|
5938 |
+ return io.ErrUnexpectedEOF |
|
5939 |
+ } |
|
5940 |
+ if m.Templating == nil { |
|
5941 |
+ m.Templating = &Driver{} |
|
5942 |
+ } |
|
5943 |
+ if err := m.Templating.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { |
|
5944 |
+ return err |
|
5945 |
+ } |
|
5946 |
+ iNdEx = postIndex |
|
5914 | 5947 |
default: |
5915 | 5948 |
iNdEx = preIndex |
5916 | 5949 |
skippy, err := skipSpecs(dAtA[iNdEx:]) |
... | ... |
@@ -6040,121 +6156,122 @@ var ( |
6040 | 6040 |
func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) } |
6041 | 6041 |
|
6042 | 6042 |
var fileDescriptorSpecs = []byte{ |
6043 |
- // 1846 bytes of a gzipped FileDescriptorProto |
|
6044 |
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x73, 0x1b, 0x49, |
|
6045 |
- 0x15, 0xb6, 0x6c, 0x59, 0x3f, 0xde, 0xc8, 0x89, 0xd2, 0x24, 0x61, 0xac, 0xb0, 0xb2, 0xa2, 0x0d, |
|
6046 |
- 0xc1, 0xcb, 0x16, 0x72, 0x61, 0xa8, 0x25, 0x4b, 0x58, 0x40, 0xb2, 0x84, 0x63, 0x8c, 0x1d, 0x55, |
|
6047 |
- 0xdb, 0x1b, 0xc8, 0x49, 0xd5, 0x9e, 0x69, 0x4b, 0x53, 0x1e, 0x75, 0x0f, 0xdd, 0x3d, 0xda, 0xd2, |
|
6048 |
- 0x8d, 0xe3, 0x56, 0xae, 0x9c, 0x5d, 0x1c, 0xf8, 0x67, 0x72, 0xa4, 0x38, 0x71, 0x72, 0xb1, 0xfe, |
|
6049 |
- 0x17, 0xb8, 0x71, 0x81, 0xea, 0x9e, 0x1e, 0xfd, 0x48, 0xc6, 0x9b, 0x54, 0x11, 0x6e, 0xdd, 0xaf, |
|
6050 |
- 0xbf, 0xef, 0x75, 0xf7, 0xeb, 0xaf, 0xfb, 0xbd, 0x06, 0x47, 0x46, 0xd4, 0x93, 0xad, 0x48, 0x70, |
|
6051 |
- 0xc5, 0x11, 0xf2, 0xb9, 0x77, 0x41, 0x45, 0x4b, 0x7e, 0x45, 0xc4, 0xf8, 0x22, 0x50, 0xad, 0xc9, |
|
6052 |
- 0x8f, 0x6b, 0x8e, 0x9a, 0x46, 0xd4, 0x02, 0x6a, 0x77, 0x87, 0x7c, 0xc8, 0x4d, 0x73, 0x47, 0xb7, |
|
6053 |
- 0xac, 0xb5, 0x3e, 0xe4, 0x7c, 0x18, 0xd2, 0x1d, 0xd3, 0x3b, 0x8b, 0xcf, 0x77, 0xfc, 0x58, 0x10, |
|
6054 |
- 0x15, 0x70, 0x66, 0xc7, 0x37, 0xdf, 0x1c, 0x27, 0x6c, 0x9a, 0x0c, 0x35, 0x2f, 0xf3, 0x50, 0x3a, |
|
6055 |
- 0xe6, 0x3e, 0x3d, 0x89, 0xa8, 0x87, 0xf6, 0xc1, 0x21, 0x8c, 0x71, 0x65, 0xb8, 0xd2, 0xcd, 0x35, |
|
6056 |
- 0x72, 0xdb, 0xce, 0xee, 0x56, 0xeb, 0xed, 0x45, 0xb5, 0xda, 0x73, 0x58, 0x27, 0xff, 0xfa, 0x6a, |
|
6057 |
- 0x6b, 0x05, 0x2f, 0x32, 0xd1, 0xaf, 0xa0, 0xe2, 0x53, 0x19, 0x08, 0xea, 0x0f, 0x04, 0x0f, 0xa9, |
|
6058 |
- 0xbb, 0xda, 0xc8, 0x6d, 0xdf, 0xda, 0xfd, 0x5e, 0x96, 0x27, 0x3d, 0x39, 0xe6, 0x21, 0xc5, 0x8e, |
|
6059 |
- 0x65, 0xe8, 0x0e, 0xda, 0x07, 0x18, 0xd3, 0xf1, 0x19, 0x15, 0x72, 0x14, 0x44, 0xee, 0x9a, 0xa1, |
|
6060 |
- 0xff, 0xe0, 0x26, 0xba, 0x5e, 0x7b, 0xeb, 0x68, 0x06, 0xc7, 0x0b, 0x54, 0x74, 0x04, 0x15, 0x32, |
|
6061 |
- 0x21, 0x41, 0x48, 0xce, 0x82, 0x30, 0x50, 0x53, 0x37, 0x6f, 0x5c, 0x7d, 0xf2, 0xad, 0xae, 0xda, |
|
6062 |
- 0x0b, 0x04, 0xbc, 0x44, 0x6f, 0xfa, 0x00, 0xf3, 0x89, 0xd0, 0x63, 0x28, 0xf6, 0x7b, 0xc7, 0xdd, |
|
6063 |
- 0x83, 0xe3, 0xfd, 0xea, 0x4a, 0x6d, 0xf3, 0xd5, 0x65, 0xe3, 0x9e, 0xf6, 0x31, 0x07, 0xf4, 0x29, |
|
6064 |
- 0xf3, 0x03, 0x36, 0x44, 0xdb, 0x50, 0x6a, 0xef, 0xed, 0xf5, 0xfa, 0xa7, 0xbd, 0x6e, 0x35, 0x57, |
|
6065 |
- 0xab, 0xbd, 0xba, 0x6c, 0xdc, 0x5f, 0x06, 0xb6, 0x3d, 0x8f, 0x46, 0x8a, 0xfa, 0xb5, 0xfc, 0xd7, |
|
6066 |
- 0x7f, 0xad, 0xaf, 0x34, 0xbf, 0xce, 0x41, 0x65, 0x71, 0x11, 0xe8, 0x31, 0x14, 0xda, 0x7b, 0xa7, |
|
6067 |
- 0x07, 0x2f, 0x7a, 0xd5, 0x95, 0x39, 0x7d, 0x11, 0xd1, 0xf6, 0x54, 0x30, 0xa1, 0xe8, 0x11, 0xac, |
|
6068 |
- 0xf7, 0xdb, 0x5f, 0x9e, 0xf4, 0xaa, 0xb9, 0xf9, 0x72, 0x16, 0x61, 0x7d, 0x12, 0x4b, 0x83, 0xea, |
|
6069 |
- 0xe2, 0xf6, 0xc1, 0x71, 0x75, 0x35, 0x1b, 0xd5, 0x15, 0x24, 0x60, 0x76, 0x29, 0x7f, 0xc9, 0x83, |
|
6070 |
- 0x73, 0x42, 0xc5, 0x24, 0xf0, 0x3e, 0xb0, 0x44, 0x3e, 0x83, 0xbc, 0x22, 0xf2, 0xc2, 0x48, 0xc3, |
|
6071 |
- 0xc9, 0x96, 0xc6, 0x29, 0x91, 0x17, 0x7a, 0x52, 0x4b, 0x37, 0x78, 0xad, 0x0c, 0x41, 0xa3, 0x30, |
|
6072 |
- 0xf0, 0x88, 0xa2, 0xbe, 0x51, 0x86, 0xb3, 0xfb, 0xfd, 0x2c, 0x36, 0x9e, 0xa1, 0xec, 0xfa, 0x9f, |
|
6073 |
- 0xad, 0xe0, 0x05, 0x2a, 0x7a, 0x0a, 0x85, 0x61, 0xc8, 0xcf, 0x48, 0x68, 0x34, 0xe1, 0xec, 0x3e, |
|
6074 |
- 0xcc, 0x72, 0xb2, 0x6f, 0x10, 0x73, 0x07, 0x96, 0x82, 0x9e, 0x40, 0x21, 0x8e, 0x7c, 0xa2, 0xa8, |
|
6075 |
- 0x5b, 0x30, 0xe4, 0x46, 0x16, 0xf9, 0x4b, 0x83, 0xd8, 0xe3, 0xec, 0x3c, 0x18, 0x62, 0x8b, 0x47, |
|
6076 |
- 0x87, 0x50, 0x62, 0x54, 0x7d, 0xc5, 0xc5, 0x85, 0x74, 0x8b, 0x8d, 0xb5, 0x6d, 0x67, 0xf7, 0xd3, |
|
6077 |
- 0x4c, 0x31, 0x26, 0x98, 0xb6, 0x52, 0xc4, 0x1b, 0x8d, 0x29, 0x53, 0x89, 0x9b, 0xce, 0xaa, 0x9b, |
|
6078 |
- 0xc3, 0x33, 0x07, 0xe8, 0x17, 0x50, 0xa2, 0xcc, 0x8f, 0x78, 0xc0, 0x94, 0x5b, 0xba, 0x79, 0x21, |
|
6079 |
- 0x3d, 0x8b, 0xd1, 0xc1, 0xc4, 0x33, 0x86, 0x66, 0x0b, 0x1e, 0x86, 0x67, 0xc4, 0xbb, 0x70, 0xcb, |
|
6080 |
- 0xef, 0xb9, 0x8d, 0x19, 0xa3, 0x53, 0x80, 0xfc, 0x98, 0xfb, 0xb4, 0xb9, 0x03, 0x77, 0xde, 0x0a, |
|
6081 |
- 0x35, 0xaa, 0x41, 0xc9, 0x86, 0x3a, 0xd1, 0x48, 0x1e, 0xcf, 0xfa, 0xcd, 0xdb, 0xb0, 0xb1, 0x14, |
|
6082 |
- 0xd6, 0xe6, 0xdf, 0xf3, 0x50, 0x4a, 0xcf, 0x1a, 0xb5, 0xa1, 0xec, 0x71, 0xa6, 0x48, 0xc0, 0xa8, |
|
6083 |
- 0xb0, 0xf2, 0xca, 0x3c, 0x99, 0xbd, 0x14, 0xa4, 0x59, 0xcf, 0x56, 0xf0, 0x9c, 0x85, 0x7e, 0x03, |
|
6084 |
- 0x65, 0x41, 0x25, 0x8f, 0x85, 0x47, 0xa5, 0xd5, 0xd7, 0x76, 0xb6, 0x42, 0x12, 0x10, 0xa6, 0x7f, |
|
6085 |
- 0x8c, 0x03, 0x41, 0x75, 0x94, 0x25, 0x9e, 0x53, 0xd1, 0x53, 0x28, 0x0a, 0x2a, 0x15, 0x11, 0xea, |
|
6086 |
- 0xdb, 0x24, 0x82, 0x13, 0x48, 0x9f, 0x87, 0x81, 0x37, 0xc5, 0x29, 0x03, 0x3d, 0x85, 0x72, 0x14, |
|
6087 |
- 0x12, 0xcf, 0x78, 0x75, 0xd7, 0x0d, 0xfd, 0xa3, 0x2c, 0x7a, 0x3f, 0x05, 0xe1, 0x39, 0x1e, 0x7d, |
|
6088 |
- 0x0e, 0x10, 0xf2, 0xe1, 0xc0, 0x17, 0xc1, 0x84, 0x0a, 0x2b, 0xb1, 0x5a, 0x16, 0xbb, 0x6b, 0x10, |
|
6089 |
- 0xb8, 0x1c, 0xf2, 0x61, 0xd2, 0x44, 0xfb, 0xff, 0x93, 0xbe, 0x16, 0xb4, 0x75, 0x08, 0x40, 0x66, |
|
6090 |
- 0xa3, 0x56, 0x5d, 0x9f, 0xbc, 0x97, 0x2b, 0x7b, 0x22, 0x0b, 0x74, 0xf4, 0x10, 0x2a, 0xe7, 0x5c, |
|
6091 |
- 0x78, 0x74, 0x60, 0x6f, 0x4d, 0xd9, 0x68, 0xc2, 0x31, 0xb6, 0x44, 0x5f, 0xa8, 0x03, 0xc5, 0x21, |
|
6092 |
- 0x65, 0x54, 0x04, 0x9e, 0x0b, 0x66, 0xb2, 0xc7, 0x99, 0x17, 0x32, 0x81, 0xe0, 0x98, 0xa9, 0x60, |
|
6093 |
- 0x4c, 0xed, 0x4c, 0x29, 0xb1, 0x53, 0x86, 0xa2, 0x48, 0x46, 0x9a, 0x7f, 0x00, 0xf4, 0x36, 0x16, |
|
6094 |
- 0x21, 0xc8, 0x5f, 0x04, 0xcc, 0x37, 0xc2, 0x2a, 0x63, 0xd3, 0x46, 0x2d, 0x28, 0x46, 0x64, 0x1a, |
|
6095 |
- 0x72, 0xe2, 0x5b, 0xb1, 0xdc, 0x6d, 0x25, 0xf9, 0xb2, 0x95, 0xe6, 0xcb, 0x56, 0x9b, 0x4d, 0x71, |
|
6096 |
- 0x0a, 0x6a, 0x1e, 0xc2, 0xbd, 0xcc, 0x2d, 0xa3, 0x5d, 0xa8, 0xcc, 0x44, 0x38, 0x08, 0xec, 0x24, |
|
6097 |
- 0x9d, 0xdb, 0xd7, 0x57, 0x5b, 0xce, 0x4c, 0xad, 0x07, 0x5d, 0xec, 0xcc, 0x40, 0x07, 0x7e, 0xf3, |
|
6098 |
- 0xcf, 0x65, 0xd8, 0x58, 0x92, 0x32, 0xba, 0x0b, 0xeb, 0xc1, 0x98, 0x0c, 0xa9, 0x5d, 0x63, 0xd2, |
|
6099 |
- 0x41, 0x3d, 0x28, 0x84, 0xe4, 0x8c, 0x86, 0x5a, 0xd0, 0xfa, 0x50, 0x7f, 0xf4, 0xce, 0x3b, 0xd1, |
|
6100 |
- 0xfa, 0x9d, 0xc1, 0xf7, 0x98, 0x12, 0x53, 0x6c, 0xc9, 0xc8, 0x85, 0xa2, 0xc7, 0xc7, 0x63, 0xc2, |
|
6101 |
- 0xf4, 0xd3, 0xb9, 0xb6, 0x5d, 0xc6, 0x69, 0x57, 0x47, 0x86, 0x88, 0xa1, 0x74, 0xf3, 0xc6, 0x6c, |
|
6102 |
- 0xda, 0xa8, 0x0a, 0x6b, 0x94, 0x4d, 0xdc, 0x75, 0x63, 0xd2, 0x4d, 0x6d, 0xf1, 0x83, 0x44, 0x91, |
|
6103 |
- 0x65, 0xac, 0x9b, 0x9a, 0x17, 0x4b, 0x2a, 0xdc, 0x62, 0x12, 0x51, 0xdd, 0x46, 0x3f, 0x83, 0xc2, |
|
6104 |
- 0x98, 0xc7, 0x4c, 0x49, 0xb7, 0x64, 0x16, 0xbb, 0x99, 0xb5, 0xd8, 0x23, 0x8d, 0xb0, 0x4f, 0xbb, |
|
6105 |
- 0x85, 0xa3, 0x1e, 0xdc, 0x91, 0x8a, 0x47, 0x83, 0xa1, 0x20, 0x1e, 0x1d, 0x44, 0x54, 0x04, 0xdc, |
|
6106 |
- 0xb7, 0x4f, 0xd3, 0xe6, 0x5b, 0x87, 0xd2, 0xb5, 0x45, 0x0e, 0xbe, 0xad, 0x39, 0xfb, 0x9a, 0xd2, |
|
6107 |
- 0x37, 0x0c, 0xd4, 0x87, 0x4a, 0x14, 0x87, 0xe1, 0x80, 0x47, 0x49, 0x96, 0x4a, 0xf4, 0xf4, 0x1e, |
|
6108 |
- 0x21, 0xeb, 0xc7, 0x61, 0xf8, 0x3c, 0x21, 0x61, 0x27, 0x9a, 0x77, 0xd0, 0x7d, 0x28, 0x0c, 0x05, |
|
6109 |
- 0x8f, 0x23, 0xe9, 0x3a, 0x26, 0x18, 0xb6, 0x87, 0xbe, 0x80, 0xa2, 0xa4, 0x9e, 0xa0, 0x4a, 0xba, |
|
6110 |
- 0x15, 0xb3, 0xd5, 0x8f, 0xb3, 0x26, 0x39, 0x31, 0x10, 0x4c, 0xcf, 0xa9, 0xa0, 0xcc, 0xa3, 0x38, |
|
6111 |
- 0xe5, 0xa0, 0x4d, 0x58, 0x53, 0x6a, 0xea, 0x6e, 0x34, 0x72, 0xdb, 0xa5, 0x4e, 0xf1, 0xfa, 0x6a, |
|
6112 |
- 0x6b, 0xed, 0xf4, 0xf4, 0x25, 0xd6, 0x36, 0xfd, 0x82, 0x8e, 0xb8, 0x54, 0x8c, 0x8c, 0xa9, 0x7b, |
|
6113 |
- 0xcb, 0xc4, 0x76, 0xd6, 0x47, 0x2f, 0x01, 0x7c, 0x26, 0x07, 0x9e, 0xb9, 0xb2, 0xee, 0x6d, 0xb3, |
|
6114 |
- 0xbb, 0x4f, 0xdf, 0xbd, 0xbb, 0xee, 0xf1, 0x89, 0xcd, 0x22, 0x1b, 0xd7, 0x57, 0x5b, 0xe5, 0x59, |
|
6115 |
- 0x17, 0x97, 0x7d, 0x26, 0x93, 0x26, 0xea, 0x80, 0x33, 0xa2, 0x24, 0x54, 0x23, 0x6f, 0x44, 0xbd, |
|
6116 |
- 0x0b, 0xb7, 0x7a, 0x73, 0x5a, 0x78, 0x66, 0x60, 0xd6, 0xc3, 0x22, 0x49, 0x2b, 0x58, 0x2f, 0x55, |
|
6117 |
- 0xba, 0x77, 0x4c, 0xac, 0x92, 0x0e, 0xfa, 0x08, 0x80, 0x47, 0x94, 0x0d, 0xa4, 0xf2, 0x03, 0xe6, |
|
6118 |
- 0x22, 0xbd, 0x65, 0x5c, 0xd6, 0x96, 0x13, 0x6d, 0x40, 0x0f, 0xf4, 0xa3, 0x4d, 0xfc, 0x01, 0x67, |
|
6119 |
- 0xe1, 0xd4, 0xfd, 0x8e, 0x19, 0x2d, 0x69, 0xc3, 0x73, 0x16, 0x4e, 0xd1, 0x16, 0x38, 0x46, 0x17, |
|
6120 |
- 0x32, 0x18, 0x32, 0x12, 0xba, 0x77, 0x4d, 0x3c, 0x40, 0x9b, 0x4e, 0x8c, 0x45, 0x9f, 0x43, 0x12, |
|
6121 |
- 0x0d, 0xe9, 0xde, 0xbb, 0xf9, 0x1c, 0xec, 0x62, 0xe7, 0xe7, 0x60, 0x39, 0xe8, 0x97, 0x00, 0x91, |
|
6122 |
- 0x08, 0x26, 0x41, 0x48, 0x87, 0x54, 0xba, 0xf7, 0xcd, 0xa6, 0xeb, 0x99, 0xaf, 0xf5, 0x0c, 0x85, |
|
6123 |
- 0x17, 0x18, 0xb5, 0xcf, 0xc1, 0x59, 0xb8, 0x6d, 0xfa, 0x96, 0x5c, 0xd0, 0xa9, 0xbd, 0xc0, 0xba, |
|
6124 |
- 0xa9, 0x43, 0x32, 0x21, 0x61, 0x9c, 0x54, 0xc2, 0x65, 0x9c, 0x74, 0x7e, 0xbe, 0xfa, 0x24, 0x57, |
|
6125 |
- 0xdb, 0x05, 0x67, 0x41, 0x75, 0xe8, 0x63, 0xd8, 0x10, 0x74, 0x18, 0x48, 0x25, 0xa6, 0x03, 0x12, |
|
6126 |
- 0xab, 0x91, 0xfb, 0x6b, 0x43, 0xa8, 0xa4, 0xc6, 0x76, 0xac, 0x46, 0xb5, 0x01, 0xcc, 0x0f, 0x0f, |
|
6127 |
- 0x35, 0xc0, 0xd1, 0xa2, 0x90, 0x54, 0x4c, 0xa8, 0xd0, 0xd9, 0x56, 0xc7, 0x7c, 0xd1, 0xa4, 0xc5, |
|
6128 |
- 0x2b, 0x29, 0x11, 0xde, 0xc8, 0xbc, 0x1d, 0x65, 0x6c, 0x7b, 0xfa, 0x31, 0x48, 0x6f, 0x88, 0x7d, |
|
6129 |
- 0x0c, 0x6c, 0xb7, 0xf9, 0xaf, 0x1c, 0x54, 0x16, 0x8b, 0x06, 0xb4, 0x97, 0x24, 0x7b, 0xb3, 0xa5, |
|
6130 |
- 0x5b, 0xbb, 0x3b, 0xef, 0x2a, 0x32, 0x4c, 0x6a, 0x0d, 0x63, 0xed, 0xec, 0x48, 0xd7, 0xf7, 0x86, |
|
6131 |
- 0x8c, 0x7e, 0x0a, 0xeb, 0x11, 0x17, 0x2a, 0x7d, 0xc2, 0xb2, 0x03, 0xcc, 0x45, 0x9a, 0x8a, 0x12, |
|
6132 |
- 0x70, 0x73, 0x04, 0xb7, 0x96, 0xbd, 0xa1, 0x47, 0xb0, 0xf6, 0xe2, 0xa0, 0x5f, 0x5d, 0xa9, 0x3d, |
|
6133 |
- 0x78, 0x75, 0xd9, 0xf8, 0xee, 0xf2, 0xe0, 0x8b, 0x40, 0xa8, 0x98, 0x84, 0x07, 0x7d, 0xf4, 0x43, |
|
6134 |
- 0x58, 0xef, 0x1e, 0x9f, 0x60, 0x5c, 0xcd, 0xd5, 0xb6, 0x5e, 0x5d, 0x36, 0x1e, 0x2c, 0xe3, 0xf4, |
|
6135 |
- 0x10, 0x8f, 0x99, 0x8f, 0xf9, 0xd9, 0xac, 0xd6, 0xfd, 0xf7, 0x2a, 0x38, 0xf6, 0x65, 0xff, 0xd0, |
|
6136 |
- 0xdf, 0xa1, 0x8d, 0x24, 0x95, 0xa7, 0x57, 0x76, 0xf5, 0x9d, 0x19, 0xbd, 0x92, 0x10, 0xec, 0x19, |
|
6137 |
- 0x3f, 0x84, 0x4a, 0x10, 0x4d, 0x3e, 0x1b, 0x50, 0x46, 0xce, 0x42, 0x5b, 0xf6, 0x96, 0xb0, 0xa3, |
|
6138 |
- 0x6d, 0xbd, 0xc4, 0xa4, 0xdf, 0x8b, 0x80, 0x29, 0x2a, 0x98, 0x2d, 0x68, 0x4b, 0x78, 0xd6, 0x47, |
|
6139 |
- 0x5f, 0x40, 0x3e, 0x88, 0xc8, 0xd8, 0x96, 0x21, 0x99, 0x3b, 0x38, 0xe8, 0xb7, 0x8f, 0xac, 0x06, |
|
6140 |
- 0x3b, 0xa5, 0xeb, 0xab, 0xad, 0xbc, 0x36, 0x60, 0x43, 0x43, 0xf5, 0xb4, 0x12, 0xd0, 0x33, 0x99, |
|
6141 |
- 0xb7, 0xbf, 0x84, 0x17, 0x2c, 0x5a, 0x47, 0x01, 0x1b, 0x0a, 0x2a, 0xa5, 0xc9, 0x02, 0x25, 0x9c, |
|
6142 |
- 0x76, 0x51, 0x0d, 0x8a, 0xb6, 0x9e, 0x30, 0x05, 0x44, 0x59, 0xe7, 0x6a, 0x6b, 0xe8, 0x6c, 0x80, |
|
6143 |
- 0x93, 0x44, 0x63, 0x70, 0x2e, 0xf8, 0xb8, 0xf9, 0x9f, 0x3c, 0x38, 0x7b, 0x61, 0x2c, 0x95, 0x4d, |
|
6144 |
- 0x83, 0x1f, 0x2c, 0xf8, 0x2f, 0xe1, 0x0e, 0x31, 0xdf, 0x2b, 0xc2, 0x74, 0x4e, 0x31, 0x65, 0x9a, |
|
6145 |
- 0x3d, 0x80, 0x47, 0x99, 0xee, 0x66, 0xe0, 0xa4, 0xa4, 0xeb, 0x14, 0xb4, 0x4f, 0x37, 0x87, 0xab, |
|
6146 |
- 0xe4, 0x8d, 0x11, 0x74, 0x02, 0x1b, 0x5c, 0x78, 0x23, 0x2a, 0x55, 0x92, 0x89, 0xec, 0x77, 0x24, |
|
6147 |
- 0xf3, 0xa3, 0xfa, 0x7c, 0x11, 0x68, 0x9f, 0xe1, 0x64, 0xb5, 0xcb, 0x3e, 0xd0, 0x13, 0xc8, 0x0b, |
|
6148 |
- 0x72, 0x9e, 0x96, 0x9c, 0x99, 0x97, 0x04, 0x93, 0x73, 0xb5, 0xe4, 0xc2, 0x30, 0xd0, 0x6f, 0x01, |
|
6149 |
- 0xfc, 0x40, 0x46, 0x44, 0x79, 0x23, 0x2a, 0xec, 0x61, 0x67, 0x6e, 0xb1, 0x3b, 0x43, 0x2d, 0x79, |
|
6150 |
- 0x59, 0x60, 0xa3, 0x43, 0x28, 0x7b, 0x24, 0x95, 0x6b, 0xe1, 0xe6, 0x3f, 0xda, 0x5e, 0xdb, 0xba, |
|
6151 |
- 0xa8, 0x6a, 0x17, 0xd7, 0x57, 0x5b, 0xa5, 0xd4, 0x82, 0x4b, 0x1e, 0xb1, 0xf2, 0x3d, 0x84, 0x0d, |
|
6152 |
- 0xfd, 0x77, 0x1b, 0xf8, 0xf4, 0x9c, 0xc4, 0xa1, 0x4a, 0x64, 0x72, 0x43, 0x5a, 0xd1, 0x1f, 0x81, |
|
6153 |
- 0xae, 0xc5, 0xd9, 0x75, 0x55, 0xd4, 0x82, 0x0d, 0xfd, 0x1e, 0xee, 0x50, 0xe6, 0x89, 0xa9, 0x11, |
|
6154 |
- 0x6b, 0xba, 0xc2, 0xd2, 0xcd, 0x9b, 0xed, 0xcd, 0xc0, 0x4b, 0x9b, 0xad, 0xd2, 0x37, 0xec, 0xcd, |
|
6155 |
- 0x00, 0x20, 0x49, 0xd4, 0x1f, 0x56, 0x7f, 0x08, 0xf2, 0x3e, 0x51, 0xc4, 0x48, 0xae, 0x82, 0x4d, |
|
6156 |
- 0x5b, 0x4f, 0x95, 0x4c, 0xfa, 0x7f, 0x9f, 0xaa, 0xe3, 0xbe, 0xfe, 0xa6, 0xbe, 0xf2, 0x8f, 0x6f, |
|
6157 |
- 0xea, 0x2b, 0x7f, 0xba, 0xae, 0xe7, 0x5e, 0x5f, 0xd7, 0x73, 0x7f, 0xbb, 0xae, 0xe7, 0xfe, 0x79, |
|
6158 |
- 0x5d, 0xcf, 0x9d, 0x15, 0x4c, 0x25, 0xf5, 0x93, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x21, |
|
6159 |
- 0x2b, 0x33, 0x82, 0x12, 0x00, 0x00, |
|
6043 |
+ // 1867 bytes of a gzipped FileDescriptorProto |
|
6044 |
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x57, 0xcf, 0x73, 0x1b, 0x49, |
|
6045 |
+ 0x15, 0xb6, 0x6c, 0x59, 0x3f, 0xde, 0xc8, 0x89, 0xd2, 0x24, 0x61, 0xa2, 0xb0, 0xb2, 0xa2, 0x0d, |
|
6046 |
+ 0xc1, 0xcb, 0x16, 0x72, 0x61, 0xa8, 0x25, 0xbb, 0x61, 0x01, 0xc9, 0x12, 0x8e, 0x31, 0x76, 0x54, |
|
6047 |
+ 0x6d, 0x6f, 0x20, 0x27, 0x55, 0x7b, 0xa6, 0x3d, 0x9a, 0xf2, 0xa8, 0x7b, 0xe8, 0xe9, 0xd1, 0x96, |
|
6048 |
+ 0x6e, 0x1c, 0xb7, 0x72, 0xe5, 0xec, 0xe2, 0x40, 0xf1, 0xbf, 0xe4, 0x48, 0x71, 0xe2, 0xe4, 0x62, |
|
6049 |
+ 0xfd, 0x2f, 0x70, 0xe3, 0x02, 0xd5, 0x3d, 0x3d, 0xd2, 0x28, 0x19, 0x27, 0xa9, 0x22, 0x07, 0x6e, |
|
6050 |
+ 0xdd, 0xaf, 0xbf, 0xef, 0xcd, 0xeb, 0xd7, 0x5f, 0xf7, 0x7b, 0x03, 0x56, 0x14, 0x52, 0x27, 0xea, |
|
6051 |
+ 0x84, 0x82, 0x4b, 0x8e, 0x90, 0xcb, 0x9d, 0x73, 0x2a, 0x3a, 0xd1, 0xd7, 0x44, 0x4c, 0xce, 0x7d, |
|
6052 |
+ 0xd9, 0x99, 0xfe, 0xb8, 0x61, 0xc9, 0x59, 0x48, 0x0d, 0xa0, 0x71, 0xdb, 0xe3, 0x1e, 0xd7, 0xc3, |
|
6053 |
+ 0x6d, 0x35, 0x32, 0xd6, 0xa6, 0xc7, 0xb9, 0x17, 0xd0, 0x6d, 0x3d, 0x3b, 0x8d, 0xcf, 0xb6, 0xdd, |
|
6054 |
+ 0x58, 0x10, 0xe9, 0x73, 0x66, 0xd6, 0xef, 0xbd, 0xbe, 0x4e, 0xd8, 0x2c, 0x59, 0x6a, 0x5f, 0x14, |
|
6055 |
+ 0xa1, 0x72, 0xc4, 0x5d, 0x7a, 0x1c, 0x52, 0x07, 0xed, 0x81, 0x45, 0x18, 0xe3, 0x52, 0x73, 0x23, |
|
6056 |
+ 0xbb, 0xd0, 0x2a, 0x6c, 0x59, 0x3b, 0x9b, 0x9d, 0x37, 0x83, 0xea, 0x74, 0x17, 0xb0, 0x5e, 0xf1, |
|
6057 |
+ 0xd5, 0xe5, 0xe6, 0x0a, 0xce, 0x32, 0xd1, 0x2f, 0xa1, 0xe6, 0xd2, 0xc8, 0x17, 0xd4, 0x1d, 0x09, |
|
6058 |
+ 0x1e, 0x50, 0x7b, 0xb5, 0x55, 0xd8, 0xba, 0xb1, 0xf3, 0xbd, 0x3c, 0x4f, 0xea, 0xe3, 0x98, 0x07, |
|
6059 |
+ 0x14, 0x5b, 0x86, 0xa1, 0x26, 0x68, 0x0f, 0x60, 0x42, 0x27, 0xa7, 0x54, 0x44, 0x63, 0x3f, 0xb4, |
|
6060 |
+ 0xd7, 0x34, 0xfd, 0x07, 0xd7, 0xd1, 0x55, 0xec, 0x9d, 0xc3, 0x39, 0x1c, 0x67, 0xa8, 0xe8, 0x10, |
|
6061 |
+ 0x6a, 0x64, 0x4a, 0xfc, 0x80, 0x9c, 0xfa, 0x81, 0x2f, 0x67, 0x76, 0x51, 0xbb, 0xfa, 0xe4, 0xad, |
|
6062 |
+ 0xae, 0xba, 0x19, 0x02, 0x5e, 0xa2, 0xb7, 0x5d, 0x80, 0xc5, 0x87, 0xd0, 0x23, 0x28, 0x0f, 0x07, |
|
6063 |
+ 0x47, 0xfd, 0xfd, 0xa3, 0xbd, 0xfa, 0x4a, 0xe3, 0xde, 0xcb, 0x8b, 0xd6, 0x1d, 0xe5, 0x63, 0x01, |
|
6064 |
+ 0x18, 0x52, 0xe6, 0xfa, 0xcc, 0x43, 0x5b, 0x50, 0xe9, 0xee, 0xee, 0x0e, 0x86, 0x27, 0x83, 0x7e, |
|
6065 |
+ 0xbd, 0xd0, 0x68, 0xbc, 0xbc, 0x68, 0xdd, 0x5d, 0x06, 0x76, 0x1d, 0x87, 0x86, 0x92, 0xba, 0x8d, |
|
6066 |
+ 0xe2, 0x37, 0x7f, 0x69, 0xae, 0xb4, 0xbf, 0x29, 0x40, 0x2d, 0x1b, 0x04, 0x7a, 0x04, 0xa5, 0xee, |
|
6067 |
+ 0xee, 0xc9, 0xfe, 0xf3, 0x41, 0x7d, 0x65, 0x41, 0xcf, 0x22, 0xba, 0x8e, 0xf4, 0xa7, 0x14, 0x3d, |
|
6068 |
+ 0x84, 0xf5, 0x61, 0xf7, 0xab, 0xe3, 0x41, 0xbd, 0xb0, 0x08, 0x27, 0x0b, 0x1b, 0x92, 0x38, 0xd2, |
|
6069 |
+ 0xa8, 0x3e, 0xee, 0xee, 0x1f, 0xd5, 0x57, 0xf3, 0x51, 0x7d, 0x41, 0x7c, 0x66, 0x42, 0xf9, 0x73, |
|
6070 |
+ 0x11, 0xac, 0x63, 0x2a, 0xa6, 0xbe, 0xf3, 0x81, 0x25, 0xf2, 0x19, 0x14, 0x25, 0x89, 0xce, 0xb5, |
|
6071 |
+ 0x34, 0xac, 0x7c, 0x69, 0x9c, 0x90, 0xe8, 0x5c, 0x7d, 0xd4, 0xd0, 0x35, 0x5e, 0x29, 0x43, 0xd0, |
|
6072 |
+ 0x30, 0xf0, 0x1d, 0x22, 0xa9, 0xab, 0x95, 0x61, 0xed, 0x7c, 0x3f, 0x8f, 0x8d, 0xe7, 0x28, 0x13, |
|
6073 |
+ 0xff, 0xd3, 0x15, 0x9c, 0xa1, 0xa2, 0x27, 0x50, 0xf2, 0x02, 0x7e, 0x4a, 0x02, 0xad, 0x09, 0x6b, |
|
6074 |
+ 0xe7, 0x41, 0x9e, 0x93, 0x3d, 0x8d, 0x58, 0x38, 0x30, 0x14, 0xf4, 0x18, 0x4a, 0x71, 0xe8, 0x12, |
|
6075 |
+ 0x49, 0xed, 0x92, 0x26, 0xb7, 0xf2, 0xc8, 0x5f, 0x69, 0xc4, 0x2e, 0x67, 0x67, 0xbe, 0x87, 0x0d, |
|
6076 |
+ 0x1e, 0x1d, 0x40, 0x85, 0x51, 0xf9, 0x35, 0x17, 0xe7, 0x91, 0x5d, 0x6e, 0xad, 0x6d, 0x59, 0x3b, |
|
6077 |
+ 0x9f, 0xe6, 0x8a, 0x31, 0xc1, 0x74, 0xa5, 0x24, 0xce, 0x78, 0x42, 0x99, 0x4c, 0xdc, 0xf4, 0x56, |
|
6078 |
+ 0xed, 0x02, 0x9e, 0x3b, 0x40, 0x3f, 0x87, 0x0a, 0x65, 0x6e, 0xc8, 0x7d, 0x26, 0xed, 0xca, 0xf5, |
|
6079 |
+ 0x81, 0x0c, 0x0c, 0x46, 0x25, 0x13, 0xcf, 0x19, 0x8a, 0x2d, 0x78, 0x10, 0x9c, 0x12, 0xe7, 0xdc, |
|
6080 |
+ 0xae, 0xbe, 0xe7, 0x36, 0xe6, 0x8c, 0x5e, 0x09, 0x8a, 0x13, 0xee, 0xd2, 0xf6, 0x36, 0xdc, 0x7a, |
|
6081 |
+ 0x23, 0xd5, 0xa8, 0x01, 0x15, 0x93, 0xea, 0x44, 0x23, 0x45, 0x3c, 0x9f, 0xb7, 0x6f, 0xc2, 0xc6, |
|
6082 |
+ 0x52, 0x5a, 0xdb, 0x7f, 0x2f, 0x42, 0x25, 0x3d, 0x6b, 0xd4, 0x85, 0xaa, 0xc3, 0x99, 0x24, 0x3e, |
|
6083 |
+ 0xa3, 0xc2, 0xc8, 0x2b, 0xf7, 0x64, 0x76, 0x53, 0x90, 0x62, 0x3d, 0x5d, 0xc1, 0x0b, 0x16, 0xfa, |
|
6084 |
+ 0x35, 0x54, 0x05, 0x8d, 0x78, 0x2c, 0x1c, 0x1a, 0x19, 0x7d, 0x6d, 0xe5, 0x2b, 0x24, 0x01, 0x61, |
|
6085 |
+ 0xfa, 0x87, 0xd8, 0x17, 0x54, 0x65, 0x39, 0xc2, 0x0b, 0x2a, 0x7a, 0x02, 0x65, 0x41, 0x23, 0x49, |
|
6086 |
+ 0x84, 0x7c, 0x9b, 0x44, 0x70, 0x02, 0x19, 0xf2, 0xc0, 0x77, 0x66, 0x38, 0x65, 0xa0, 0x27, 0x50, |
|
6087 |
+ 0x0d, 0x03, 0xe2, 0x68, 0xaf, 0xf6, 0xba, 0xa6, 0x7f, 0x94, 0x47, 0x1f, 0xa6, 0x20, 0xbc, 0xc0, |
|
6088 |
+ 0xa3, 0xcf, 0x01, 0x02, 0xee, 0x8d, 0x5c, 0xe1, 0x4f, 0xa9, 0x30, 0x12, 0x6b, 0xe4, 0xb1, 0xfb, |
|
6089 |
+ 0x1a, 0x81, 0xab, 0x01, 0xf7, 0x92, 0x21, 0xda, 0xfb, 0x9f, 0xf4, 0x95, 0xd1, 0xd6, 0x01, 0x00, |
|
6090 |
+ 0x99, 0xaf, 0x1a, 0x75, 0x7d, 0xf2, 0x5e, 0xae, 0xcc, 0x89, 0x64, 0xe8, 0xe8, 0x01, 0xd4, 0xce, |
|
6091 |
+ 0xb8, 0x70, 0xe8, 0xc8, 0xdc, 0x9a, 0xaa, 0xd6, 0x84, 0xa5, 0x6d, 0x89, 0xbe, 0x50, 0x0f, 0xca, |
|
6092 |
+ 0x1e, 0x65, 0x54, 0xf8, 0x8e, 0x0d, 0xfa, 0x63, 0x8f, 0x72, 0x2f, 0x64, 0x02, 0xc1, 0x31, 0x93, |
|
6093 |
+ 0xfe, 0x84, 0x9a, 0x2f, 0xa5, 0xc4, 0x5e, 0x15, 0xca, 0x22, 0x59, 0x69, 0xff, 0x1e, 0xd0, 0x9b, |
|
6094 |
+ 0x58, 0x84, 0xa0, 0x78, 0xee, 0x33, 0x57, 0x0b, 0xab, 0x8a, 0xf5, 0x18, 0x75, 0xa0, 0x1c, 0x92, |
|
6095 |
+ 0x59, 0xc0, 0x89, 0x6b, 0xc4, 0x72, 0xbb, 0x93, 0xd4, 0xcb, 0x4e, 0x5a, 0x2f, 0x3b, 0x5d, 0x36, |
|
6096 |
+ 0xc3, 0x29, 0xa8, 0x7d, 0x00, 0x77, 0x72, 0xb7, 0x8c, 0x76, 0xa0, 0x36, 0x17, 0xe1, 0xc8, 0x37, |
|
6097 |
+ 0x1f, 0xe9, 0xdd, 0xbc, 0xba, 0xdc, 0xb4, 0xe6, 0x6a, 0xdd, 0xef, 0x63, 0x6b, 0x0e, 0xda, 0x77, |
|
6098 |
+ 0xdb, 0x7f, 0xaa, 0xc2, 0xc6, 0x92, 0x94, 0xd1, 0x6d, 0x58, 0xf7, 0x27, 0xc4, 0xa3, 0x26, 0xc6, |
|
6099 |
+ 0x64, 0x82, 0x06, 0x50, 0x0a, 0xc8, 0x29, 0x0d, 0x94, 0xa0, 0xd5, 0xa1, 0xfe, 0xe8, 0x9d, 0x77, |
|
6100 |
+ 0xa2, 0xf3, 0x5b, 0x8d, 0x1f, 0x30, 0x29, 0x66, 0xd8, 0x90, 0x91, 0x0d, 0x65, 0x87, 0x4f, 0x26, |
|
6101 |
+ 0x84, 0xa9, 0xa7, 0x73, 0x6d, 0xab, 0x8a, 0xd3, 0xa9, 0xca, 0x0c, 0x11, 0x5e, 0x64, 0x17, 0xb5, |
|
6102 |
+ 0x59, 0x8f, 0x51, 0x1d, 0xd6, 0x28, 0x9b, 0xda, 0xeb, 0xda, 0xa4, 0x86, 0xca, 0xe2, 0xfa, 0x89, |
|
6103 |
+ 0x22, 0xab, 0x58, 0x0d, 0x15, 0x2f, 0x8e, 0xa8, 0xb0, 0xcb, 0x49, 0x46, 0xd5, 0x18, 0xfd, 0x0c, |
|
6104 |
+ 0x4a, 0x13, 0x1e, 0x33, 0x19, 0xd9, 0x15, 0x1d, 0xec, 0xbd, 0xbc, 0x60, 0x0f, 0x15, 0xc2, 0x3c, |
|
6105 |
+ 0xed, 0x06, 0x8e, 0x06, 0x70, 0x2b, 0x92, 0x3c, 0x1c, 0x79, 0x82, 0x38, 0x74, 0x14, 0x52, 0xe1, |
|
6106 |
+ 0x73, 0xd7, 0x3c, 0x4d, 0xf7, 0xde, 0x38, 0x94, 0xbe, 0x69, 0x72, 0xf0, 0x4d, 0xc5, 0xd9, 0x53, |
|
6107 |
+ 0x94, 0xa1, 0x66, 0xa0, 0x21, 0xd4, 0xc2, 0x38, 0x08, 0x46, 0x3c, 0x4c, 0xaa, 0x54, 0xa2, 0xa7, |
|
6108 |
+ 0xf7, 0x48, 0xd9, 0x30, 0x0e, 0x82, 0x67, 0x09, 0x09, 0x5b, 0xe1, 0x62, 0x82, 0xee, 0x42, 0xc9, |
|
6109 |
+ 0x13, 0x3c, 0x0e, 0x23, 0xdb, 0xd2, 0xc9, 0x30, 0x33, 0xf4, 0x25, 0x94, 0x23, 0xea, 0x08, 0x2a, |
|
6110 |
+ 0x23, 0xbb, 0xa6, 0xb7, 0xfa, 0x71, 0xde, 0x47, 0x8e, 0x35, 0x04, 0xd3, 0x33, 0x2a, 0x28, 0x73, |
|
6111 |
+ 0x28, 0x4e, 0x39, 0xe8, 0x1e, 0xac, 0x49, 0x39, 0xb3, 0x37, 0x5a, 0x85, 0xad, 0x4a, 0xaf, 0x7c, |
|
6112 |
+ 0x75, 0xb9, 0xb9, 0x76, 0x72, 0xf2, 0x02, 0x2b, 0x9b, 0x7a, 0x41, 0xc7, 0x3c, 0x92, 0x8c, 0x4c, |
|
6113 |
+ 0xa8, 0x7d, 0x43, 0xe7, 0x76, 0x3e, 0x47, 0x2f, 0x00, 0x5c, 0x16, 0x8d, 0x1c, 0x7d, 0x65, 0xed, |
|
6114 |
+ 0x9b, 0x7a, 0x77, 0x9f, 0xbe, 0x7b, 0x77, 0xfd, 0xa3, 0x63, 0x53, 0x45, 0x36, 0xae, 0x2e, 0x37, |
|
6115 |
+ 0xab, 0xf3, 0x29, 0xae, 0xba, 0x2c, 0x4a, 0x86, 0xa8, 0x07, 0xd6, 0x98, 0x92, 0x40, 0x8e, 0x9d, |
|
6116 |
+ 0x31, 0x75, 0xce, 0xed, 0xfa, 0xf5, 0x65, 0xe1, 0xa9, 0x86, 0x19, 0x0f, 0x59, 0x92, 0x52, 0xb0, |
|
6117 |
+ 0x0a, 0x35, 0xb2, 0x6f, 0xe9, 0x5c, 0x25, 0x13, 0xf4, 0x11, 0x00, 0x0f, 0x29, 0x1b, 0x45, 0xd2, |
|
6118 |
+ 0xf5, 0x99, 0x8d, 0xd4, 0x96, 0x71, 0x55, 0x59, 0x8e, 0x95, 0x01, 0xdd, 0x57, 0x8f, 0x36, 0x71, |
|
6119 |
+ 0x47, 0x9c, 0x05, 0x33, 0xfb, 0x3b, 0x7a, 0xb5, 0xa2, 0x0c, 0xcf, 0x58, 0x30, 0x43, 0x9b, 0x60, |
|
6120 |
+ 0x69, 0x5d, 0x44, 0xbe, 0xc7, 0x48, 0x60, 0xdf, 0xd6, 0xf9, 0x00, 0x65, 0x3a, 0xd6, 0x16, 0x75, |
|
6121 |
+ 0x0e, 0x49, 0x36, 0x22, 0xfb, 0xce, 0xf5, 0xe7, 0x60, 0x82, 0x5d, 0x9c, 0x83, 0xe1, 0xa0, 0x5f, |
|
6122 |
+ 0x00, 0x84, 0xc2, 0x9f, 0xfa, 0x01, 0xf5, 0x68, 0x64, 0xdf, 0xd5, 0x9b, 0x6e, 0xe6, 0xbe, 0xd6, |
|
6123 |
+ 0x73, 0x14, 0xce, 0x30, 0x1a, 0x9f, 0x83, 0x95, 0xb9, 0x6d, 0xea, 0x96, 0x9c, 0xd3, 0x99, 0xb9, |
|
6124 |
+ 0xc0, 0x6a, 0xa8, 0x52, 0x32, 0x25, 0x41, 0x9c, 0x74, 0xc2, 0x55, 0x9c, 0x4c, 0xbe, 0x58, 0x7d, |
|
6125 |
+ 0x5c, 0x68, 0xec, 0x80, 0x95, 0x51, 0x1d, 0xfa, 0x18, 0x36, 0x04, 0xf5, 0xfc, 0x48, 0x8a, 0xd9, |
|
6126 |
+ 0x88, 0xc4, 0x72, 0x6c, 0xff, 0x4a, 0x13, 0x6a, 0xa9, 0xb1, 0x1b, 0xcb, 0x71, 0x63, 0x04, 0x8b, |
|
6127 |
+ 0xc3, 0x43, 0x2d, 0xb0, 0x94, 0x28, 0x22, 0x2a, 0xa6, 0x54, 0xa8, 0x6a, 0xab, 0x72, 0x9e, 0x35, |
|
6128 |
+ 0x29, 0xf1, 0x46, 0x94, 0x08, 0x67, 0xac, 0xdf, 0x8e, 0x2a, 0x36, 0x33, 0xf5, 0x18, 0xa4, 0x37, |
|
6129 |
+ 0xc4, 0x3c, 0x06, 0x66, 0xda, 0xfe, 0x57, 0x01, 0x6a, 0xd9, 0xa6, 0x01, 0xed, 0x26, 0xc5, 0x5e, |
|
6130 |
+ 0x6f, 0xe9, 0xc6, 0xce, 0xf6, 0xbb, 0x9a, 0x0c, 0x5d, 0x5a, 0x83, 0x58, 0x39, 0x3b, 0x54, 0xfd, |
|
6131 |
+ 0xbd, 0x26, 0xa3, 0x9f, 0xc2, 0x7a, 0xc8, 0x85, 0x4c, 0x9f, 0xb0, 0xfc, 0x04, 0x73, 0x91, 0x96, |
|
6132 |
+ 0xa2, 0x04, 0xdc, 0x1e, 0xc3, 0x8d, 0x65, 0x6f, 0xe8, 0x21, 0xac, 0x3d, 0xdf, 0x1f, 0xd6, 0x57, |
|
6133 |
+ 0x1a, 0xf7, 0x5f, 0x5e, 0xb4, 0xbe, 0xbb, 0xbc, 0xf8, 0xdc, 0x17, 0x32, 0x26, 0xc1, 0xfe, 0x10, |
|
6134 |
+ 0xfd, 0x10, 0xd6, 0xfb, 0x47, 0xc7, 0x18, 0xd7, 0x0b, 0x8d, 0xcd, 0x97, 0x17, 0xad, 0xfb, 0xcb, |
|
6135 |
+ 0x38, 0xb5, 0xc4, 0x63, 0xe6, 0x62, 0x7e, 0x3a, 0xef, 0x75, 0xff, 0xbd, 0x0a, 0x96, 0x79, 0xd9, |
|
6136 |
+ 0x3f, 0xf4, 0xef, 0xd0, 0x46, 0x52, 0xca, 0xd3, 0x2b, 0xbb, 0xfa, 0xce, 0x8a, 0x5e, 0x4b, 0x08, |
|
6137 |
+ 0xe6, 0x8c, 0x1f, 0x40, 0xcd, 0x0f, 0xa7, 0x9f, 0x8d, 0x28, 0x23, 0xa7, 0x81, 0x69, 0x7b, 0x2b, |
|
6138 |
+ 0xd8, 0x52, 0xb6, 0x41, 0x62, 0x52, 0xef, 0x85, 0xcf, 0x24, 0x15, 0xcc, 0x34, 0xb4, 0x15, 0x3c, |
|
6139 |
+ 0x9f, 0xa3, 0x2f, 0xa1, 0xe8, 0x87, 0x64, 0x62, 0xda, 0x90, 0xdc, 0x1d, 0xec, 0x0f, 0xbb, 0x87, |
|
6140 |
+ 0x46, 0x83, 0xbd, 0xca, 0xd5, 0xe5, 0x66, 0x51, 0x19, 0xb0, 0xa6, 0xa1, 0x66, 0xda, 0x09, 0xa8, |
|
6141 |
+ 0x2f, 0xe9, 0xb7, 0xbf, 0x82, 0x33, 0x16, 0xa5, 0x23, 0x9f, 0x79, 0x82, 0x46, 0x91, 0xae, 0x02, |
|
6142 |
+ 0x15, 0x9c, 0x4e, 0x51, 0x03, 0xca, 0xa6, 0x9f, 0xd0, 0x0d, 0x44, 0x55, 0xd5, 0x6a, 0x63, 0xe8, |
|
6143 |
+ 0x6d, 0x80, 0x95, 0x64, 0x63, 0x74, 0x26, 0xf8, 0xa4, 0xfd, 0x9f, 0x22, 0x58, 0xbb, 0x41, 0x1c, |
|
6144 |
+ 0x49, 0x53, 0x06, 0x3f, 0x58, 0xf2, 0x5f, 0xc0, 0x2d, 0xa2, 0x7f, 0xaf, 0x08, 0x53, 0x35, 0x45, |
|
6145 |
+ 0xb7, 0x69, 0xe6, 0x00, 0x1e, 0xe6, 0xba, 0x9b, 0x83, 0x93, 0x96, 0xae, 0x57, 0x52, 0x3e, 0xed, |
|
6146 |
+ 0x02, 0xae, 0x93, 0xd7, 0x56, 0xd0, 0x31, 0x6c, 0x70, 0xe1, 0x8c, 0x69, 0x24, 0x93, 0x4a, 0x64, |
|
6147 |
+ 0x7e, 0x47, 0x72, 0x7f, 0x54, 0x9f, 0x65, 0x81, 0xe6, 0x19, 0x4e, 0xa2, 0x5d, 0xf6, 0x81, 0x1e, |
|
6148 |
+ 0x43, 0x51, 0x90, 0xb3, 0xb4, 0xe5, 0xcc, 0xbd, 0x24, 0x98, 0x9c, 0xc9, 0x25, 0x17, 0x9a, 0x81, |
|
6149 |
+ 0x7e, 0x03, 0xe0, 0xfa, 0x51, 0x48, 0xa4, 0x33, 0xa6, 0xc2, 0x1c, 0x76, 0xee, 0x16, 0xfb, 0x73, |
|
6150 |
+ 0xd4, 0x92, 0x97, 0x0c, 0x1b, 0x1d, 0x40, 0xd5, 0x21, 0xa9, 0x5c, 0x4b, 0xd7, 0xff, 0xa3, 0xed, |
|
6151 |
+ 0x76, 0x8d, 0x8b, 0xba, 0x72, 0x71, 0x75, 0xb9, 0x59, 0x49, 0x2d, 0xb8, 0xe2, 0x10, 0x23, 0xdf, |
|
6152 |
+ 0x03, 0xd8, 0x50, 0xff, 0x6e, 0x23, 0x97, 0x9e, 0x91, 0x38, 0x90, 0x89, 0x4c, 0xae, 0x29, 0x2b, |
|
6153 |
+ 0xea, 0x47, 0xa0, 0x6f, 0x70, 0x26, 0xae, 0x9a, 0xcc, 0xd8, 0xd0, 0xef, 0xe0, 0x16, 0x65, 0x8e, |
|
6154 |
+ 0x98, 0x69, 0xb1, 0xa6, 0x11, 0x56, 0xae, 0xdf, 0xec, 0x60, 0x0e, 0x5e, 0xda, 0x6c, 0x9d, 0xbe, |
|
6155 |
+ 0x66, 0x6f, 0xff, 0xb5, 0x00, 0x90, 0x54, 0xea, 0x0f, 0x2b, 0x40, 0x04, 0x45, 0x97, 0x48, 0xa2, |
|
6156 |
+ 0x35, 0x57, 0xc3, 0x7a, 0x8c, 0xbe, 0x00, 0x90, 0x74, 0x12, 0x06, 0x44, 0xfa, 0xcc, 0x33, 0xb2, |
|
6157 |
+ 0x79, 0xdb, 0x73, 0x90, 0x41, 0xeb, 0x38, 0x93, 0x90, 0xff, 0xaf, 0xe3, 0xec, 0xd9, 0xaf, 0xbe, |
|
6158 |
+ 0x6d, 0xae, 0xfc, 0xe3, 0xdb, 0xe6, 0xca, 0x1f, 0xaf, 0x9a, 0x85, 0x57, 0x57, 0xcd, 0xc2, 0xdf, |
|
6159 |
+ 0xae, 0x9a, 0x85, 0x7f, 0x5e, 0x35, 0x0b, 0xa7, 0x25, 0xdd, 0xc3, 0xfd, 0xe4, 0xbf, 0x01, 0x00, |
|
6160 |
+ 0x00, 0xff, 0xff, 0x06, 0x93, 0x6e, 0xba, 0xfc, 0x12, 0x00, 0x00, |
|
6160 | 6161 |
} |
... | ... |
@@ -386,6 +386,13 @@ message SecretSpec { |
386 | 386 |
|
387 | 387 |
// Data is the secret payload - the maximum size is 500KB (that is, 500*1024 bytes) |
388 | 388 |
bytes data = 2; |
389 |
+ |
|
390 |
+ // Templating controls whether and how to evaluate the secret payload as |
|
391 |
+ // a template. If it is not set, no templating is used. |
|
392 |
+ // |
|
393 |
+ // The currently recognized values are: |
|
394 |
+ // - golang: Go templating |
|
395 |
+ Driver templating = 3; |
|
389 | 396 |
} |
390 | 397 |
|
391 | 398 |
// ConfigSpec specifies user-provided configuration files. |
... | ... |
@@ -396,4 +403,11 @@ message ConfigSpec { |
396 | 396 |
// TODO(aaronl): Do we want to revise this to include multiple payloads in a single |
397 | 397 |
// ConfigSpec? Define this to be a tar? etc... |
398 | 398 |
bytes data = 2; |
399 |
+ |
|
400 |
+ // Templating controls whether and how to evaluate the secret payload as |
|
401 |
+ // a template. If it is not set, no templating is used. |
|
402 |
+ // |
|
403 |
+ // The currently recognized values are: |
|
404 |
+ // - golang: Go templating |
|
405 |
+ Driver templating = 3; |
|
399 | 406 |
} |
... | ... |
@@ -126,6 +126,11 @@ type LocalSigner struct { |
126 | 126 |
cryptoSigner crypto.Signer |
127 | 127 |
} |
128 | 128 |
|
129 |
+type x509UnknownAuthError struct { |
|
130 |
+ error |
|
131 |
+ failedLeafCert *x509.Certificate |
|
132 |
+} |
|
133 |
+ |
|
129 | 134 |
// RootCA is the representation of everything we need to sign certificates and/or to verify certificates |
130 | 135 |
// |
131 | 136 |
// RootCA.Cert: [CA cert1][CA cert2] |
... | ... |
@@ -275,6 +280,17 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWrit |
275 | 275 |
// Create an X509Cert so we can .Verify() |
276 | 276 |
// Check to see if this certificate was signed by our CA, and isn't expired |
277 | 277 |
parsedCerts, chains, err := ValidateCertChain(rca.Pool, signedCert, false) |
278 |
+ // TODO(cyli): - right now we need the invalid certificate in order to determine whether or not we should |
|
279 |
+ // download a new root, because we only want to do that in the case of workers. When we have a single |
|
280 |
+ // codepath for updating the root CAs for both managers and workers, this snippet can go. |
|
281 |
+ if _, ok := err.(x509.UnknownAuthorityError); ok { |
|
282 |
+ if parsedCerts, parseErr := helpers.ParseCertificatesPEM(signedCert); parseErr == nil && len(parsedCerts) > 0 { |
|
283 |
+ return nil, nil, x509UnknownAuthError{ |
|
284 |
+ error: err, |
|
285 |
+ failedLeafCert: parsedCerts[0], |
|
286 |
+ } |
|
287 |
+ } |
|
288 |
+ } |
|
278 | 289 |
if err != nil { |
279 | 290 |
return nil, nil, err |
280 | 291 |
} |
... | ... |
@@ -492,9 +492,35 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite |
492 | 492 |
return secConfig, err |
493 | 493 |
} |
494 | 494 |
|
495 |
+// TODO(cyli): currently we have to only update if it's a worker role - if we have a single root CA update path for |
|
496 |
+// both managers and workers, we won't need to check any more. |
|
497 |
+func updateRootThenUpdateCert(ctx context.Context, s *SecurityConfig, connBroker *connectionbroker.Broker, rootPaths CertPaths, failedCert *x509.Certificate) (*tls.Certificate, *IssuerInfo, error) { |
|
498 |
+ if len(failedCert.Subject.OrganizationalUnit) == 0 || failedCert.Subject.OrganizationalUnit[0] != WorkerRole { |
|
499 |
+ return nil, nil, errors.New("cannot update root CA since this is not a worker") |
|
500 |
+ } |
|
501 |
+ // try downloading a new root CA if it's an unknown authority issue, in case there was a root rotation completion |
|
502 |
+ // and we just didn't get the new root |
|
503 |
+ rootCA, err := GetRemoteCA(ctx, "", connBroker) |
|
504 |
+ if err != nil { |
|
505 |
+ return nil, nil, err |
|
506 |
+ } |
|
507 |
+ // validate against the existing security config creds |
|
508 |
+ if err := s.UpdateRootCA(&rootCA, rootCA.Pool); err != nil { |
|
509 |
+ return nil, nil, err |
|
510 |
+ } |
|
511 |
+ if err := SaveRootCA(rootCA, rootPaths); err != nil { |
|
512 |
+ return nil, nil, err |
|
513 |
+ } |
|
514 |
+ return rootCA.RequestAndSaveNewCertificates(ctx, s.KeyWriter(), |
|
515 |
+ CertificateRequestConfig{ |
|
516 |
+ ConnBroker: connBroker, |
|
517 |
+ Credentials: s.ClientTLSCreds, |
|
518 |
+ }) |
|
519 |
+} |
|
520 |
+ |
|
495 | 521 |
// RenewTLSConfigNow gets a new TLS cert and key, and updates the security config if provided. This is similar to |
496 | 522 |
// RenewTLSConfig, except while that monitors for expiry, and periodically renews, this renews once and is blocking |
497 |
-func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *connectionbroker.Broker) error { |
|
523 |
+func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *connectionbroker.Broker, rootPaths CertPaths) error { |
|
498 | 524 |
s.renewalMu.Lock() |
499 | 525 |
defer s.renewalMu.Unlock() |
500 | 526 |
|
... | ... |
@@ -512,6 +538,15 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne |
512 | 512 |
ConnBroker: connBroker, |
513 | 513 |
Credentials: s.ClientTLSCreds, |
514 | 514 |
}) |
515 |
+ if wrappedError, ok := err.(x509UnknownAuthError); ok { |
|
516 |
+ var newErr error |
|
517 |
+ tlsKeyPair, issuerInfo, newErr = updateRootThenUpdateCert(ctx, s, connBroker, rootPaths, wrappedError.failedLeafCert) |
|
518 |
+ if newErr != nil { |
|
519 |
+ err = wrappedError.error |
|
520 |
+ } else { |
|
521 |
+ err = nil |
|
522 |
+ } |
|
523 |
+ } |
|
515 | 524 |
if err != nil { |
516 | 525 |
log.WithError(err).Errorf("failed to renew the certificate") |
517 | 526 |
return err |
... | ... |
@@ -27,14 +27,16 @@ type TLSRenewer struct { |
27 | 27 |
connBroker *connectionbroker.Broker |
28 | 28 |
renew chan struct{} |
29 | 29 |
expectedRole string |
30 |
+ rootPaths CertPaths |
|
30 | 31 |
} |
31 | 32 |
|
32 | 33 |
// NewTLSRenewer creates a new TLS renewer. It must be started with Start. |
33 |
-func NewTLSRenewer(s *SecurityConfig, connBroker *connectionbroker.Broker) *TLSRenewer { |
|
34 |
+func NewTLSRenewer(s *SecurityConfig, connBroker *connectionbroker.Broker, rootPaths CertPaths) *TLSRenewer { |
|
34 | 35 |
return &TLSRenewer{ |
35 | 36 |
s: s, |
36 | 37 |
connBroker: connBroker, |
37 | 38 |
renew: make(chan struct{}, 1), |
39 |
+ rootPaths: rootPaths, |
|
38 | 40 |
} |
39 | 41 |
} |
40 | 42 |
|
... | ... |
@@ -135,7 +137,7 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate { |
135 | 135 |
|
136 | 136 |
// ignore errors - it will just try again later |
137 | 137 |
var certUpdate CertificateUpdate |
138 |
- if err := RenewTLSConfigNow(ctx, t.s, t.connBroker); err != nil { |
|
138 |
+ if err := RenewTLSConfigNow(ctx, t.s, t.connBroker, t.rootPaths); err != nil { |
|
139 | 139 |
certUpdate.Err = err |
140 | 140 |
expBackoff.Failure(nil, nil) |
141 | 141 |
} else { |
... | ... |
@@ -624,10 +624,6 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error { |
624 | 624 |
if err != nil { |
625 | 625 |
return errors.Wrap(err, "invalid Root CA object in cluster") |
626 | 626 |
} |
627 |
- if err := SaveRootCA(updatedRootCA, s.rootPaths); err != nil { |
|
628 |
- return errors.Wrap(err, "unable to save new root CA certificates") |
|
629 |
- } |
|
630 |
- |
|
631 | 627 |
externalCARootPool := updatedRootCA.Pool |
632 | 628 |
if rCA.RootRotation != nil { |
633 | 629 |
// the external CA has to trust the new CA cert |
... | ... |
@@ -640,6 +636,9 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster) error { |
640 | 640 |
if err := s.securityConfig.UpdateRootCA(&updatedRootCA, externalCARootPool); err != nil { |
641 | 641 |
return errors.Wrap(err, "updating Root CA failed") |
642 | 642 |
} |
643 |
+ if err := SaveRootCA(updatedRootCA, s.rootPaths); err != nil { |
|
644 |
+ return errors.Wrap(err, "unable to save new root CA certificates") |
|
645 |
+ } |
|
643 | 646 |
// only update the server cache if we've successfully updated the root CA |
644 | 647 |
logger.Debugf("Root CA %s successfully", setOrUpdate) |
645 | 648 |
s.lastSeenClusterRootCA = rCA |
... | ... |
@@ -142,6 +142,10 @@ func (na *cnmNetworkAllocator) Allocate(n *api.Network) error { |
142 | 142 |
n.DriverState = &api.Driver{ |
143 | 143 |
Name: d.name, |
144 | 144 |
} |
145 |
+ // In order to support backward compatibility with older daemon |
|
146 |
+ // versions which assumes the network attachment to contains |
|
147 |
+ // non nil IPAM attribute, passing an empty object |
|
148 |
+ n.IPAM = &api.IPAMOptions{Driver: &api.Driver{}} |
|
145 | 149 |
} else { |
146 | 150 |
nw.pools, err = na.allocatePools(n) |
147 | 151 |
if err != nil { |
... | ... |
@@ -59,6 +59,12 @@ type networkContext struct { |
59 | 59 |
// lastRetry is the last timestamp when unallocated |
60 | 60 |
// tasks/services/networks were retried. |
61 | 61 |
lastRetry time.Time |
62 |
+ |
|
63 |
+ // somethingWasDeallocated indicates that we just deallocated at |
|
64 |
+ // least one service/task/network, so we should retry failed |
|
65 |
+ // allocations (in we are experiencing IP exhaustion and an IP was |
|
66 |
+ // released). |
|
67 |
+ somethingWasDeallocated bool |
|
62 | 68 |
} |
63 | 69 |
|
64 | 70 |
func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { |
... | ... |
@@ -226,6 +232,8 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { |
226 | 226 |
// resources. |
227 | 227 |
if err := nc.nwkAllocator.Deallocate(n); err != nil { |
228 | 228 |
log.G(ctx).WithError(err).Errorf("Failed during network free for network %s", n.ID) |
229 |
+ } else { |
|
230 |
+ nc.somethingWasDeallocated = true |
|
229 | 231 |
} |
230 | 232 |
|
231 | 233 |
delete(nc.unallocatedNetworks, n.ID) |
... | ... |
@@ -292,6 +300,8 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { |
292 | 292 |
|
293 | 293 |
if err := nc.nwkAllocator.DeallocateService(s); err != nil { |
294 | 294 |
log.G(ctx).WithError(err).Errorf("Failed deallocation during delete of service %s", s.ID) |
295 |
+ } else { |
|
296 |
+ nc.somethingWasDeallocated = true |
|
295 | 297 |
} |
296 | 298 |
|
297 | 299 |
// Remove it from unallocatedServices just in case |
... | ... |
@@ -304,11 +314,12 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { |
304 | 304 |
case state.EventCommit: |
305 | 305 |
a.procTasksNetwork(ctx, false) |
306 | 306 |
|
307 |
- if time.Since(nc.lastRetry) > retryInterval { |
|
307 |
+ if time.Since(nc.lastRetry) > retryInterval || nc.somethingWasDeallocated { |
|
308 | 308 |
a.procUnallocatedNetworks(ctx) |
309 | 309 |
a.procUnallocatedServices(ctx) |
310 | 310 |
a.procTasksNetwork(ctx, true) |
311 | 311 |
nc.lastRetry = time.Now() |
312 |
+ nc.somethingWasDeallocated = false |
|
312 | 313 |
} |
313 | 314 |
|
314 | 315 |
// Any left over tasks are moved to the unallocated set |
... | ... |
@@ -353,6 +364,8 @@ func (a *Allocator) doNodeAlloc(ctx context.Context, ev events.Event) { |
353 | 353 |
if nc.nwkAllocator.IsNodeAllocated(node) { |
354 | 354 |
if err := nc.nwkAllocator.DeallocateNode(node); err != nil { |
355 | 355 |
log.G(ctx).WithError(err).Errorf("Failed freeing network resources for node %s", node.ID) |
356 |
+ } else { |
|
357 |
+ nc.somethingWasDeallocated = true |
|
356 | 358 |
} |
357 | 359 |
} |
358 | 360 |
return |
... | ... |
@@ -447,6 +460,8 @@ func (a *Allocator) deallocateNodes(ctx context.Context) error { |
447 | 447 |
if nc.nwkAllocator.IsNodeAllocated(node) { |
448 | 448 |
if err := nc.nwkAllocator.DeallocateNode(node); err != nil { |
449 | 449 |
log.G(ctx).WithError(err).Errorf("Failed freeing network resources for node %s", node.ID) |
450 |
+ } else { |
|
451 |
+ nc.somethingWasDeallocated = true |
|
450 | 452 |
} |
451 | 453 |
node.Attachment = nil |
452 | 454 |
if err := a.store.Batch(func(batch *store.Batch) error { |
... | ... |
@@ -695,12 +710,15 @@ func (a *Allocator) doTaskAlloc(ctx context.Context, ev events.Event) { |
695 | 695 |
if nc.nwkAllocator.IsTaskAllocated(t) { |
696 | 696 |
if err := nc.nwkAllocator.DeallocateTask(t); err != nil { |
697 | 697 |
log.G(ctx).WithError(err).Errorf("Failed freeing network resources for task %s", t.ID) |
698 |
+ } else { |
|
699 |
+ nc.somethingWasDeallocated = true |
|
698 | 700 |
} |
699 | 701 |
} |
700 | 702 |
|
701 | 703 |
// Cleanup any task references that might exist |
702 | 704 |
delete(nc.pendingTasks, t.ID) |
703 | 705 |
delete(nc.unallocatedTasks, t.ID) |
706 |
+ |
|
704 | 707 |
return |
705 | 708 |
} |
706 | 709 |
|
... | ... |
@@ -835,6 +853,7 @@ func (a *Allocator) allocateService(ctx context.Context, s *api.Service) error { |
835 | 835 |
if err := nc.nwkAllocator.DeallocateService(s); err != nil { |
836 | 836 |
return err |
837 | 837 |
} |
838 |
+ nc.somethingWasDeallocated = true |
|
838 | 839 |
} |
839 | 840 |
|
840 | 841 |
if err := nc.nwkAllocator.AllocateService(s); err != nil { |
... | ... |
@@ -887,7 +906,7 @@ func (a *Allocator) allocateNetwork(ctx context.Context, n *api.Network) error { |
887 | 887 |
|
888 | 888 |
if err := nc.nwkAllocator.Allocate(n); err != nil { |
889 | 889 |
nc.unallocatedNetworks[n.ID] = n |
890 |
- return errors.Wrapf(err, "failed during network allocation for network %s", n.ID) |
|
890 |
+ return err |
|
891 | 891 |
} |
892 | 892 |
|
893 | 893 |
return nil |
... | ... |
@@ -954,7 +973,6 @@ func (a *Allocator) allocateTask(ctx context.Context, t *api.Task) (err error) { |
954 | 954 |
} |
955 | 955 |
|
956 | 956 |
if err = nc.nwkAllocator.AllocateTask(t); err != nil { |
957 |
- err = errors.Wrapf(err, "failed during network allocation for task %s", t.ID) |
|
958 | 957 |
return |
959 | 958 |
} |
960 | 959 |
if nc.nwkAllocator.IsTaskAllocated(t) { |
... | ... |
@@ -247,6 +247,11 @@ func redactClusters(clusters []*api.Cluster) []*api.Cluster { |
247 | 247 |
// Do not copy secret keys |
248 | 248 |
redactedSpec := cluster.Spec.Copy() |
249 | 249 |
redactedSpec.CAConfig.SigningCAKey = nil |
250 |
+ // the cert is not a secret, but if API users get the cluster spec and then update, |
|
251 |
+ // then because the cert is included but not the key, the user can get update errors |
|
252 |
+ // or unintended consequences (such as telling swarm to forget about the key so long |
|
253 |
+ // as there is a corresponding external CA) |
|
254 |
+ redactedSpec.CAConfig.SigningCACert = nil |
|
250 | 255 |
|
251 | 256 |
redactedRootCA := cluster.RootCA.Copy() |
252 | 257 |
redactedRootCA.CAKey = nil |
... | ... |
@@ -631,7 +631,7 @@ func (d *Dispatcher) processUpdates(ctx context.Context) { |
631 | 631 |
logger.WithError(err).Error("failed to update task status") |
632 | 632 |
return nil |
633 | 633 |
} |
634 |
- logger.Debug("task status updated") |
|
634 |
+ logger.Debug("dispatcher committed status update to store") |
|
635 | 635 |
return nil |
636 | 636 |
}) |
637 | 637 |
if err != nil { |
... | ... |
@@ -698,7 +698,7 @@ func (m *Manager) updateKEK(ctx context.Context, cluster *api.Cluster) error { |
698 | 698 |
|
699 | 699 |
connBroker := connectionbroker.New(remotes.NewRemotes()) |
700 | 700 |
connBroker.SetLocalConn(conn) |
701 |
- if err := ca.RenewTLSConfigNow(ctx, securityConfig, connBroker); err != nil { |
|
701 |
+ if err := ca.RenewTLSConfigNow(ctx, securityConfig, connBroker, m.config.RootCAPaths); err != nil { |
|
702 | 702 |
logger.WithError(err).Error("failed to download new TLS certificate after locking the cluster") |
703 | 703 |
} |
704 | 704 |
}() |
... | ... |
@@ -945,18 +945,19 @@ func (m *Manager) becomeLeader(ctx context.Context) { |
945 | 945 |
if err := store.CreateNetwork(tx, newIngressNetwork()); err != nil { |
946 | 946 |
log.G(ctx).WithError(err).Error("failed to create default ingress network") |
947 | 947 |
} |
948 |
- // Create now the static predefined node-local networks which |
|
949 |
- // are known to be present in each cluster node. This is needed |
|
950 |
- // in order to allow running services on the predefined docker |
|
951 |
- // networks like `bridge` and `host`. |
|
952 |
- log.G(ctx).Info("Creating node-local predefined networks") |
|
953 |
- for _, p := range allocator.PredefinedNetworks() { |
|
948 |
+ } |
|
949 |
+ // Create now the static predefined if the store does not contain predefined |
|
950 |
+ //networks like bridge/host node-local networks which |
|
951 |
+ // are known to be present in each cluster node. This is needed |
|
952 |
+ // in order to allow running services on the predefined docker |
|
953 |
+ // networks like `bridge` and `host`. |
|
954 |
+ for _, p := range allocator.PredefinedNetworks() { |
|
955 |
+ if store.GetNetwork(tx, p.Name) == nil { |
|
954 | 956 |
if err := store.CreateNetwork(tx, newPredefinedNetwork(p.Name, p.Driver)); err != nil { |
955 | 957 |
log.G(ctx).WithError(err).Error("failed to create predefined network " + p.Name) |
956 | 958 |
} |
957 | 959 |
} |
958 | 960 |
} |
959 |
- |
|
960 | 961 |
return nil |
961 | 962 |
}) |
962 | 963 |
|
... | ... |
@@ -1033,7 +1034,7 @@ func (m *Manager) becomeLeader(ctx context.Context) { |
1033 | 1033 |
}(m.constraintEnforcer) |
1034 | 1034 |
|
1035 | 1035 |
go func(taskReaper *taskreaper.TaskReaper) { |
1036 |
- taskReaper.Run() |
|
1036 |
+ taskReaper.Run(ctx) |
|
1037 | 1037 |
}(m.taskReaper) |
1038 | 1038 |
|
1039 | 1039 |
go func(orchestrator *replicated.Orchestrator) { |
... | ... |
@@ -4,7 +4,6 @@ import ( |
4 | 4 |
"sort" |
5 | 5 |
"time" |
6 | 6 |
|
7 |
- "github.com/docker/go-events" |
|
8 | 7 |
"github.com/docker/swarmkit/api" |
9 | 8 |
"github.com/docker/swarmkit/log" |
10 | 9 |
"github.com/docker/swarmkit/manager/state" |
... | ... |
@@ -33,29 +32,28 @@ type TaskReaper struct { |
33 | 33 |
taskHistory int64 |
34 | 34 |
dirty map[instanceTuple]struct{} |
35 | 35 |
orphaned []string |
36 |
- watcher chan events.Event |
|
37 |
- cancelWatch func() |
|
38 | 36 |
stopChan chan struct{} |
39 | 37 |
doneChan chan struct{} |
40 | 38 |
} |
41 | 39 |
|
42 | 40 |
// New creates a new TaskReaper. |
43 | 41 |
func New(store *store.MemoryStore) *TaskReaper { |
44 |
- watcher, cancel := state.Watch(store.WatchQueue(), api.EventCreateTask{}, api.EventUpdateTask{}, api.EventUpdateCluster{}) |
|
45 |
- |
|
46 | 42 |
return &TaskReaper{ |
47 |
- store: store, |
|
48 |
- watcher: watcher, |
|
49 |
- cancelWatch: cancel, |
|
50 |
- dirty: make(map[instanceTuple]struct{}), |
|
51 |
- stopChan: make(chan struct{}), |
|
52 |
- doneChan: make(chan struct{}), |
|
43 |
+ store: store, |
|
44 |
+ dirty: make(map[instanceTuple]struct{}), |
|
45 |
+ stopChan: make(chan struct{}), |
|
46 |
+ doneChan: make(chan struct{}), |
|
53 | 47 |
} |
54 | 48 |
} |
55 | 49 |
|
56 | 50 |
// Run is the TaskReaper's main loop. |
57 |
-func (tr *TaskReaper) Run() { |
|
58 |
- defer close(tr.doneChan) |
|
51 |
+func (tr *TaskReaper) Run(ctx context.Context) { |
|
52 |
+ watcher, watchCancel := state.Watch(tr.store.WatchQueue(), api.EventCreateTask{}, api.EventUpdateTask{}, api.EventUpdateCluster{}) |
|
53 |
+ |
|
54 |
+ defer func() { |
|
55 |
+ close(tr.doneChan) |
|
56 |
+ watchCancel() |
|
57 |
+ }() |
|
59 | 58 |
|
60 | 59 |
var tasks []*api.Task |
61 | 60 |
tr.store.View(func(readTx store.ReadTx) { |
... | ... |
@@ -68,7 +66,7 @@ func (tr *TaskReaper) Run() { |
68 | 68 |
|
69 | 69 |
tasks, err = store.FindTasks(readTx, store.ByTaskState(api.TaskStateOrphaned)) |
70 | 70 |
if err != nil { |
71 |
- log.G(context.TODO()).WithError(err).Error("failed to find Orphaned tasks in task reaper init") |
|
71 |
+ log.G(ctx).WithError(err).Error("failed to find Orphaned tasks in task reaper init") |
|
72 | 72 |
} |
73 | 73 |
}) |
74 | 74 |
|
... | ... |
@@ -91,7 +89,7 @@ func (tr *TaskReaper) Run() { |
91 | 91 |
|
92 | 92 |
for { |
93 | 93 |
select { |
94 |
- case event := <-tr.watcher: |
|
94 |
+ case event := <-watcher: |
|
95 | 95 |
switch v := event.(type) { |
96 | 96 |
case api.EventCreateTask: |
97 | 97 |
t := v.Task |
... | ... |
@@ -218,7 +216,6 @@ func (tr *TaskReaper) tick() { |
218 | 218 |
|
219 | 219 |
// Stop stops the TaskReaper and waits for the main loop to exit. |
220 | 220 |
func (tr *TaskReaper) Stop() { |
221 |
- tr.cancelWatch() |
|
222 | 221 |
close(tr.stopChan) |
223 | 222 |
<-tr.doneChan |
224 | 223 |
} |
... | ... |
@@ -128,7 +128,7 @@ func (f *PluginFilter) SetTask(t *api.Task) bool { |
128 | 128 |
} |
129 | 129 |
} |
130 | 130 |
|
131 |
- if (c != nil && volumeTemplates) || len(t.Networks) > 0 { |
|
131 |
+ if (c != nil && volumeTemplates) || len(t.Networks) > 0 || t.Spec.LogDriver != nil { |
|
132 | 132 |
f.t = t |
133 | 133 |
return true |
134 | 134 |
} |
... | ... |
@@ -153,7 +153,7 @@ func (f *PluginFilter) Check(n *NodeInfo) bool { |
153 | 153 |
if container != nil { |
154 | 154 |
for _, mount := range container.Mounts { |
155 | 155 |
if referencesVolumePlugin(mount) { |
156 |
- if !f.pluginExistsOnNode("Volume", mount.VolumeOptions.DriverConfig.Name, nodePlugins) { |
|
156 |
+ if _, exists := f.pluginExistsOnNode("Volume", mount.VolumeOptions.DriverConfig.Name, nodePlugins); !exists { |
|
157 | 157 |
return false |
158 | 158 |
} |
159 | 159 |
} |
... | ... |
@@ -163,22 +163,34 @@ func (f *PluginFilter) Check(n *NodeInfo) bool { |
163 | 163 |
// Check if all network plugins required by task are installed on node |
164 | 164 |
for _, tn := range f.t.Networks { |
165 | 165 |
if tn.Network != nil && tn.Network.DriverState != nil && tn.Network.DriverState.Name != "" { |
166 |
- if !f.pluginExistsOnNode("Network", tn.Network.DriverState.Name, nodePlugins) { |
|
166 |
+ if _, exists := f.pluginExistsOnNode("Network", tn.Network.DriverState.Name, nodePlugins); !exists { |
|
167 | 167 |
return false |
168 | 168 |
} |
169 | 169 |
} |
170 | 170 |
} |
171 |
+ |
|
172 |
+ if f.t.Spec.LogDriver != nil { |
|
173 |
+ // If there are no log driver types in the list at all, most likely this is |
|
174 |
+ // an older daemon that did not report this information. In this case don't filter |
|
175 |
+ if typeFound, exists := f.pluginExistsOnNode("Log", f.t.Spec.LogDriver.Name, nodePlugins); !exists && typeFound { |
|
176 |
+ return false |
|
177 |
+ } |
|
178 |
+ } |
|
171 | 179 |
return true |
172 | 180 |
} |
173 | 181 |
|
174 | 182 |
// pluginExistsOnNode returns true if the (pluginName, pluginType) pair is present in nodePlugins |
175 |
-func (f *PluginFilter) pluginExistsOnNode(pluginType string, pluginName string, nodePlugins []api.PluginDescription) bool { |
|
183 |
+func (f *PluginFilter) pluginExistsOnNode(pluginType string, pluginName string, nodePlugins []api.PluginDescription) (bool, bool) { |
|
184 |
+ var typeFound bool |
|
185 |
+ |
|
176 | 186 |
for _, np := range nodePlugins { |
177 | 187 |
if pluginType != np.Type { |
178 | 188 |
continue |
179 | 189 |
} |
190 |
+ typeFound = true |
|
191 |
+ |
|
180 | 192 |
if pluginName == np.Name { |
181 |
- return true |
|
193 |
+ return true, true |
|
182 | 194 |
} |
183 | 195 |
// This does not use the reference package to avoid the |
184 | 196 |
// overhead of parsing references as part of the scheduling |
... | ... |
@@ -186,10 +198,10 @@ func (f *PluginFilter) pluginExistsOnNode(pluginType string, pluginName string, |
186 | 186 |
// strict subset of the reference grammar that is always |
187 | 187 |
// name:tag. |
188 | 188 |
if strings.HasPrefix(np.Name, pluginName) && np.Name[len(pluginName):] == ":latest" { |
189 |
- return true |
|
189 |
+ return true, true |
|
190 | 190 |
} |
191 | 191 |
} |
192 |
- return false |
|
192 |
+ return typeFound, false |
|
193 | 193 |
} |
194 | 194 |
|
195 | 195 |
// Explain returns an explanation of a failure. |
... | ... |
@@ -63,6 +63,15 @@ func (nodeInfo *NodeInfo) removeTask(t *api.Task) bool { |
63 | 63 |
nodeInfo.ActiveTasksCountByService[t.ServiceID]-- |
64 | 64 |
} |
65 | 65 |
|
66 |
+ if t.Endpoint != nil { |
|
67 |
+ for _, port := range t.Endpoint.Ports { |
|
68 |
+ if port.PublishMode == api.PublishModeHost && port.PublishedPort != 0 { |
|
69 |
+ portSpec := hostPortSpec{protocol: port.Protocol, publishedPort: port.PublishedPort} |
|
70 |
+ delete(nodeInfo.usedHostPorts, portSpec) |
|
71 |
+ } |
|
72 |
+ } |
|
73 |
+ } |
|
74 |
+ |
|
66 | 75 |
reservations := taskReservations(t.Spec) |
67 | 76 |
resources := nodeInfo.AvailableResources |
68 | 77 |
|
... | ... |
@@ -79,15 +88,6 @@ func (nodeInfo *NodeInfo) removeTask(t *api.Task) bool { |
79 | 79 |
nodeRes := nodeInfo.Description.Resources.Generic |
80 | 80 |
genericresource.Reclaim(nodeAvailableResources, taskAssigned, nodeRes) |
81 | 81 |
|
82 |
- if t.Endpoint != nil { |
|
83 |
- for _, port := range t.Endpoint.Ports { |
|
84 |
- if port.PublishMode == api.PublishModeHost && port.PublishedPort != 0 { |
|
85 |
- portSpec := hostPortSpec{protocol: port.Protocol, publishedPort: port.PublishedPort} |
|
86 |
- delete(nodeInfo.usedHostPorts, portSpec) |
|
87 |
- } |
|
88 |
- } |
|
89 |
- } |
|
90 |
- |
|
91 | 82 |
return true |
92 | 83 |
} |
93 | 84 |
|
... | ... |
@@ -4,7 +4,6 @@ import ( |
4 | 4 |
"container/heap" |
5 | 5 |
"errors" |
6 | 6 |
"strings" |
7 |
- "time" |
|
8 | 7 |
|
9 | 8 |
"github.com/docker/swarmkit/api" |
10 | 9 |
"github.com/docker/swarmkit/manager/constraint" |
... | ... |
@@ -32,16 +31,6 @@ func (ns *nodeSet) nodeInfo(nodeID string) (NodeInfo, error) { |
32 | 32 |
// addOrUpdateNode sets the number of tasks for a given node. It adds the node |
33 | 33 |
// to the set if it wasn't already tracked. |
34 | 34 |
func (ns *nodeSet) addOrUpdateNode(n NodeInfo) { |
35 |
- if n.Tasks == nil { |
|
36 |
- n.Tasks = make(map[string]*api.Task) |
|
37 |
- } |
|
38 |
- if n.ActiveTasksCountByService == nil { |
|
39 |
- n.ActiveTasksCountByService = make(map[string]int) |
|
40 |
- } |
|
41 |
- if n.recentFailures == nil { |
|
42 |
- n.recentFailures = make(map[string][]time.Time) |
|
43 |
- } |
|
44 |
- |
|
45 | 35 |
ns.nodes[n.ID] = n |
46 | 36 |
} |
47 | 37 |
|
... | ... |
@@ -31,8 +31,11 @@ type schedulingDecision struct { |
31 | 31 |
type Scheduler struct { |
32 | 32 |
store *store.MemoryStore |
33 | 33 |
unassignedTasks map[string]*api.Task |
34 |
- // preassignedTasks already have NodeID, need resource validation |
|
35 |
- preassignedTasks map[string]*api.Task |
|
34 |
+ // pendingPreassignedTasks already have NodeID, need resource validation |
|
35 |
+ pendingPreassignedTasks map[string]*api.Task |
|
36 |
+ // preassignedTasks tracks tasks that were preassigned, including those |
|
37 |
+ // past the pending state. |
|
38 |
+ preassignedTasks map[string]struct{} |
|
36 | 39 |
nodeSet nodeSet |
37 | 40 |
allTasks map[string]*api.Task |
38 | 41 |
pipeline *Pipeline |
... | ... |
@@ -46,13 +49,14 @@ type Scheduler struct { |
46 | 46 |
// New creates a new scheduler. |
47 | 47 |
func New(store *store.MemoryStore) *Scheduler { |
48 | 48 |
return &Scheduler{ |
49 |
- store: store, |
|
50 |
- unassignedTasks: make(map[string]*api.Task), |
|
51 |
- preassignedTasks: make(map[string]*api.Task), |
|
52 |
- allTasks: make(map[string]*api.Task), |
|
53 |
- stopChan: make(chan struct{}), |
|
54 |
- doneChan: make(chan struct{}), |
|
55 |
- pipeline: NewPipeline(), |
|
49 |
+ store: store, |
|
50 |
+ unassignedTasks: make(map[string]*api.Task), |
|
51 |
+ pendingPreassignedTasks: make(map[string]*api.Task), |
|
52 |
+ preassignedTasks: make(map[string]struct{}), |
|
53 |
+ allTasks: make(map[string]*api.Task), |
|
54 |
+ stopChan: make(chan struct{}), |
|
55 |
+ doneChan: make(chan struct{}), |
|
56 |
+ pipeline: NewPipeline(), |
|
56 | 57 |
} |
57 | 58 |
} |
58 | 59 |
|
... | ... |
@@ -77,7 +81,8 @@ func (s *Scheduler) setupTasksList(tx store.ReadTx) error { |
77 | 77 |
} |
78 | 78 |
// preassigned tasks need to validate resource requirement on corresponding node |
79 | 79 |
if t.Status.State == api.TaskStatePending { |
80 |
- s.preassignedTasks[t.ID] = t |
|
80 |
+ s.preassignedTasks[t.ID] = struct{}{} |
|
81 |
+ s.pendingPreassignedTasks[t.ID] = t |
|
81 | 82 |
continue |
82 | 83 |
} |
83 | 84 |
|
... | ... |
@@ -129,7 +134,7 @@ func (s *Scheduler) Run(ctx context.Context) error { |
129 | 129 |
tickRequired := false |
130 | 130 |
|
131 | 131 |
schedule := func() { |
132 |
- if len(s.preassignedTasks) > 0 { |
|
132 |
+ if len(s.pendingPreassignedTasks) > 0 { |
|
133 | 133 |
s.processPreassignedTasks(ctx) |
134 | 134 |
} |
135 | 135 |
if tickRequired { |
... | ... |
@@ -152,7 +157,7 @@ func (s *Scheduler) Run(ctx context.Context) error { |
152 | 152 |
tickRequired = true |
153 | 153 |
} |
154 | 154 |
case api.EventDeleteTask: |
155 |
- if s.deleteTask(ctx, v.Task) { |
|
155 |
+ if s.deleteTask(v.Task) { |
|
156 | 156 |
// deleting tasks may free up node resource, pending tasks should be re-evaluated. |
157 | 157 |
tickRequired = true |
158 | 158 |
} |
... | ... |
@@ -216,7 +221,8 @@ func (s *Scheduler) createTask(ctx context.Context, t *api.Task) bool { |
216 | 216 |
} |
217 | 217 |
|
218 | 218 |
if t.Status.State == api.TaskStatePending { |
219 |
- s.preassignedTasks[t.ID] = t |
|
219 |
+ s.preassignedTasks[t.ID] = struct{}{} |
|
220 |
+ s.pendingPreassignedTasks[t.ID] = t |
|
220 | 221 |
// preassigned tasks do not contribute to running tasks count |
221 | 222 |
return false |
222 | 223 |
} |
... | ... |
@@ -244,22 +250,32 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) bool { |
244 | 244 |
if oldTask == nil { |
245 | 245 |
return false |
246 | 246 |
} |
247 |
- s.deleteTask(ctx, oldTask) |
|
247 |
+ |
|
248 | 248 |
if t.Status.State != oldTask.Status.State && |
249 | 249 |
(t.Status.State == api.TaskStateFailed || t.Status.State == api.TaskStateRejected) { |
250 |
- nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID) |
|
251 |
- if err == nil { |
|
252 |
- nodeInfo.taskFailed(ctx, t.ServiceID) |
|
253 |
- s.nodeSet.updateNode(nodeInfo) |
|
250 |
+ // Keep track of task failures, so other nodes can be preferred |
|
251 |
+ // for scheduling this service if it looks like the service is |
|
252 |
+ // failing in a loop on this node. However, skip this for |
|
253 |
+ // preassigned tasks, because the scheduler does not choose |
|
254 |
+ // which nodes those run on. |
|
255 |
+ if _, wasPreassigned := s.preassignedTasks[t.ID]; !wasPreassigned { |
|
256 |
+ nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID) |
|
257 |
+ if err == nil { |
|
258 |
+ nodeInfo.taskFailed(ctx, t.ServiceID) |
|
259 |
+ s.nodeSet.updateNode(nodeInfo) |
|
260 |
+ } |
|
254 | 261 |
} |
255 | 262 |
} |
263 |
+ |
|
264 |
+ s.deleteTask(oldTask) |
|
265 |
+ |
|
256 | 266 |
return true |
257 | 267 |
} |
258 | 268 |
|
259 | 269 |
if t.NodeID == "" { |
260 | 270 |
// unassigned task |
261 | 271 |
if oldTask != nil { |
262 |
- s.deleteTask(ctx, oldTask) |
|
272 |
+ s.deleteTask(oldTask) |
|
263 | 273 |
} |
264 | 274 |
s.allTasks[t.ID] = t |
265 | 275 |
s.enqueue(t) |
... | ... |
@@ -268,10 +284,11 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) bool { |
268 | 268 |
|
269 | 269 |
if t.Status.State == api.TaskStatePending { |
270 | 270 |
if oldTask != nil { |
271 |
- s.deleteTask(ctx, oldTask) |
|
271 |
+ s.deleteTask(oldTask) |
|
272 | 272 |
} |
273 |
+ s.preassignedTasks[t.ID] = struct{}{} |
|
273 | 274 |
s.allTasks[t.ID] = t |
274 |
- s.preassignedTasks[t.ID] = t |
|
275 |
+ s.pendingPreassignedTasks[t.ID] = t |
|
275 | 276 |
// preassigned tasks do not contribute to running tasks count |
276 | 277 |
return false |
277 | 278 |
} |
... | ... |
@@ -285,9 +302,10 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) bool { |
285 | 285 |
return false |
286 | 286 |
} |
287 | 287 |
|
288 |
-func (s *Scheduler) deleteTask(ctx context.Context, t *api.Task) bool { |
|
288 |
+func (s *Scheduler) deleteTask(t *api.Task) bool { |
|
289 | 289 |
delete(s.allTasks, t.ID) |
290 | 290 |
delete(s.preassignedTasks, t.ID) |
291 |
+ delete(s.pendingPreassignedTasks, t.ID) |
|
291 | 292 |
nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID) |
292 | 293 |
if err == nil && nodeInfo.removeTask(t) { |
293 | 294 |
s.nodeSet.updateNode(nodeInfo) |
... | ... |
@@ -297,31 +315,38 @@ func (s *Scheduler) deleteTask(ctx context.Context, t *api.Task) bool { |
297 | 297 |
} |
298 | 298 |
|
299 | 299 |
func (s *Scheduler) createOrUpdateNode(n *api.Node) { |
300 |
- nodeInfo, _ := s.nodeSet.nodeInfo(n.ID) |
|
300 |
+ nodeInfo, nodeInfoErr := s.nodeSet.nodeInfo(n.ID) |
|
301 | 301 |
var resources *api.Resources |
302 | 302 |
if n.Description != nil && n.Description.Resources != nil { |
303 | 303 |
resources = n.Description.Resources.Copy() |
304 | 304 |
// reconcile resources by looping over all tasks in this node |
305 |
- for _, task := range nodeInfo.Tasks { |
|
306 |
- reservations := taskReservations(task.Spec) |
|
305 |
+ if nodeInfoErr == nil { |
|
306 |
+ for _, task := range nodeInfo.Tasks { |
|
307 |
+ reservations := taskReservations(task.Spec) |
|
307 | 308 |
|
308 |
- resources.MemoryBytes -= reservations.MemoryBytes |
|
309 |
- resources.NanoCPUs -= reservations.NanoCPUs |
|
309 |
+ resources.MemoryBytes -= reservations.MemoryBytes |
|
310 |
+ resources.NanoCPUs -= reservations.NanoCPUs |
|
310 | 311 |
|
311 |
- genericresource.ConsumeNodeResources(&resources.Generic, |
|
312 |
- task.AssignedGenericResources) |
|
312 |
+ genericresource.ConsumeNodeResources(&resources.Generic, |
|
313 |
+ task.AssignedGenericResources) |
|
314 |
+ } |
|
313 | 315 |
} |
314 | 316 |
} else { |
315 | 317 |
resources = &api.Resources{} |
316 | 318 |
} |
317 |
- nodeInfo.Node = n |
|
318 |
- nodeInfo.AvailableResources = resources |
|
319 |
+ |
|
320 |
+ if nodeInfoErr != nil { |
|
321 |
+ nodeInfo = newNodeInfo(n, nil, *resources) |
|
322 |
+ } else { |
|
323 |
+ nodeInfo.Node = n |
|
324 |
+ nodeInfo.AvailableResources = resources |
|
325 |
+ } |
|
319 | 326 |
s.nodeSet.addOrUpdateNode(nodeInfo) |
320 | 327 |
} |
321 | 328 |
|
322 | 329 |
func (s *Scheduler) processPreassignedTasks(ctx context.Context) { |
323 |
- schedulingDecisions := make(map[string]schedulingDecision, len(s.preassignedTasks)) |
|
324 |
- for _, t := range s.preassignedTasks { |
|
330 |
+ schedulingDecisions := make(map[string]schedulingDecision, len(s.pendingPreassignedTasks)) |
|
331 |
+ for _, t := range s.pendingPreassignedTasks { |
|
325 | 332 |
newT := s.taskFitNode(ctx, t, t.NodeID) |
326 | 333 |
if newT == nil { |
327 | 334 |
continue |
... | ... |
@@ -333,7 +358,7 @@ func (s *Scheduler) processPreassignedTasks(ctx context.Context) { |
333 | 333 |
|
334 | 334 |
for _, decision := range successful { |
335 | 335 |
if decision.new.Status.State == api.TaskStateAssigned { |
336 |
- delete(s.preassignedTasks, decision.old.ID) |
|
336 |
+ delete(s.pendingPreassignedTasks, decision.old.ID) |
|
337 | 337 |
} |
338 | 338 |
} |
339 | 339 |
for _, decision := range failed { |
... | ... |
@@ -421,12 +446,7 @@ func (s *Scheduler) applySchedulingDecisions(ctx context.Context, schedulingDeci |
421 | 421 |
t := store.GetTask(tx, taskID) |
422 | 422 |
if t == nil { |
423 | 423 |
// Task no longer exists |
424 |
- nodeInfo, err := s.nodeSet.nodeInfo(decision.new.NodeID) |
|
425 |
- if err == nil && nodeInfo.removeTask(decision.new) { |
|
426 |
- s.nodeSet.updateNode(nodeInfo) |
|
427 |
- } |
|
428 |
- delete(s.allTasks, decision.old.ID) |
|
429 |
- |
|
424 |
+ s.deleteTask(decision.new) |
|
430 | 425 |
continue |
431 | 426 |
} |
432 | 427 |
|
... | ... |
@@ -281,7 +281,7 @@ func (n *Node) run(ctx context.Context) (err error) { |
281 | 281 |
return err |
282 | 282 |
} |
283 | 283 |
|
284 |
- renewer := ca.NewTLSRenewer(securityConfig, n.connBroker) |
|
284 |
+ renewer := ca.NewTLSRenewer(securityConfig, n.connBroker, paths.RootCA) |
|
285 | 285 |
|
286 | 286 |
ctx = log.WithLogger(ctx, log.G(ctx).WithField("node.id", n.NodeID())) |
287 | 287 |
|
... | ... |
@@ -3,13 +3,22 @@ package template |
3 | 3 |
import ( |
4 | 4 |
"bytes" |
5 | 5 |
"fmt" |
6 |
+ "strings" |
|
7 |
+ "text/template" |
|
6 | 8 |
|
9 |
+ "github.com/docker/swarmkit/agent/configs" |
|
10 |
+ "github.com/docker/swarmkit/agent/exec" |
|
11 |
+ "github.com/docker/swarmkit/agent/secrets" |
|
7 | 12 |
"github.com/docker/swarmkit/api" |
8 | 13 |
"github.com/docker/swarmkit/api/naming" |
14 |
+ "github.com/pkg/errors" |
|
9 | 15 |
) |
10 | 16 |
|
11 | 17 |
// Context defines the strict set of values that can be injected into a |
12 | 18 |
// template expression in SwarmKit data structure. |
19 |
+// NOTE: Be very careful adding any fields to this structure with types |
|
20 |
+// that have methods defined on them. The template would be able to |
|
21 |
+// invoke those methods. |
|
13 | 22 |
type Context struct { |
14 | 23 |
Service struct { |
15 | 24 |
ID string |
... | ... |
@@ -58,7 +67,118 @@ func NewContextFromTask(t *api.Task) (ctx Context) { |
58 | 58 |
// Expand treats the string s as a template and populates it with values from |
59 | 59 |
// the context. |
60 | 60 |
func (ctx *Context) Expand(s string) (string, error) { |
61 |
- tmpl, err := newTemplate(s) |
|
61 |
+ tmpl, err := newTemplate(s, nil) |
|
62 |
+ if err != nil { |
|
63 |
+ return s, err |
|
64 |
+ } |
|
65 |
+ |
|
66 |
+ var buf bytes.Buffer |
|
67 |
+ if err := tmpl.Execute(&buf, ctx); err != nil { |
|
68 |
+ return s, err |
|
69 |
+ } |
|
70 |
+ |
|
71 |
+ return buf.String(), nil |
|
72 |
+} |
|
73 |
+ |
|
74 |
+// PayloadContext provides a context for expanding a config or secret payload. |
|
75 |
+// NOTE: Be very careful adding any fields to this structure with types |
|
76 |
+// that have methods defined on them. The template would be able to |
|
77 |
+// invoke those methods. |
|
78 |
+type PayloadContext struct { |
|
79 |
+ Context |
|
80 |
+ |
|
81 |
+ t *api.Task |
|
82 |
+ restrictedSecrets exec.SecretGetter |
|
83 |
+ restrictedConfigs exec.ConfigGetter |
|
84 |
+} |
|
85 |
+ |
|
86 |
+func (ctx PayloadContext) secretGetter(target string) (string, error) { |
|
87 |
+ if ctx.restrictedSecrets == nil { |
|
88 |
+ return "", errors.New("secrets unavailable") |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ container := ctx.t.Spec.GetContainer() |
|
92 |
+ if container == nil { |
|
93 |
+ return "", errors.New("task is not a container") |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ for _, secretRef := range container.Secrets { |
|
97 |
+ file := secretRef.GetFile() |
|
98 |
+ if file != nil && file.Name == target { |
|
99 |
+ secret, err := ctx.restrictedSecrets.Get(secretRef.SecretID) |
|
100 |
+ if err != nil { |
|
101 |
+ return "", err |
|
102 |
+ } |
|
103 |
+ return string(secret.Spec.Data), nil |
|
104 |
+ } |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ return "", errors.Errorf("secret target %s not found", target) |
|
108 |
+} |
|
109 |
+ |
|
110 |
+func (ctx PayloadContext) configGetter(target string) (string, error) { |
|
111 |
+ if ctx.restrictedConfigs == nil { |
|
112 |
+ return "", errors.New("configs unavailable") |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ container := ctx.t.Spec.GetContainer() |
|
116 |
+ if container == nil { |
|
117 |
+ return "", errors.New("task is not a container") |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ for _, configRef := range container.Configs { |
|
121 |
+ file := configRef.GetFile() |
|
122 |
+ if file != nil && file.Name == target { |
|
123 |
+ config, err := ctx.restrictedConfigs.Get(configRef.ConfigID) |
|
124 |
+ if err != nil { |
|
125 |
+ return "", err |
|
126 |
+ } |
|
127 |
+ return string(config.Spec.Data), nil |
|
128 |
+ } |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ return "", errors.Errorf("config target %s not found", target) |
|
132 |
+} |
|
133 |
+ |
|
134 |
+func (ctx PayloadContext) envGetter(variable string) (string, error) { |
|
135 |
+ container := ctx.t.Spec.GetContainer() |
|
136 |
+ if container == nil { |
|
137 |
+ return "", errors.New("task is not a container") |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ for _, env := range container.Env { |
|
141 |
+ parts := strings.SplitN(env, "=", 2) |
|
142 |
+ |
|
143 |
+ if len(parts) > 1 && parts[0] == variable { |
|
144 |
+ return parts[1], nil |
|
145 |
+ } |
|
146 |
+ } |
|
147 |
+ return "", nil |
|
148 |
+} |
|
149 |
+ |
|
150 |
+// NewPayloadContextFromTask returns a new template context from the data |
|
151 |
+// available in the task. This context also provides access to the configs |
|
152 |
+// and secrets that the task has access to. The provided context can then |
|
153 |
+// be used to populate runtime values in a templated config or secret. |
|
154 |
+func NewPayloadContextFromTask(t *api.Task, dependencies exec.DependencyGetter) (ctx PayloadContext) { |
|
155 |
+ return PayloadContext{ |
|
156 |
+ Context: NewContextFromTask(t), |
|
157 |
+ t: t, |
|
158 |
+ restrictedSecrets: secrets.Restrict(dependencies.Secrets(), t), |
|
159 |
+ restrictedConfigs: configs.Restrict(dependencies.Configs(), t), |
|
160 |
+ } |
|
161 |
+} |
|
162 |
+ |
|
163 |
+// Expand treats the string s as a template and populates it with values from |
|
164 |
+// the context. |
|
165 |
+func (ctx *PayloadContext) Expand(s string) (string, error) { |
|
166 |
+ funcMap := template.FuncMap{ |
|
167 |
+ "secret": ctx.secretGetter, |
|
168 |
+ "config": ctx.configGetter, |
|
169 |
+ "env": ctx.envGetter, |
|
170 |
+ } |
|
171 |
+ |
|
172 |
+ tmpl, err := newTemplate(s, funcMap) |
|
62 | 173 |
if err != nil { |
63 | 174 |
return s, err |
64 | 175 |
} |
... | ... |
@@ -4,6 +4,7 @@ import ( |
4 | 4 |
"fmt" |
5 | 5 |
"strings" |
6 | 6 |
|
7 |
+ "github.com/docker/swarmkit/agent/exec" |
|
7 | 8 |
"github.com/docker/swarmkit/api" |
8 | 9 |
"github.com/pkg/errors" |
9 | 10 |
) |
... | ... |
@@ -116,3 +117,45 @@ func expandEnv(ctx Context, values []string) ([]string, error) { |
116 | 116 |
|
117 | 117 |
return result, nil |
118 | 118 |
} |
119 |
+ |
|
120 |
+func expandPayload(ctx PayloadContext, payload []byte) ([]byte, error) { |
|
121 |
+ result, err := ctx.Expand(string(payload)) |
|
122 |
+ if err != nil { |
|
123 |
+ return payload, err |
|
124 |
+ } |
|
125 |
+ return []byte(result), nil |
|
126 |
+} |
|
127 |
+ |
|
128 |
+// ExpandSecretSpec expands the template inside the secret payload, if any. |
|
129 |
+// Templating is evaluated on the agent-side. |
|
130 |
+func ExpandSecretSpec(s *api.Secret, t *api.Task, dependencies exec.DependencyGetter) (*api.SecretSpec, error) { |
|
131 |
+ if s.Spec.Templating == nil { |
|
132 |
+ return &s.Spec, nil |
|
133 |
+ } |
|
134 |
+ if s.Spec.Templating.Name == "golang" { |
|
135 |
+ ctx := NewPayloadContextFromTask(t, dependencies) |
|
136 |
+ secretSpec := s.Spec.Copy() |
|
137 |
+ |
|
138 |
+ var err error |
|
139 |
+ secretSpec.Data, err = expandPayload(ctx, secretSpec.Data) |
|
140 |
+ return secretSpec, err |
|
141 |
+ } |
|
142 |
+ return &s.Spec, errors.New("unrecognized template type") |
|
143 |
+} |
|
144 |
+ |
|
145 |
+// ExpandConfigSpec expands the template inside the config payload, if any. |
|
146 |
+// Templating is evaluated on the agent-side. |
|
147 |
+func ExpandConfigSpec(c *api.Config, t *api.Task, dependencies exec.DependencyGetter) (*api.ConfigSpec, error) { |
|
148 |
+ if c.Spec.Templating == nil { |
|
149 |
+ return &c.Spec, nil |
|
150 |
+ } |
|
151 |
+ if c.Spec.Templating.Name == "golang" { |
|
152 |
+ ctx := NewPayloadContextFromTask(t, dependencies) |
|
153 |
+ configSpec := c.Spec.Copy() |
|
154 |
+ |
|
155 |
+ var err error |
|
156 |
+ configSpec.Data, err = expandPayload(ctx, configSpec.Data) |
|
157 |
+ return configSpec, err |
|
158 |
+ } |
|
159 |
+ return &c.Spec, errors.New("unrecognized template type") |
|
160 |
+} |
119 | 161 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,98 @@ |
0 |
+package template |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "github.com/docker/swarmkit/agent/exec" |
|
4 |
+ "github.com/docker/swarmkit/api" |
|
5 |
+ "github.com/pkg/errors" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+type templatedSecretGetter struct { |
|
9 |
+ dependencies exec.DependencyGetter |
|
10 |
+ t *api.Task |
|
11 |
+} |
|
12 |
+ |
|
13 |
+// NewTemplatedSecretGetter returns a SecretGetter that evaluates templates. |
|
14 |
+func NewTemplatedSecretGetter(dependencies exec.DependencyGetter, t *api.Task) exec.SecretGetter { |
|
15 |
+ return templatedSecretGetter{dependencies: dependencies, t: t} |
|
16 |
+} |
|
17 |
+ |
|
18 |
+func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) { |
|
19 |
+ if t.dependencies == nil { |
|
20 |
+ return nil, errors.New("no secret provider available") |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ secrets := t.dependencies.Secrets() |
|
24 |
+ if secrets == nil { |
|
25 |
+ return nil, errors.New("no secret provider available") |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ secret, err := secrets.Get(secretID) |
|
29 |
+ if err != nil { |
|
30 |
+ return secret, err |
|
31 |
+ } |
|
32 |
+ |
|
33 |
+ newSpec, err := ExpandSecretSpec(secret, t.t, t.dependencies) |
|
34 |
+ if err != nil { |
|
35 |
+ return secret, errors.Wrapf(err, "failed to expand templated secret %s", secretID) |
|
36 |
+ } |
|
37 |
+ |
|
38 |
+ secretCopy := *secret |
|
39 |
+ secretCopy.Spec = *newSpec |
|
40 |
+ return &secretCopy, nil |
|
41 |
+} |
|
42 |
+ |
|
43 |
+type templatedConfigGetter struct { |
|
44 |
+ dependencies exec.DependencyGetter |
|
45 |
+ t *api.Task |
|
46 |
+} |
|
47 |
+ |
|
48 |
+// NewTemplatedConfigGetter returns a ConfigGetter that evaluates templates. |
|
49 |
+func NewTemplatedConfigGetter(dependencies exec.DependencyGetter, t *api.Task) exec.ConfigGetter { |
|
50 |
+ return templatedConfigGetter{dependencies: dependencies, t: t} |
|
51 |
+} |
|
52 |
+ |
|
53 |
+func (t templatedConfigGetter) Get(configID string) (*api.Config, error) { |
|
54 |
+ if t.dependencies == nil { |
|
55 |
+ return nil, errors.New("no config provider available") |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ configs := t.dependencies.Configs() |
|
59 |
+ if configs == nil { |
|
60 |
+ return nil, errors.New("no config provider available") |
|
61 |
+ } |
|
62 |
+ |
|
63 |
+ config, err := configs.Get(configID) |
|
64 |
+ if err != nil { |
|
65 |
+ return config, err |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ newSpec, err := ExpandConfigSpec(config, t.t, t.dependencies) |
|
69 |
+ if err != nil { |
|
70 |
+ return config, errors.Wrapf(err, "failed to expand templated config %s", configID) |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ configCopy := *config |
|
74 |
+ configCopy.Spec = *newSpec |
|
75 |
+ return &configCopy, nil |
|
76 |
+} |
|
77 |
+ |
|
78 |
+type templatedDependencyGetter struct { |
|
79 |
+ secrets exec.SecretGetter |
|
80 |
+ configs exec.ConfigGetter |
|
81 |
+} |
|
82 |
+ |
|
83 |
+// NewTemplatedDependencyGetter returns a DependencyGetter that evaluates templates. |
|
84 |
+func NewTemplatedDependencyGetter(dependencies exec.DependencyGetter, t *api.Task) exec.DependencyGetter { |
|
85 |
+ return templatedDependencyGetter{ |
|
86 |
+ secrets: NewTemplatedSecretGetter(dependencies, t), |
|
87 |
+ configs: NewTemplatedConfigGetter(dependencies, t), |
|
88 |
+ } |
|
89 |
+} |
|
90 |
+ |
|
91 |
+func (t templatedDependencyGetter) Secrets() exec.SecretGetter { |
|
92 |
+ return t.secrets |
|
93 |
+} |
|
94 |
+ |
|
95 |
+func (t templatedDependencyGetter) Configs() exec.ConfigGetter { |
|
96 |
+ return t.configs |
|
97 |
+} |
... | ... |
@@ -13,6 +13,10 @@ var funcMap = template.FuncMap{ |
13 | 13 |
}, |
14 | 14 |
} |
15 | 15 |
|
16 |
-func newTemplate(s string) (*template.Template, error) { |
|
17 |
- return template.New("expansion").Option("missingkey=error").Funcs(funcMap).Parse(s) |
|
16 |
+func newTemplate(s string, extraFuncs template.FuncMap) (*template.Template, error) { |
|
17 |
+ tmpl := template.New("expansion").Option("missingkey=error").Funcs(funcMap) |
|
18 |
+ if len(extraFuncs) != 0 { |
|
19 |
+ tmpl = tmpl.Funcs(extraFuncs) |
|
20 |
+ } |
|
21 |
+ return tmpl.Parse(s) |
|
18 | 22 |
} |
... | ... |
@@ -30,6 +30,14 @@ github.com/opencontainers/runc b6b70e53451794e8333e9b602cc096b47a20bd0f |
30 | 30 |
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb |
31 | 31 |
github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe |
32 | 32 |
|
33 |
+# containerd executor |
|
34 |
+github.com/containerd/containerd 7fc91b05917e93d474fab9465547d44eacd10ce3 |
|
35 |
+github.com/containerd/continuity f4ad4294c92f596c9241947c416d1297f9faf3ea |
|
36 |
+github.com/containerd/fifo 69b99525e472735860a5269b75af1970142b3062 |
|
37 |
+github.com/opencontainers/runtime-spec v1.0.0-rc5 |
|
38 |
+github.com/nightlyone/lockfile 1d49c987357a327b5b03aa84cbddd582c328615d |
|
39 |
+golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c |
|
40 |
+ |
|
33 | 41 |
github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d |
34 | 42 |
github.com/Microsoft/go-winio f778f05015353be65d242f3fedc18695756153bb |
35 | 43 |
github.com/Sirupsen/logrus v0.11.0 |
36 | 44 |
deleted file mode 100644 |
... | ... |
@@ -1,231 +0,0 @@ |
1 |
-// Copyright 2015 Red Hat Inc. All rights reserved. |
|
2 |
-// |
|
3 |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 |
-// you may not use this file except in compliance with the License. |
|
5 |
-// You may obtain a copy of the License at |
|
6 |
-// http://www.apache.org/licenses/LICENSE-2.0 |
|
7 |
-// |
|
8 |
-// Unless required by applicable law or agreed to in writing, software |
|
9 |
-// distributed under the License is distributed on an "AS IS" BASIS, |
|
10 |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
11 |
-// See the License for the specific language governing permissions and |
|
12 |
-// limitations under the License. |
|
13 |
- |
|
14 |
-package doc |
|
15 |
- |
|
16 |
-import ( |
|
17 |
- "bytes" |
|
18 |
- "fmt" |
|
19 |
- "io" |
|
20 |
- "os" |
|
21 |
- "path/filepath" |
|
22 |
- "sort" |
|
23 |
- "strings" |
|
24 |
- "time" |
|
25 |
- |
|
26 |
- mangen "github.com/cpuguy83/go-md2man/md2man" |
|
27 |
- "github.com/spf13/cobra" |
|
28 |
- "github.com/spf13/pflag" |
|
29 |
-) |
|
30 |
- |
|
31 |
-// GenManTree will generate a man page for this command and all descendants |
|
32 |
-// in the directory given. The header may be nil. This function may not work |
|
33 |
-// correctly if your command names have - in them. If you have `cmd` with two |
|
34 |
-// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` |
|
35 |
-// it is undefined which help output will be in the file `cmd-sub-third.1`. |
|
36 |
-func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { |
|
37 |
- return GenManTreeFromOpts(cmd, GenManTreeOptions{ |
|
38 |
- Header: header, |
|
39 |
- Path: dir, |
|
40 |
- CommandSeparator: "_", |
|
41 |
- }) |
|
42 |
-} |
|
43 |
- |
|
44 |
-// GenManTreeFromOpts generates a man page for the command and all descendants. |
|
45 |
-// The pages are written to the opts.Path directory. |
|
46 |
-func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { |
|
47 |
- header := opts.Header |
|
48 |
- if header == nil { |
|
49 |
- header = &GenManHeader{} |
|
50 |
- } |
|
51 |
- for _, c := range cmd.Commands() { |
|
52 |
- if !c.IsAvailableCommand() || c.IsHelpCommand() { |
|
53 |
- continue |
|
54 |
- } |
|
55 |
- if err := GenManTreeFromOpts(c, opts); err != nil { |
|
56 |
- return err |
|
57 |
- } |
|
58 |
- } |
|
59 |
- section := "1" |
|
60 |
- if header.Section != "" { |
|
61 |
- section = header.Section |
|
62 |
- } |
|
63 |
- |
|
64 |
- separator := "_" |
|
65 |
- if opts.CommandSeparator != "" { |
|
66 |
- separator = opts.CommandSeparator |
|
67 |
- } |
|
68 |
- basename := strings.Replace(cmd.CommandPath(), " ", separator, -1) |
|
69 |
- filename := filepath.Join(opts.Path, basename+"."+section) |
|
70 |
- f, err := os.Create(filename) |
|
71 |
- if err != nil { |
|
72 |
- return err |
|
73 |
- } |
|
74 |
- defer f.Close() |
|
75 |
- |
|
76 |
- headerCopy := *header |
|
77 |
- return GenMan(cmd, &headerCopy, f) |
|
78 |
-} |
|
79 |
- |
|
80 |
-type GenManTreeOptions struct { |
|
81 |
- Header *GenManHeader |
|
82 |
- Path string |
|
83 |
- CommandSeparator string |
|
84 |
-} |
|
85 |
- |
|
86 |
-// GenManHeader is a lot like the .TH header at the start of man pages. These |
|
87 |
-// include the title, section, date, source, and manual. We will use the |
|
88 |
-// current time if Date if unset and will use "Auto generated by spf13/cobra" |
|
89 |
-// if the Source is unset. |
|
90 |
-type GenManHeader struct { |
|
91 |
- Title string |
|
92 |
- Section string |
|
93 |
- Date *time.Time |
|
94 |
- date string |
|
95 |
- Source string |
|
96 |
- Manual string |
|
97 |
-} |
|
98 |
- |
|
99 |
-// GenMan will generate a man page for the given command and write it to |
|
100 |
-// w. The header argument may be nil, however obviously w may not. |
|
101 |
-func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { |
|
102 |
- if header == nil { |
|
103 |
- header = &GenManHeader{} |
|
104 |
- } |
|
105 |
- fillHeader(header, cmd.CommandPath()) |
|
106 |
- |
|
107 |
- b := genMan(cmd, header) |
|
108 |
- _, err := w.Write(mangen.Render(b)) |
|
109 |
- return err |
|
110 |
-} |
|
111 |
- |
|
112 |
-func fillHeader(header *GenManHeader, name string) { |
|
113 |
- if header.Title == "" { |
|
114 |
- header.Title = strings.ToUpper(strings.Replace(name, " ", "\\-", -1)) |
|
115 |
- } |
|
116 |
- if header.Section == "" { |
|
117 |
- header.Section = "1" |
|
118 |
- } |
|
119 |
- if header.Date == nil { |
|
120 |
- now := time.Now() |
|
121 |
- header.Date = &now |
|
122 |
- } |
|
123 |
- header.date = (*header.Date).Format("Jan 2006") |
|
124 |
- if header.Source == "" { |
|
125 |
- header.Source = "Auto generated by spf13/cobra" |
|
126 |
- } |
|
127 |
-} |
|
128 |
- |
|
129 |
-func manPreamble(out io.Writer, header *GenManHeader, cmd *cobra.Command, dashedName string) { |
|
130 |
- description := cmd.Long |
|
131 |
- if len(description) == 0 { |
|
132 |
- description = cmd.Short |
|
133 |
- } |
|
134 |
- |
|
135 |
- fmt.Fprintf(out, `%% %s(%s)%s |
|
136 |
-%% %s |
|
137 |
-%% %s |
|
138 |
-# NAME |
|
139 |
-`, header.Title, header.Section, header.date, header.Source, header.Manual) |
|
140 |
- fmt.Fprintf(out, "%s \\- %s\n\n", dashedName, cmd.Short) |
|
141 |
- fmt.Fprintf(out, "# SYNOPSIS\n") |
|
142 |
- fmt.Fprintf(out, "**%s**\n\n", cmd.UseLine()) |
|
143 |
- fmt.Fprintf(out, "# DESCRIPTION\n") |
|
144 |
- fmt.Fprintf(out, "%s\n\n", description) |
|
145 |
-} |
|
146 |
- |
|
147 |
-func manPrintFlags(out io.Writer, flags *pflag.FlagSet) { |
|
148 |
- flags.VisitAll(func(flag *pflag.Flag) { |
|
149 |
- if len(flag.Deprecated) > 0 || flag.Hidden { |
|
150 |
- return |
|
151 |
- } |
|
152 |
- format := "" |
|
153 |
- if len(flag.Shorthand) > 0 && len(flag.ShorthandDeprecated) == 0 { |
|
154 |
- format = fmt.Sprintf("**-%s**, **--%s**", flag.Shorthand, flag.Name) |
|
155 |
- } else { |
|
156 |
- format = fmt.Sprintf("**--%s**", flag.Name) |
|
157 |
- } |
|
158 |
- if len(flag.NoOptDefVal) > 0 { |
|
159 |
- format = format + "[" |
|
160 |
- } |
|
161 |
- if flag.Value.Type() == "string" { |
|
162 |
- // put quotes on the value |
|
163 |
- format = format + "=%q" |
|
164 |
- } else { |
|
165 |
- format = format + "=%s" |
|
166 |
- } |
|
167 |
- if len(flag.NoOptDefVal) > 0 { |
|
168 |
- format = format + "]" |
|
169 |
- } |
|
170 |
- format = format + "\n\t%s\n\n" |
|
171 |
- fmt.Fprintf(out, format, flag.DefValue, flag.Usage) |
|
172 |
- }) |
|
173 |
-} |
|
174 |
- |
|
175 |
-func manPrintOptions(out io.Writer, command *cobra.Command) { |
|
176 |
- flags := command.NonInheritedFlags() |
|
177 |
- if flags.HasFlags() { |
|
178 |
- fmt.Fprintf(out, "# OPTIONS\n") |
|
179 |
- manPrintFlags(out, flags) |
|
180 |
- fmt.Fprintf(out, "\n") |
|
181 |
- } |
|
182 |
- flags = command.InheritedFlags() |
|
183 |
- if flags.HasFlags() { |
|
184 |
- fmt.Fprintf(out, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") |
|
185 |
- manPrintFlags(out, flags) |
|
186 |
- fmt.Fprintf(out, "\n") |
|
187 |
- } |
|
188 |
-} |
|
189 |
- |
|
190 |
-func genMan(cmd *cobra.Command, header *GenManHeader) []byte { |
|
191 |
- // something like `rootcmd-subcmd1-subcmd2` |
|
192 |
- dashCommandName := strings.Replace(cmd.CommandPath(), " ", "-", -1) |
|
193 |
- |
|
194 |
- buf := new(bytes.Buffer) |
|
195 |
- |
|
196 |
- manPreamble(buf, header, cmd, dashCommandName) |
|
197 |
- manPrintOptions(buf, cmd) |
|
198 |
- if len(cmd.Example) > 0 { |
|
199 |
- fmt.Fprintf(buf, "# EXAMPLE\n") |
|
200 |
- fmt.Fprintf(buf, "\n%s\n\n", cmd.Example) |
|
201 |
- } |
|
202 |
- if hasSeeAlso(cmd) { |
|
203 |
- fmt.Fprintf(buf, "# SEE ALSO\n") |
|
204 |
- seealsos := make([]string, 0) |
|
205 |
- if cmd.HasParent() { |
|
206 |
- parentPath := cmd.Parent().CommandPath() |
|
207 |
- dashParentPath := strings.Replace(parentPath, " ", "-", -1) |
|
208 |
- seealso := fmt.Sprintf("**%s(%s)**", dashParentPath, header.Section) |
|
209 |
- seealsos = append(seealsos, seealso) |
|
210 |
- cmd.VisitParents(func(c *cobra.Command) { |
|
211 |
- if c.DisableAutoGenTag { |
|
212 |
- cmd.DisableAutoGenTag = c.DisableAutoGenTag |
|
213 |
- } |
|
214 |
- }) |
|
215 |
- } |
|
216 |
- children := cmd.Commands() |
|
217 |
- sort.Sort(byName(children)) |
|
218 |
- for _, c := range children { |
|
219 |
- if !c.IsAvailableCommand() || c.IsHelpCommand() { |
|
220 |
- continue |
|
221 |
- } |
|
222 |
- seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) |
|
223 |
- seealsos = append(seealsos, seealso) |
|
224 |
- } |
|
225 |
- fmt.Fprintf(buf, "%s\n", strings.Join(seealsos, ", ")) |
|
226 |
- } |
|
227 |
- if !cmd.DisableAutoGenTag { |
|
228 |
- fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")) |
|
229 |
- } |
|
230 |
- return buf.Bytes() |
|
231 |
-} |
232 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,175 +0,0 @@ |
1 |
-//Copyright 2015 Red Hat Inc. All rights reserved. |
|
2 |
-// |
|
3 |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 |
-// you may not use this file except in compliance with the License. |
|
5 |
-// You may obtain a copy of the License at |
|
6 |
-// http://www.apache.org/licenses/LICENSE-2.0 |
|
7 |
-// |
|
8 |
-// Unless required by applicable law or agreed to in writing, software |
|
9 |
-// distributed under the License is distributed on an "AS IS" BASIS, |
|
10 |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
11 |
-// See the License for the specific language governing permissions and |
|
12 |
-// limitations under the License. |
|
13 |
- |
|
14 |
-package doc |
|
15 |
- |
|
16 |
-import ( |
|
17 |
- "fmt" |
|
18 |
- "io" |
|
19 |
- "os" |
|
20 |
- "path/filepath" |
|
21 |
- "sort" |
|
22 |
- "strings" |
|
23 |
- "time" |
|
24 |
- |
|
25 |
- "github.com/spf13/cobra" |
|
26 |
-) |
|
27 |
- |
|
28 |
-func printOptions(w io.Writer, cmd *cobra.Command, name string) error { |
|
29 |
- flags := cmd.NonInheritedFlags() |
|
30 |
- flags.SetOutput(w) |
|
31 |
- if flags.HasFlags() { |
|
32 |
- if _, err := fmt.Fprintf(w, "### Options\n\n```\n"); err != nil { |
|
33 |
- return err |
|
34 |
- } |
|
35 |
- flags.PrintDefaults() |
|
36 |
- if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { |
|
37 |
- return err |
|
38 |
- } |
|
39 |
- } |
|
40 |
- |
|
41 |
- parentFlags := cmd.InheritedFlags() |
|
42 |
- parentFlags.SetOutput(w) |
|
43 |
- if parentFlags.HasFlags() { |
|
44 |
- if _, err := fmt.Fprintf(w, "### Options inherited from parent commands\n\n```\n"); err != nil { |
|
45 |
- return err |
|
46 |
- } |
|
47 |
- parentFlags.PrintDefaults() |
|
48 |
- if _, err := fmt.Fprintf(w, "```\n\n"); err != nil { |
|
49 |
- return err |
|
50 |
- } |
|
51 |
- } |
|
52 |
- return nil |
|
53 |
-} |
|
54 |
- |
|
55 |
-func GenMarkdown(cmd *cobra.Command, w io.Writer) error { |
|
56 |
- return GenMarkdownCustom(cmd, w, func(s string) string { return s }) |
|
57 |
-} |
|
58 |
- |
|
59 |
-func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { |
|
60 |
- name := cmd.CommandPath() |
|
61 |
- |
|
62 |
- short := cmd.Short |
|
63 |
- long := cmd.Long |
|
64 |
- if len(long) == 0 { |
|
65 |
- long = short |
|
66 |
- } |
|
67 |
- |
|
68 |
- if _, err := fmt.Fprintf(w, "## %s\n\n", name); err != nil { |
|
69 |
- return err |
|
70 |
- } |
|
71 |
- if _, err := fmt.Fprintf(w, "%s\n\n", short); err != nil { |
|
72 |
- return err |
|
73 |
- } |
|
74 |
- if _, err := fmt.Fprintf(w, "### Synopsis\n\n"); err != nil { |
|
75 |
- return err |
|
76 |
- } |
|
77 |
- if _, err := fmt.Fprintf(w, "\n%s\n\n", long); err != nil { |
|
78 |
- return err |
|
79 |
- } |
|
80 |
- |
|
81 |
- if cmd.Runnable() { |
|
82 |
- if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.UseLine()); err != nil { |
|
83 |
- return err |
|
84 |
- } |
|
85 |
- } |
|
86 |
- |
|
87 |
- if len(cmd.Example) > 0 { |
|
88 |
- if _, err := fmt.Fprintf(w, "### Examples\n\n"); err != nil { |
|
89 |
- return err |
|
90 |
- } |
|
91 |
- if _, err := fmt.Fprintf(w, "```\n%s\n```\n\n", cmd.Example); err != nil { |
|
92 |
- return err |
|
93 |
- } |
|
94 |
- } |
|
95 |
- |
|
96 |
- if err := printOptions(w, cmd, name); err != nil { |
|
97 |
- return err |
|
98 |
- } |
|
99 |
- if hasSeeAlso(cmd) { |
|
100 |
- if _, err := fmt.Fprintf(w, "### SEE ALSO\n"); err != nil { |
|
101 |
- return err |
|
102 |
- } |
|
103 |
- if cmd.HasParent() { |
|
104 |
- parent := cmd.Parent() |
|
105 |
- pname := parent.CommandPath() |
|
106 |
- link := pname + ".md" |
|
107 |
- link = strings.Replace(link, " ", "_", -1) |
|
108 |
- if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short); err != nil { |
|
109 |
- return err |
|
110 |
- } |
|
111 |
- cmd.VisitParents(func(c *cobra.Command) { |
|
112 |
- if c.DisableAutoGenTag { |
|
113 |
- cmd.DisableAutoGenTag = c.DisableAutoGenTag |
|
114 |
- } |
|
115 |
- }) |
|
116 |
- } |
|
117 |
- |
|
118 |
- children := cmd.Commands() |
|
119 |
- sort.Sort(byName(children)) |
|
120 |
- |
|
121 |
- for _, child := range children { |
|
122 |
- if !child.IsAvailableCommand() || child.IsHelpCommand() { |
|
123 |
- continue |
|
124 |
- } |
|
125 |
- cname := name + " " + child.Name() |
|
126 |
- link := cname + ".md" |
|
127 |
- link = strings.Replace(link, " ", "_", -1) |
|
128 |
- if _, err := fmt.Fprintf(w, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short); err != nil { |
|
129 |
- return err |
|
130 |
- } |
|
131 |
- } |
|
132 |
- if _, err := fmt.Fprintf(w, "\n"); err != nil { |
|
133 |
- return err |
|
134 |
- } |
|
135 |
- } |
|
136 |
- if !cmd.DisableAutoGenTag { |
|
137 |
- if _, err := fmt.Fprintf(w, "###### Auto generated by spf13/cobra on %s\n", time.Now().Format("2-Jan-2006")); err != nil { |
|
138 |
- return err |
|
139 |
- } |
|
140 |
- } |
|
141 |
- return nil |
|
142 |
-} |
|
143 |
- |
|
144 |
-func GenMarkdownTree(cmd *cobra.Command, dir string) error { |
|
145 |
- identity := func(s string) string { return s } |
|
146 |
- emptyStr := func(s string) string { return "" } |
|
147 |
- return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity) |
|
148 |
-} |
|
149 |
- |
|
150 |
-func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { |
|
151 |
- for _, c := range cmd.Commands() { |
|
152 |
- if !c.IsAvailableCommand() || c.IsHelpCommand() { |
|
153 |
- continue |
|
154 |
- } |
|
155 |
- if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { |
|
156 |
- return err |
|
157 |
- } |
|
158 |
- } |
|
159 |
- |
|
160 |
- basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".md" |
|
161 |
- filename := filepath.Join(dir, basename) |
|
162 |
- f, err := os.Create(filename) |
|
163 |
- if err != nil { |
|
164 |
- return err |
|
165 |
- } |
|
166 |
- defer f.Close() |
|
167 |
- |
|
168 |
- if _, err := io.WriteString(f, filePrepender(filename)); err != nil { |
|
169 |
- return err |
|
170 |
- } |
|
171 |
- if err := GenMarkdownCustom(cmd, f, linkHandler); err != nil { |
|
172 |
- return err |
|
173 |
- } |
|
174 |
- return nil |
|
175 |
-} |
176 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,38 +0,0 @@ |
1 |
-// Copyright 2015 Red Hat Inc. All rights reserved. |
|
2 |
-// |
|
3 |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 |
-// you may not use this file except in compliance with the License. |
|
5 |
-// You may obtain a copy of the License at |
|
6 |
-// http://www.apache.org/licenses/LICENSE-2.0 |
|
7 |
-// |
|
8 |
-// Unless required by applicable law or agreed to in writing, software |
|
9 |
-// distributed under the License is distributed on an "AS IS" BASIS, |
|
10 |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
11 |
-// See the License for the specific language governing permissions and |
|
12 |
-// limitations under the License. |
|
13 |
- |
|
14 |
-package doc |
|
15 |
- |
|
16 |
-import "github.com/spf13/cobra" |
|
17 |
- |
|
18 |
-// Test to see if we have a reason to print See Also information in docs |
|
19 |
-// Basically this is a test for a parent commend or a subcommand which is |
|
20 |
-// both not deprecated and not the autogenerated help command. |
|
21 |
-func hasSeeAlso(cmd *cobra.Command) bool { |
|
22 |
- if cmd.HasParent() { |
|
23 |
- return true |
|
24 |
- } |
|
25 |
- for _, c := range cmd.Commands() { |
|
26 |
- if !c.IsAvailableCommand() || c.IsHelpCommand() { |
|
27 |
- continue |
|
28 |
- } |
|
29 |
- return true |
|
30 |
- } |
|
31 |
- return false |
|
32 |
-} |
|
33 |
- |
|
34 |
-type byName []*cobra.Command |
|
35 |
- |
|
36 |
-func (s byName) Len() int { return len(s) } |
|
37 |
-func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
|
38 |
-func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } |