diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 714af2125..25a50e144 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -30,7 +30,7 @@ Write your release note: Format of block header: Possible values: -- category: breaking|feature|bugfix|doc|other +- category: breaking|noteworthy|feature|bugfix|doc|other - target_group: user|operator|developer|dependency --> ```other operator diff --git a/.gitignore b/.gitignore index 52490d77b..88635c788 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ TODO # Virtual go & fuse .virtualgo .fuse_hidden* +/gardener/ \ No newline at end of file diff --git a/charts/charts.go b/charts/charts.go new file mode 100644 index 000000000..0e1bc83cf --- /dev/null +++ b/charts/charts.go @@ -0,0 +1,12 @@ +package charts + +import ( + "embed" +) + +// InternalChart embeds the internal charts in embed.FS +// +//go:embed internal +var InternalChart embed.FS + +const InternalChartsPath = "internal" diff --git a/go.mod b/go.mod index 18873bf5a..67aa6f0be 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module github.com/23technologies/gardener-extension-provider-hcloud go 1.21 require ( - github.com/Masterminds/semver v1.5.0 + github.com/Masterminds/semver/v3 v3.2.1 github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 github.com/coreos/go-systemd/v22 v22.5.0 - github.com/gardener/etcd-druid v0.19.2 - github.com/gardener/gardener v1.80.0 + github.com/gardener/etcd-druid v0.20.1 + github.com/gardener/gardener v1.83.3 github.com/gardener/machine-controller-manager v0.52.0 github.com/go-logr/logr v1.4.1 github.com/golang/mock v1.6.0 @@ -18,29 +18,31 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 go.uber.org/mock v0.4.0 - k8s.io/api v0.28.2 - k8s.io/apiextensions-apiserver v0.28.2 - k8s.io/apimachinery v0.28.2 + k8s.io/api v0.28.3 + k8s.io/apiextensions-apiserver v0.28.3 + k8s.io/apimachinery v0.28.3 k8s.io/autoscaler/vertical-pod-autoscaler v0.14.0 - k8s.io/client-go v0.28.2 - k8s.io/code-generator v0.28.2 - k8s.io/component-base v0.28.2 - k8s.io/kubelet v0.28.2 + k8s.io/client-go v0.28.3 + k8s.io/code-generator v0.28.3 + k8s.io/component-base v0.28.3 + k8s.io/kubelet v0.28.3 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 - sigs.k8s.io/controller-runtime v0.16.2 + sigs.k8s.io/controller-runtime v0.16.3 ) require ( github.com/BurntSushi/toml v1.2.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/Masterminds/sprig/v3 v3.2.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bronze1man/yaml2json v0.0.0-20211227013850-8972abeaea25 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/color v1.15.0 // indirect @@ -88,7 +90,9 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.18.0 // indirect @@ -111,15 +115,15 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect istio.io/api v0.0.0-20230302172406-582f573dde0c // indirect istio.io/client-go v1.17.1 // indirect - k8s.io/apiserver v0.28.2 // indirect + k8s.io/apiserver v0.28.3 // indirect k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/helm v2.17.0+incompatible // indirect k8s.io/klog v1.0.0 // indirect k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-aggregator v0.28.2 // indirect + k8s.io/kube-aggregator v0.28.3 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/metrics v0.28.2 // indirect - sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20230707163321-8a64e5f3bd78 // indirect + k8s.io/metrics v0.28.3 // indirect + sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20231015215740-bf15e44028f9 // indirect sigs.k8s.io/controller-tools v0.13.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect diff --git a/go.sum b/go.sum index 474faaf57..1f6eae385 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,13 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -99,8 +104,8 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= -github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -116,14 +121,16 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fluent/fluent-operator/v2 v2.2.0 h1:97CiP6WKOHRM7zY/zCynX187Rg+T8hgx2JzD2iuJof8= github.com/fluent/fluent-operator/v2 v2.2.0/go.mod h1:v/q0zLEOWP6MKHP7xvrhtASZTwlrk4LcCne/kgPQ7J0= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gardener/etcd-druid v0.19.2 h1:Z8TTbmVUxZ7UWU5iJAwUHUI6A9E5Mfd5JcvokVfYH1A= -github.com/gardener/etcd-druid v0.19.2/go.mod h1:0Q9nKPiONDac/Gr0SZYFkVXHGt/Yt//rcRfDIUfftZo= -github.com/gardener/gardener v1.80.0 h1:4YtouwM/mhsk5KGc6minWsVAX7lQHch4bb4/0oQGLJQ= -github.com/gardener/gardener v1.80.0/go.mod h1:6X6NgG25u2qdhrGVndfHJnA8hOc6r/2UwtnJK+/9g2Q= +github.com/gardener/etcd-druid v0.20.1 h1:o6F4higujfg7dvBXvk+yPb86+3t2+XLE0Hmw5W1kXtM= +github.com/gardener/etcd-druid v0.20.1/go.mod h1:1tAeHycB0Vb2GfCX6sUCc6V6frGrCQI//quVg4K3GNA= +github.com/gardener/gardener v1.83.3 h1:ZnN5W0JWeUrheHHVpLfZc2xnl/vxLTQNRKCEB2VqrEM= +github.com/gardener/gardener v1.83.3/go.mod h1:WbCEy0CuG3fk1QFDeQeagwvWRtA7FaiuP9ska9EA7Xc= github.com/gardener/hvpa-controller/api v0.10.0 h1:xsYfxHncH6CdIKca7aZAvKUhYapGi0cwBqR2FEafig0= github.com/gardener/hvpa-controller/api v0.10.0/go.mod h1:N6Zmm871PWw0Y3H91JwS7Dd91cRGe7+e9Pp4JxODgEQ= github.com/gardener/machine-controller-manager v0.52.0 h1:irhpamQ/QXixCXJpNKRL71aM3FAdNO1HxZwA54jvncI= @@ -259,11 +266,13 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hetznercloud/hcloud-go v1.53.0 h1:xThhlJc6MdpvDAqVB7bAw+nAQuCpQMwsf3yanCis4rM= github.com/hetznercloud/hcloud-go v1.53.0/go.mod h1:VzDWThl47lOnZXY0q5/LPFD+M62pfe/52TV+mOrpp9Q= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -306,10 +315,12 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= @@ -361,10 +372,15 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -374,6 +390,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -413,6 +430,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -758,6 +776,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -776,25 +795,25 @@ istio.io/api v0.0.0-20230302172406-582f573dde0c/go.mod h1:q3bvmBQjuI+OKNn9693bhG istio.io/client-go v1.17.1 h1:W0kQXYCzIluA/20zLzxeNF7bNMJXXArmGYRt/MIg2io= istio.io/client-go v1.17.1/go.mod h1:mLTRYYFxHctzUbt8Iclgj+Sueq34+qC2ZEJTn6BxRuE= k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= -k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= +k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= +k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= +k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= +k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= -k8s.io/apiserver v0.28.2 h1:rBeYkLvF94Nku9XfXyUIirsVzCzJBs6jMn3NWeHieyI= -k8s.io/apiserver v0.28.2/go.mod h1:f7D5e8wH8MWcKD7azq6Csw9UN+CjdtXIVQUyUhrtb+E= +k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= +k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= +k8s.io/apiserver v0.28.3 h1:8Ov47O1cMyeDzTXz0rwcfIIGAP/dP7L8rWbEljRcg5w= +k8s.io/apiserver v0.28.3/go.mod h1:YIpM+9wngNAv8Ctt0rHG4vQuX/I5rvkEMtZtsxW2rNM= k8s.io/autoscaler/vertical-pod-autoscaler v0.14.0 h1:HkQHkcuwVP3BgJpVqTGeYHro83qGBj8mWotygHZND1k= k8s.io/autoscaler/vertical-pod-autoscaler v0.14.0/go.mod h1:w6/LjLR3DPQd57vlgvgbpzpuJKsCiily0+OzQI+nyfI= k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= +k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= -k8s.io/code-generator v0.28.2 h1:u47guga1rCWLnEnffF09p+cqj8B20oHOLoQ1lb1HGtQ= -k8s.io/code-generator v0.28.2/go.mod h1:ueeSJZJ61NHBa0ccWLey6mwawum25vX61nRZ6WOzN9A= -k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= -k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= +k8s.io/code-generator v0.28.3 h1:I847QvdpYx7xKiG2KVQeCSyNF/xU9TowaDAg601mvlw= +k8s.io/code-generator v0.28.3/go.mod h1:A2EAHTRYvCvBrb/MM2zZBNipeCk3f8NtpdNIKawC43M= +k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= +k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= @@ -809,25 +828,25 @@ k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-aggregator v0.28.2 h1:tCjAfB1p/v18yD2NpegNQRuahzyA/szFfcRARnpjDeo= -k8s.io/kube-aggregator v0.28.2/go.mod h1:g4hZVjC4KhJtZHV2pyiRBiU6AdBA/sAjh9Y9GJC/SbU= +k8s.io/kube-aggregator v0.28.3 h1:CVbj3+cpshSHR5dWPzLYx3sVpIDEPLlzMSxY/lAc9cM= +k8s.io/kube-aggregator v0.28.3/go.mod h1:5DyLevbRTcWnT1f9b+lB3BfbXC1w7gDa/OtB6kKInCw= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/kubelet v0.28.2 h1:wqe5zKtVhNWwtdABU0mpcWVe8hc6VdVvs2kqQridZRw= -k8s.io/kubelet v0.28.2/go.mod h1:rvd0e7T5TjPcfZvy62P90XhFzp0IhPIOy+Pqy3Rtipo= -k8s.io/metrics v0.28.2 h1:Z/oMk5SmiT/Ji1SaWOPfW2l9W831BLO9/XxDq9iS3ak= -k8s.io/metrics v0.28.2/go.mod h1:QTIIdjMrq+KodO+rmp6R9Pr1LZO8kTArNtkWoQXw0sw= +k8s.io/kubelet v0.28.3 h1:bp/uIf1R5F61BlFvFtzc4PDEiK7TtFcw3wFJlc0V0LM= +k8s.io/kubelet v0.28.3/go.mod h1:E3NHYbp/v45Ao6AD0EOZnqO3L0R6Haks6Nm0+bnFwtU= +k8s.io/metrics v0.28.3 h1:w2s3kVi7HulXqCVDFkF4hN/OsL1tXTTb4Biif995h/g= +k8s.io/metrics v0.28.3/go.mod h1:OZZ23AHFojPzU6r3xoHGRUcV3I9pauLua+07sAUbwLc= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= -sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20230707163321-8a64e5f3bd78 h1:WmfMsXeG/lrERxQHSuROAyrToWwkUMJ6UrVDvSFtbdk= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20230707163321-8a64e5f3bd78/go.mod h1:B6HLcvOy2S1qq2eWOFm9xepiKPMIc8Z9OXSPsnUDaR4= +sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= +sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20231015215740-bf15e44028f9 h1:O27fSMHw4u0h+Rj8bNzcZk5jY0iZCO0J8/mCpigpnbw= +sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20231015215740-bf15e44028f9/go.mod h1:TF/lVLWS+JNNaVqJuDDictY2hZSXSsIHCx4FClMvqFg= sigs.k8s.io/controller-tools v0.13.0 h1:NfrvuZ4bxyolhDBt/rCZhDnx3M2hzlhgo5n3Iv2RykI= sigs.k8s.io/controller-tools v0.13.0/go.mod h1:5vw3En2NazbejQGCeWKRrE7q4P+CW8/klfVqP8QZkgA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/hack/ci/.gitignore b/hack/ci/.gitignore new file mode 100644 index 000000000..e997125d0 --- /dev/null +++ b/hack/ci/.gitignore @@ -0,0 +1 @@ +handy.sh diff --git a/hack/test.sh b/hack/test.sh index 8d2c22138..87a9eca7c 100755 --- a/hack/test.sh +++ b/hack/test.sh @@ -93,7 +93,7 @@ if [[ "${SKIP_UNIT_TESTS}" != "" ]]; then else echo ">>>>> Invoking unit tests" TEST_PACKAGES="pkg" - GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomize-all --randomize-suites --fail-on-pending --progress" + GINKGO_COMMON_FLAGS="-r -timeout=1h0m0s --randomize-all --randomize-suites --fail-on-pending --show-node-events" if [[ $TEST_COVERAGE == true ]]; then test_with_coverage diff --git a/pkg/cmd/controller/cmd.go b/pkg/cmd/controller/cmd.go index 2cabd62bd..6f3b693e9 100644 --- a/pkg/cmd/controller/cmd.go +++ b/pkg/cmd/controller/cmd.go @@ -20,16 +20,17 @@ package controller import ( "context" "fmt" + "github.com/gardener/gardener/pkg/client/kubernetes" + "github.com/go-logr/logr" "os" + "sigs.k8s.io/controller-runtime/pkg/cluster" hcloudcontrolplane "github.com/23technologies/gardener-extension-provider-hcloud/pkg/controller/controlplane" - "github.com/23technologies/gardener-extension-provider-hcloud/pkg/controller/healthcheck" hcloudhealthcheck "github.com/23technologies/gardener-extension-provider-hcloud/pkg/controller/healthcheck" hcloudinfrastructure "github.com/23technologies/gardener-extension-provider-hcloud/pkg/controller/infrastructure" hcloudworker "github.com/23technologies/gardener-extension-provider-hcloud/pkg/controller/worker" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" hcloudapisinstall "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/install" - controlplanewebhook "github.com/23technologies/gardener-extension-provider-hcloud/pkg/webhook/controlplane" druidv1alpha1 "github.com/gardener/etcd-druid/api/v1alpha1" "github.com/gardener/gardener/extensions/pkg/controller" "github.com/gardener/gardener/extensions/pkg/controller/cmd" @@ -169,6 +170,17 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command { // add common meta types to schema for controller-runtime to use v1.ListOptions metav1.AddToGroupVersion(scheme, machinev1alpha1.SchemeGroupVersion) + log := mgr.GetLogger() + gardenCluster, err := getGardenCluster(log) + log.Info("Adding garden cluster to manager") + if err := mgr.Add(gardenCluster); err != nil { + return fmt.Errorf("failed adding garden cluster to manager: %w", err) + } + if err != nil { + return err + } + log.Info("Adding controllers to manager") + configFileOpts.Completed().ApplyGardenId(&hcloudcontrolplane.DefaultAddOptions.GardenId) configFileOpts.Completed().ApplyGardenId(&hcloudinfrastructure.DefaultAddOptions.GardenId) configFileOpts.Completed().ApplyHealthCheckConfig(&hcloudhealthcheck.DefaultAddOptions.HealthCheckConfig) @@ -181,9 +193,7 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command { reconcileOpts.Completed().Apply(&hcloudworker.DefaultAddOptions.IgnoreOperationAnnotation) workerCtrlOpts.Completed().Apply(&hcloudworker.DefaultAddOptions.Controller) - hcloudworker.DefaultAddOptions.GardenletManagesMCM = generalOpts.Completed().GardenletManagesMCM - controlplanewebhook.GardenletManagesMCM = generalOpts.Completed().GardenletManagesMCM - healthcheck.GardenletManagesMCM = generalOpts.Completed().GardenletManagesMCM + hcloudworker.DefaultAddOptions.GardenCluster = gardenCluster if _, err := webhookOptions.Completed().AddToManager(ctx, mgr); err != nil { return fmt.Errorf("Could not add webhooks to manager: %w", err) @@ -221,3 +231,22 @@ func NewControllerManagerCommand(ctx context.Context) *cobra.Command { return cmdDefinition } + +func getGardenCluster(log logr.Logger) (cluster.Cluster, error) { + log.Info("Getting rest config for garden") + gardenRESTConfig, err := kubernetes.RESTConfigFromKubeconfigFile(os.Getenv("GARDEN_KUBECONFIG"), kubernetes.AuthTokenFile) + if err != nil { + return nil, err + } + + log.Info("Setting up cluster object for garden") + gardenCluster, err := cluster.New(gardenRESTConfig, func(opts *cluster.Options) { + opts.Scheme = kubernetes.GardenScheme + opts.Logger = log + }) + if err != nil { + return nil, fmt.Errorf("failed creating garden cluster object: %w", err) + } + + return gardenCluster, nil +} diff --git a/pkg/controller/controlplane/registration.go b/pkg/controller/controlplane/registration.go index 839c26fce..fa7c4b3a4 100644 --- a/pkg/controller/controlplane/registration.go +++ b/pkg/controller/controlplane/registration.go @@ -19,9 +19,6 @@ package controlplane import ( "context" - "fmt" - "sigs.k8s.io/controller-runtime/pkg/webhook" - "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" controllerapis "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/controller" extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" @@ -59,12 +56,6 @@ type AddOptions struct { // mgr manager.Manager Control plane controller manager instance // opts AddOptions Options to add func AddToManagerWithOptions(ctx context.Context, mgr manager.Manager, opts AddOptions) error { - webhookServer := mgr.GetWebhookServer() - defaultServer, ok := webhookServer.(*webhook.DefaultServer) - if !ok { - return fmt.Errorf("expected *webhook.DefaultServer, got %T", webhookServer) - } - genericActuator, err := genericactuator.NewActuator( mgr, hcloud.Name, @@ -87,7 +78,6 @@ func AddToManagerWithOptions(ctx context.Context, mgr manager.Manager, opts AddO hcloud.CloudProviderConfig, nil, opts.WebhookServerNamespace, - defaultServer.Options.Port, ) if err != nil { diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 93cf513b5..559124c76 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -20,6 +20,7 @@ package controlplane import ( "context" "fmt" + "github.com/23technologies/gardener-extension-provider-hcloud/charts" "hash/fnv" "net" "path/filepath" @@ -47,10 +48,10 @@ import ( policyv1beta1 "k8s.io/api/policy/v1beta1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" autoscalingv1beta2 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1beta2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - "k8s.io/apimachinery/pkg/runtime/serializer" ) const ( @@ -59,16 +60,18 @@ const ( var ( configChart = &chart.Chart{ - Name: "cloud-provider-config", - Path: filepath.Join(hcloud.InternalChartsPath, "cloud-provider-config"), + Name: "cloud-provider-config", + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, "cloud-provider-config"), Objects: []*chart.Object{ {Type: &corev1.ConfigMap{}, Name: hcloud.CloudProviderConfig}, }, } controlPlaneChart = &chart.Chart{ - Name: "seed-controlplane", - Path: filepath.Join(hcloud.InternalChartsPath, "seed-controlplane"), + Name: "seed-controlplane", + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, "seed-controlplane"), SubCharts: []*chart.Chart{ { Name: hcloud.CloudControllerManagerName, @@ -98,8 +101,9 @@ var ( } controlPlaneShootChart = &chart.Chart{ - Name: "shoot-system-components", - Path: filepath.Join(hcloud.InternalChartsPath, "shoot-system-components"), + Name: "shoot-system-components", + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, "shoot-system-components"), SubCharts: []*chart.Chart{ { Name: hcloud.CloudControllerManagerName, @@ -145,8 +149,9 @@ var ( } storageClassChart = &chart.Chart{ - Name: "shoot-storageclasses", - Path: filepath.Join(hcloud.InternalChartsPath, "shoot-storageclasses"), + Name: "shoot-storageclasses", + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, "shoot-storageclasses"), } ) diff --git a/pkg/controller/healthcheck/registration.go b/pkg/controller/healthcheck/registration.go index ef6eb5bde..4915c65e0 100644 --- a/pkg/controller/healthcheck/registration.go +++ b/pkg/controller/healthcheck/registration.go @@ -47,7 +47,6 @@ var ( DefaultAddOptions = healthcheck.DefaultAddArgs{ HealthCheckConfig: extensionconfig.HealthCheckConfig{SyncPeriod: metav1.Duration{Duration: defaultSyncPeriod}}, } - GardenletManagesMCM bool ) // RegisterHealthChecks registers health checks for each extension resource @@ -86,22 +85,6 @@ func RegisterHealthChecks(ctx context.Context, mgr manager.Manager, opts healthc return err } -var ( - workerHealthChecks = []healthcheck.ConditionTypeToHealthCheck{{ - ConditionType: string(gardencorev1beta1.ShootEveryNodeReady), - HealthCheck: worker.NewNodesChecker(), - }} - workerConditionTypesToRemove = sets.New(gardencorev1beta1.ShootControlPlaneHealthy) - ) - - if !GardenletManagesMCM { - workerHealthChecks = append(workerHealthChecks, healthcheck.ConditionTypeToHealthCheck{ - ConditionType: string(gardencorev1beta1.ShootControlPlaneHealthy), - HealthCheck: general.NewSeedDeploymentHealthChecker(hcloud.MachineControllerManagerName), - }) - workerConditionTypesToRemove = workerConditionTypesToRemove.Delete(gardencorev1beta1.ShootControlPlaneHealthy) - } - return healthcheck.DefaultRegistration( ctx, hcloud.Type, @@ -111,8 +94,11 @@ var ( mgr, opts, nil, - workerHealthChecks, - workerConditionTypesToRemove, + []healthcheck.ConditionTypeToHealthCheck{{ + ConditionType: string(gardencorev1beta1.ShootEveryNodeReady), + HealthCheck: worker.NewNodesChecker(), + }}, + sets.New(gardencorev1beta1.ShootControlPlaneHealthy), ) } diff --git a/pkg/controller/infrastructure/actuator.go b/pkg/controller/infrastructure/actuator.go index 317cfb9a3..79a069fac 100644 --- a/pkg/controller/infrastructure/actuator.go +++ b/pkg/controller/infrastructure/actuator.go @@ -30,9 +30,9 @@ import ( extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/go-logr/logr" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" - "k8s.io/client-go/rest" ) type actuator struct { @@ -57,7 +57,6 @@ func NewActuator(mgr manager.Manager, gardenID string) infrastructure.Actuator { gardenID: gardenID, } } - func (a *actuator) getActuatorConfig(ctx context.Context, infra *extensionsv1alpha1.Infrastructure, cluster *extensionscontroller.Cluster) (*actuatorConfig, error) { cloudProfileConfig, err := transcoder.DecodeCloudProfileConfigFromControllerCluster(cluster) if err != nil { @@ -89,6 +88,10 @@ func (a *actuator) getActuatorConfig(ctx context.Context, infra *extensionsv1alp return config, nil } +func (a *actuator) ForceDelete(_ context.Context, _ logr.Logger, _ *extensionsv1alpha1.Infrastructure, _ *extensionscontroller.Cluster) error { + return nil +} + // Delete implements infrastructure.Actuator.Delete // // PARAMETERS diff --git a/pkg/controller/worker/actuator.go b/pkg/controller/worker/actuator.go index 67e0b7e99..446d4bf84 100644 --- a/pkg/controller/worker/actuator.go +++ b/pkg/controller/worker/actuator.go @@ -19,21 +19,18 @@ package worker import ( "context" + "sigs.k8s.io/controller-runtime/pkg/cluster" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/controller" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/v1alpha1" - controllerapis "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/controller" extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" "github.com/gardener/gardener/extensions/pkg/controller/worker" "github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator" - "github.com/gardener/gardener/extensions/pkg/util" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" gardener "github.com/gardener/gardener/pkg/client/kubernetes" - "github.com/gardener/gardener/pkg/utils/chart" - imagevectorutils "github.com/gardener/gardener/pkg/utils/imagevector" "github.com/go-logr/logr" hcloudclient "github.com/hetznercloud/hcloud-go/hcloud" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -47,46 +44,27 @@ import ( ) type delegateFactory struct { - logger logr.Logger - client client.Client - restConfig *rest.Config - scheme *runtime.Scheme + logger logr.Logger + seedClient client.Client + restConfig *rest.Config + scheme *runtime.Scheme + gardenReader client.Reader } // NewActuator creates a new Actuator that updates the status of the handled WorkerPoolConfigs. -func NewActuator(mgr manager.Manager, gardenletManagesMCM bool) (worker.Actuator, error) { +func NewActuator(mgr manager.Manager, gardenCluster cluster.Cluster) (worker.Actuator, error) { delegateFactory := &delegateFactory{ logger: log.Log.WithName("worker-actuator"), - client: mgr.GetClient(), + seedClient: mgr.GetClient(), restConfig: mgr.GetConfig(), scheme: mgr.GetScheme(), } - var ( - mcmName string - mcmChartSeed *chart.Chart - mcmChartShoot *chart.Chart - imageVector imagevectorutils.ImageVector - chartRendererFactory extensionscontroller.ChartRendererFactory - ) - - if !gardenletManagesMCM { - mcmName = hcloud.MachineControllerManagerName - mcmChartSeed = mcmChart - mcmChartShoot = mcmShootChart - imageVector = controllerapis.ImageVector() - chartRendererFactory = extensionscontroller.ChartRendererFactoryFunc(util.NewChartRendererForShoot) - } - return genericactuator.NewActuator( mgr, + gardenCluster, delegateFactory, - mcmName, - mcmChartSeed, - mcmChartShoot, - imageVector, - chartRendererFactory, - nil) + nil), nil } // WorkerDelegate returns the WorkerDelegate instance for the given worker and cluster struct. @@ -112,7 +90,7 @@ func (d *delegateFactory) WorkerDelegate(ctx context.Context, worker *extensions } return NewWorkerDelegate( - d.client, + d.seedClient, d.scheme, seedChartApplier, serverVersion.GitVersion, diff --git a/pkg/controller/worker/machine_controller_manager.go b/pkg/controller/worker/machine_controller_manager.go index f590de8b2..a3ff581f1 100644 --- a/pkg/controller/worker/machine_controller_manager.go +++ b/pkg/controller/worker/machine_controller_manager.go @@ -20,6 +20,7 @@ package worker import ( "context" "fmt" + "github.com/23technologies/gardener-extension-provider-hcloud/charts" "path/filepath" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" @@ -35,9 +36,10 @@ import ( var ( mcmChart = &chart.Chart{ - Name: hcloud.MachineControllerManagerName, - Path: filepath.Join(hcloud.InternalChartsPath, hcloud.MachineControllerManagerName, "seed"), - Images: []string{hcloud.MachineControllerManagerImageName, hcloud.MCMProviderHcloudImageName}, + Name: hcloud.MachineControllerManagerName, + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, hcloud.MachineControllerManagerName, "seed"), + Images: []string{hcloud.MachineControllerManagerImageName, hcloud.MCMProviderHcloudImageName}, Objects: []*chart.Object{ {Type: &appsv1.Deployment{}, Name: hcloud.MachineControllerManagerName}, {Type: &corev1.Service{}, Name: hcloud.MachineControllerManagerName}, @@ -49,8 +51,9 @@ var ( } mcmShootChart = &chart.Chart{ - Name: hcloud.MachineControllerManagerName, - Path: filepath.Join(hcloud.InternalChartsPath, hcloud.MachineControllerManagerName, "shoot"), + Name: hcloud.MachineControllerManagerName, + EmbeddedFS: charts.InternalChart, + Path: filepath.Join(charts.InternalChartsPath, hcloud.MachineControllerManagerName, "shoot"), Objects: []*chart.Object{ {Type: &rbacv1.ClusterRole{}, Name: fmt.Sprintf("extensions.gardener.cloud:%s:%s", hcloud.Name, hcloud.MachineControllerManagerName)}, {Type: &rbacv1.ClusterRoleBinding{}, Name: fmt.Sprintf("extensions.gardener.cloud:%s:%s", hcloud.Name, hcloud.MachineControllerManagerName)}, diff --git a/pkg/controller/worker/machines.go b/pkg/controller/worker/machines.go index 908f8b10d..6fa8f4ed6 100644 --- a/pkg/controller/worker/machines.go +++ b/pkg/controller/worker/machines.go @@ -20,6 +20,7 @@ package worker import ( "context" "fmt" + "github.com/23technologies/gardener-extension-provider-hcloud/charts" "path/filepath" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" @@ -61,7 +62,7 @@ func (w *workerDelegate) DeployMachineClasses(ctx context.Context) error { } } - return w.seedChartApplier.Apply(ctx, filepath.Join(hcloud.InternalChartsPath, "machineclass"), w.worker.Namespace, "machineclass", kubernetes.Values(map[string]interface{}{"machineClasses": w.machineClasses})) + return w.seedChartApplier.ApplyFromEmbeddedFS(ctx, charts.InternalChart, filepath.Join(charts.InternalChartsPath, "machineclass"), w.worker.Namespace, "machineclass", kubernetes.Values(map[string]interface{}{"machineClasses": w.machineClasses})) } // GenerateMachineDeployments generates the configuration for the desired machine deployments. diff --git a/pkg/controller/worker/machines_test.go b/pkg/controller/worker/machines_test.go index 3890aaccf..f4dd3595f 100644 --- a/pkg/controller/worker/machines_test.go +++ b/pkg/controller/worker/machines_test.go @@ -21,9 +21,9 @@ import ( "context" "errors" "fmt" + "github.com/23technologies/gardener-extension-provider-hcloud/charts" "path/filepath" - "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/mock" hcloudv1alpha1 "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/v1alpha1" @@ -34,7 +34,6 @@ import ( mockkubernetes "github.com/gardener/gardener/pkg/client/kubernetes/mock" mockclient "github.com/gardener/gardener/pkg/mock/controller-runtime/client" kutil "github.com/gardener/gardener/pkg/utils/kubernetes" - mcmv1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -100,24 +99,6 @@ var _ = AfterSuite(func() { }) var _ = Describe("Machines", func() { - Describe("#MachineClass", func() { - It("should return the correct kind of the machine class", func() { - workerDelegate, err := newWorkerDelegate(mockTestEnv.Client, scheme, nil, "", mock.NewWorker(), nil) - Expect(err).NotTo(HaveOccurred()) - - Expect(workerDelegate.MachineClass()).To(Equal(&mcmv1alpha1.MachineClass{})) - }) - }) - - Describe("#MachineClassKind", func() { - It("should return the correct kind of the machine class", func() { - workerDelegate, err := newWorkerDelegate(mockTestEnv.Client, scheme, nil, "", mock.NewWorker(), nil) - Expect(err).NotTo(HaveOccurred()) - - Expect(workerDelegate.MachineClassKind()).To(Equal("MachineClass")) - }) - }) - Describe("#DeployMachineClasses", func() { type setup struct { } @@ -154,9 +135,10 @@ var _ = Describe("Machines", func() { return nil }).AnyTimes() - chartApplier.EXPECT().Apply( + chartApplier.EXPECT().ApplyFromEmbeddedFS( ctx, - filepath.Join(hcloud.InternalChartsPath, "machineclass"), + charts.InternalChart, + filepath.Join(charts.InternalChartsPath, "machineclass"), mock.TestNamespace, "machineclass", gardenerclient.Values( diff --git a/pkg/controller/worker/registration.go b/pkg/controller/worker/registration.go index da3130004..efae9aa2d 100644 --- a/pkg/controller/worker/registration.go +++ b/pkg/controller/worker/registration.go @@ -24,6 +24,7 @@ import ( machinescheme "github.com/gardener/machine-controller-manager/pkg/client/clientset/versioned/scheme" apiextensionsscheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/cluster" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/manager" ) @@ -39,8 +40,8 @@ type AddOptions struct { Controller controller.Options // IgnoreOperationAnnotation specifies whether to ignore the operation annotation or not. IgnoreOperationAnnotation bool - // GardenletManagesMCM specifies whether the machine-controller-manager should be managed. - GardenletManagesMCM bool + // GardenCluster is the garden cluster object. + GardenCluster cluster.Cluster } // AddToManagerWithOptions adds a controller with the given Options to the given manager. @@ -59,7 +60,7 @@ func AddToManagerWithOptions(ctx context.Context, mgr manager.Manager, opts AddO return err } - actuator, err := NewActuator(mgr, opts.GardenletManagesMCM) + actuator, err := NewActuator(mgr, opts.GardenCluster) if err != nil { return err } diff --git a/pkg/hcloud/types.go b/pkg/hcloud/types.go index f3b3eb72d..949ab8f9b 100644 --- a/pkg/hcloud/types.go +++ b/pkg/hcloud/types.go @@ -18,8 +18,6 @@ limitations under the License. package hcloud import ( - "path/filepath" - extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" ) @@ -50,7 +48,7 @@ const ( LivenessProbeImageName = "liveness-probe" // Common HCloud credentials token - HcloudToken = "hcloudToken" + HcloudToken = "hcloudToken" // Cloud Controller Manager HCloud credentials token HcloudTokenCCM = "hcloudTokenCCM" // Container Storage Interface driver HCloud credentials token @@ -89,11 +87,6 @@ const ( ) var ( - // ChartsPath is the path to the charts - ChartsPath = filepath.Join("charts") - // InternalChartsPath is the path to the internal charts - InternalChartsPath = filepath.Join(ChartsPath, "internal") - // UsernamePrefix is a constant for the username prefix of components deployed by OpenStack. UsernamePrefix = extensionsv1alpha1.SchemeGroupVersion.Group + ":" + Name + ":" ) diff --git a/pkg/webhook/controlplane/ensurer.go b/pkg/webhook/controlplane/ensurer.go index 0d3c1efc2..599ea6712 100644 --- a/pkg/webhook/controlplane/ensurer.go +++ b/pkg/webhook/controlplane/ensurer.go @@ -26,7 +26,7 @@ import ( "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/transcoder" controllerapis "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/controller" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "github.com/coreos/go-systemd/v22/unit" extensionswebhook "github.com/gardener/gardener/extensions/pkg/webhook" gcontext "github.com/gardener/gardener/extensions/pkg/webhook/context" @@ -49,19 +49,17 @@ import ( ) // NewEnsurer creates a new controlplane ensurer. -func NewEnsurer(mgr manager.Manager, logger logr.Logger, gardenletManagesMCM bool) genericmutator.Ensurer { +func NewEnsurer(mgr manager.Manager, logger logr.Logger) genericmutator.Ensurer { return &ensurer{ - client: mgr.GetClient(), - logger: logger.WithName("hcloud-controlplane-ensurer"), - gardenletManagesMCM: gardenletManagesMCM, + client: mgr.GetClient(), + logger: logger.WithName("hcloud-controlplane-ensurer"), } } type ensurer struct { genericmutator.NoopEnsurer - client client.Client - logger logr.Logger - gardenletManagesMCM bool + client client.Client + logger logr.Logger } // ImageVector is exposed for testing. @@ -75,10 +73,6 @@ func (e *ensurer) InjectClient(client client.Client) error { // EnsureMachineControllerManagerDeployment ensures that the machine-controller-manager deployment conforms to the provider requirements. func (e *ensurer) EnsureMachineControllerManagerDeployment(_ context.Context, _ gcontext.GardenContext, newObj, _ *appsv1.Deployment) error { - if !e.gardenletManagesMCM { - return nil - } - image, err := ImageVector.FindImage(hcloud.MCMProviderHcloudImageName) if err != nil { return err @@ -93,10 +87,6 @@ func (e *ensurer) EnsureMachineControllerManagerDeployment(_ context.Context, _ // EnsureMachineControllerManagerVPA ensures that the machine-controller-manager VPA conforms to the provider requirements. func (e *ensurer) EnsureMachineControllerManagerVPA(_ context.Context, _ gcontext.GardenContext, newObj, _ *vpaautoscalingv1.VerticalPodAutoscaler) error { - if !e.gardenletManagesMCM { - return nil - } - var ( minAllowed = corev1.ResourceList{ corev1.ResourceMemory: resource.MustParse("40M"), @@ -302,7 +292,7 @@ echo '{"insecure-registries":["@@"]}' | jq -s '.[0] * .[1]' ${DOCKER_CONF}.org - // EnsureAdditionalUnits ensures that additional required system units are added. func (e *ensurer) EnsureAdditionalUnits(ctx context.Context, gctx gcontext.GardenContext, new, _ *[]extensionsv1alpha1.Unit) error { var ( - command = "start" + command = extensionsv1alpha1.CommandStart trueVar = true customUnitContent = `[Unit] Description=Extend dockerd configuration file diff --git a/pkg/webhook/controlplane/registration.go b/pkg/webhook/controlplane/registration.go index 7537a2200..98902887f 100644 --- a/pkg/webhook/controlplane/registration.go +++ b/pkg/webhook/controlplane/registration.go @@ -23,8 +23,8 @@ import ( "github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" - oscutils "github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/utils" "github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet" + oscutils "github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/utils" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" appsv1 "k8s.io/api/apps/v1" @@ -34,8 +34,6 @@ import ( var ( logger = log.Log.WithName("hcloud-controlplane-webhook") - // GardenletManagesMCM specifies whether the machine-controller-manager should be managed. - GardenletManagesMCM bool ) // AddToManager creates a webhook and adds it to the manager. @@ -48,13 +46,13 @@ func AddToManager(mgr manager.Manager) (*extensionswebhook.Webhook, error) { return controlplane.New(mgr, controlplane.Args{ Kind: controlplane.KindShoot, Provider: hcloud.Type, - Types: []extensionswebhook.Type{ - { Obj: &appsv1.Deployment{} }, - { Obj: &extensionsv1alpha1.OperatingSystemConfig{} }, + Types: []extensionswebhook.Type{ + {Obj: &appsv1.Deployment{}}, + {Obj: &extensionsv1alpha1.OperatingSystemConfig{}}, }, Mutator: genericmutator.NewMutator( mgr, - NewEnsurer(mgr, logger, GardenletManagesMCM), + NewEnsurer(mgr, logger), oscutils.NewUnitSerializer(), kubelet.NewConfigCodec(fciCodec), fciCodec, diff --git a/vendor/github.com/Masterminds/semver/v3/.gitignore b/vendor/github.com/Masterminds/semver/v3/.gitignore new file mode 100644 index 000000000..6b061e617 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/.gitignore @@ -0,0 +1 @@ +_fuzz/ \ No newline at end of file diff --git a/vendor/github.com/Masterminds/semver/v3/.golangci.yml b/vendor/github.com/Masterminds/semver/v3/.golangci.yml new file mode 100644 index 000000000..fbc633259 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/.golangci.yml @@ -0,0 +1,27 @@ +run: + deadline: 2m + +linters: + disable-all: true + enable: + - misspell + - govet + - staticcheck + - errcheck + - unparam + - ineffassign + - nakedret + - gocyclo + - dupl + - goimports + - revive + - gosec + - gosimple + - typecheck + - unused + +linters-settings: + gofmt: + simplify: true + dupl: + threshold: 600 diff --git a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md new file mode 100644 index 000000000..f12626423 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md @@ -0,0 +1,214 @@ +# Changelog + +## 3.2.0 (2022-11-28) + +### Added + +- #190: Added text marshaling and unmarshaling +- #167: Added JSON marshalling for constraints (thanks @SimonTheLeg) +- #173: Implement encoding.TextMarshaler and encoding.TextUnmarshaler on Version (thanks @MarkRosemaker) +- #179: Added New() version constructor (thanks @kazhuravlev) + +### Changed + +- #182/#183: Updated CI testing setup + +### Fixed + +- #186: Fixing issue where validation of constraint section gave false positives +- #176: Fix constraints check with *-0 (thanks @mtt0) +- #181: Fixed Caret operator (^) gives unexpected results when the minor version in constraint is 0 (thanks @arshchimni) +- #161: Fixed godoc (thanks @afirth) + +## 3.1.1 (2020-11-23) + +### Fixed + +- #158: Fixed issue with generated regex operation order that could cause problem + +## 3.1.0 (2020-04-15) + +### Added + +- #131: Add support for serializing/deserializing SQL (thanks @ryancurrah) + +### Changed + +- #148: More accurate validation messages on constraints + +## 3.0.3 (2019-12-13) + +### Fixed + +- #141: Fixed issue with <= comparison + +## 3.0.2 (2019-11-14) + +### Fixed + +- #134: Fixed broken constraint checking with ^0.0 (thanks @krmichelos) + +## 3.0.1 (2019-09-13) + +### Fixed + +- #125: Fixes issue with module path for v3 + +## 3.0.0 (2019-09-12) + +This is a major release of the semver package which includes API changes. The Go +API is compatible with ^1. The Go API was not changed because many people are using +`go get` without Go modules for their applications and API breaking changes cause +errors which we have or would need to support. + +The changes in this release are the handling based on the data passed into the +functions. These are described in the added and changed sections below. + +### Added + +- StrictNewVersion function. This is similar to NewVersion but will return an + error if the version passed in is not a strict semantic version. For example, + 1.2.3 would pass but v1.2.3 or 1.2 would fail because they are not strictly + speaking semantic versions. This function is faster, performs fewer operations, + and uses fewer allocations than NewVersion. +- Fuzzing has been performed on NewVersion, StrictNewVersion, and NewConstraint. + The Makefile contains the operations used. For more information on you can start + on Wikipedia at https://en.wikipedia.org/wiki/Fuzzing +- Now using Go modules + +### Changed + +- NewVersion has proper prerelease and metadata validation with error messages + to signal an issue with either of them +- ^ now operates using a similar set of rules to npm/js and Rust/Cargo. If the + version is >=1 the ^ ranges works the same as v1. For major versions of 0 the + rules have changed. The minor version is treated as the stable version unless + a patch is specified and then it is equivalent to =. One difference from npm/js + is that prereleases there are only to a specific version (e.g. 1.2.3). + Prereleases here look over multiple versions and follow semantic version + ordering rules. This pattern now follows along with the expected and requested + handling of this packaged by numerous users. + +## 1.5.0 (2019-09-11) + +### Added + +- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c) + +### Changed + +- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil) +- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil) +- #72: Adding docs comment pointing to vert for a cli +- #71: Update the docs on pre-release comparator handling +- #89: Test with new go versions (thanks @thedevsaddam) +- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll) + +### Fixed + +- #78: Fix unchecked error in example code (thanks @ravron) +- #70: Fix the handling of pre-releases and the 0.0.0 release edge case +- #97: Fixed copyright file for proper display on GitHub +- #107: Fix handling prerelease when sorting alphanum and num +- #109: Fixed where Validate sometimes returns wrong message on error + +## 1.4.2 (2018-04-10) + +### Changed + +- #72: Updated the docs to point to vert for a console appliaction +- #71: Update the docs on pre-release comparator handling + +### Fixed + +- #70: Fix the handling of pre-releases and the 0.0.0 release edge case + +## 1.4.1 (2018-04-02) + +### Fixed + +- Fixed #64: Fix pre-release precedence issue (thanks @uudashr) + +## 1.4.0 (2017-10-04) + +### Changed + +- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill) + +## 1.3.1 (2017-07-10) + +### Fixed + +- Fixed #57: number comparisons in prerelease sometimes inaccurate + +## 1.3.0 (2017-05-02) + +### Added + +- #45: Added json (un)marshaling support (thanks @mh-cbon) +- Stability marker. See https://masterminds.github.io/stability/ + +### Fixed + +- #51: Fix handling of single digit tilde constraint (thanks @dgodd) + +### Changed + +- #55: The godoc icon moved from png to svg + +## 1.2.3 (2017-04-03) + +### Fixed + +- #46: Fixed 0.x.x and 0.0.x in constraints being treated as * + +## Release 1.2.2 (2016-12-13) + +### Fixed + +- #34: Fixed issue where hyphen range was not working with pre-release parsing. + +## Release 1.2.1 (2016-11-28) + +### Fixed + +- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha" + properly. + +## Release 1.2.0 (2016-11-04) + +### Added + +- #20: Added MustParse function for versions (thanks @adamreese) +- #15: Added increment methods on versions (thanks @mh-cbon) + +### Fixed + +- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and + might not satisfy the intended compatibility. The change here ignores pre-releases + on constraint checks (e.g., ~ or ^) when a pre-release is not part of the + constraint. For example, `^1.2.3` will ignore pre-releases while + `^1.2.3-alpha` will include them. + +## Release 1.1.1 (2016-06-30) + +### Changed + +- Issue #9: Speed up version comparison performance (thanks @sdboyer) +- Issue #8: Added benchmarks (thanks @sdboyer) +- Updated Go Report Card URL to new location +- Updated Readme to add code snippet formatting (thanks @mh-cbon) +- Updating tagging to v[SemVer] structure for compatibility with other tools. + +## Release 1.1.0 (2016-03-11) + +- Issue #2: Implemented validation to provide reasons a versions failed a + constraint. + +## Release 1.0.1 (2015-12-31) + +- Fixed #1: * constraint failing on valid versions. + +## Release 1.0.0 (2015-10-20) + +- Initial release diff --git a/vendor/github.com/Masterminds/semver/v3/LICENSE.txt b/vendor/github.com/Masterminds/semver/v3/LICENSE.txt new file mode 100644 index 000000000..9ff7da9c4 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2014-2019, Matt Butcher and Matt Farina + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Masterminds/semver/v3/Makefile b/vendor/github.com/Masterminds/semver/v3/Makefile new file mode 100644 index 000000000..0e7b5c713 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/Makefile @@ -0,0 +1,30 @@ +GOPATH=$(shell go env GOPATH) +GOLANGCI_LINT=$(GOPATH)/bin/golangci-lint + +.PHONY: lint +lint: $(GOLANGCI_LINT) + @echo "==> Linting codebase" + @$(GOLANGCI_LINT) run + +.PHONY: test +test: + @echo "==> Running tests" + GO111MODULE=on go test -v + +.PHONY: test-cover +test-cover: + @echo "==> Running Tests with coverage" + GO111MODULE=on go test -cover . + +.PHONY: fuzz +fuzz: + @echo "==> Running Fuzz Tests" + go test -fuzz=FuzzNewVersion -fuzztime=15s . + go test -fuzz=FuzzStrictNewVersion -fuzztime=15s . + go test -fuzz=FuzzNewConstraint -fuzztime=15s . + +$(GOLANGCI_LINT): + # Install golangci-lint. The configuration for it is in the .golangci.yml + # file in the root of the repository + echo ${GOPATH} + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1 diff --git a/vendor/github.com/Masterminds/semver/v3/README.md b/vendor/github.com/Masterminds/semver/v3/README.md new file mode 100644 index 000000000..eab8cac3b --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/README.md @@ -0,0 +1,258 @@ +# SemVer + +The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to: + +* Parse semantic versions +* Sort semantic versions +* Check if a semantic version fits within a set of constraints +* Optionally work with a `v` prefix + +[![Stability: +Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html) +[![](https://github.com/Masterminds/semver/workflows/Tests/badge.svg)](https://github.com/Masterminds/semver/actions) +[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/Masterminds/semver/v3) +[![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver) + +If you are looking for a command line tool for version comparisons please see +[vert](https://github.com/Masterminds/vert) which uses this library. + +## Package Versions + +Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version. + +There are three major versions fo the `semver` package. + +* 3.x.x is the stable and active version. This version is focused on constraint + compatibility for range handling in other tools from other languages. It has + a similar API to the v1 releases. The development of this version is on the master + branch. The documentation for this version is below. +* 2.x was developed primarily for [dep](https://github.com/golang/dep). There are + no tagged releases and the development was performed by [@sdboyer](https://github.com/sdboyer). + There are API breaking changes from v1. This version lives on the [2.x branch](https://github.com/Masterminds/semver/tree/2.x). +* 1.x.x is the original release. It is no longer maintained. You should use the + v3 release instead. You can read the documentation for the 1.x.x release + [here](https://github.com/Masterminds/semver/blob/release-1/README.md). + +## Parsing Semantic Versions + +There are two functions that can parse semantic versions. The `StrictNewVersion` +function only parses valid version 2 semantic versions as outlined in the +specification. The `NewVersion` function attempts to coerce a version into a +semantic version and parse it. For example, if there is a leading v or a version +listed without all 3 parts (e.g. `v1.2`) it will attempt to coerce it into a valid +semantic version (e.g., 1.2.0). In both cases a `Version` object is returned +that can be sorted, compared, and used in constraints. + +When parsing a version an error is returned if there is an issue parsing the +version. For example, + + v, err := semver.NewVersion("1.2.3-beta.1+build345") + +The version object has methods to get the parts of the version, compare it to +other versions, convert the version back into a string, and get the original +string. Getting the original string is useful if the semantic version was coerced +into a valid form. + +## Sorting Semantic Versions + +A set of versions can be sorted using the `sort` package from the standard library. +For example, + +```go +raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} +vs := make([]*semver.Version, len(raw)) +for i, r := range raw { + v, err := semver.NewVersion(r) + if err != nil { + t.Errorf("Error parsing version: %s", err) + } + + vs[i] = v +} + +sort.Sort(semver.Collection(vs)) +``` + +## Checking Version Constraints + +There are two methods for comparing versions. One uses comparison methods on +`Version` instances and the other uses `Constraints`. There are some important +differences to notes between these two methods of comparison. + +1. When two versions are compared using functions such as `Compare`, `LessThan`, + and others it will follow the specification and always include prereleases + within the comparison. It will provide an answer that is valid with the + comparison section of the spec at https://semver.org/#spec-item-11 +2. When constraint checking is used for checks or validation it will follow a + different set of rules that are common for ranges with tools like npm/js + and Rust/Cargo. This includes considering prereleases to be invalid if the + ranges does not include one. If you want to have it include pre-releases a + simple solution is to include `-0` in your range. +3. Constraint ranges can have some complex rules including the shorthand use of + ~ and ^. For more details on those see the options below. + +There are differences between the two methods or checking versions because the +comparison methods on `Version` follow the specification while comparison ranges +are not part of the specification. Different packages and tools have taken it +upon themselves to come up with range rules. This has resulted in differences. +For example, npm/js and Cargo/Rust follow similar patterns while PHP has a +different pattern for ^. The comparison features in this package follow the +npm/js and Cargo/Rust lead because applications using it have followed similar +patters with their versions. + +Checking a version against version constraints is one of the most featureful +parts of the package. + +```go +c, err := semver.NewConstraint(">= 1.2.3") +if err != nil { + // Handle constraint not being parsable. +} + +v, err := semver.NewVersion("1.3") +if err != nil { + // Handle version not being parsable. +} +// Check if the version meets the constraints. The a variable will be true. +a := c.Check(v) +``` + +### Basic Comparisons + +There are two elements to the comparisons. First, a comparison string is a list +of space or comma separated AND comparisons. These are then separated by || (OR) +comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a +comparison that's greater than or equal to 1.2 and less than 3.0.0 or is +greater than or equal to 4.2.3. + +The basic comparisons are: + +* `=`: equal (aliased to no operator) +* `!=`: not equal +* `>`: greater than +* `<`: less than +* `>=`: greater than or equal to +* `<=`: less than or equal to + +### Working With Prerelease Versions + +Pre-releases, for those not familiar with them, are used for software releases +prior to stable or generally available releases. Examples of prereleases include +development, alpha, beta, and release candidate releases. A prerelease may be +a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the +order of precedence, prereleases come before their associated releases. In this +example `1.2.3-beta.1 < 1.2.3`. + +According to the Semantic Version specification prereleases may not be +API compliant with their release counterpart. It says, + +> A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. + +SemVer comparisons using constraints without a prerelease comparator will skip +prerelease versions. For example, `>=1.2.3` will skip prereleases when looking +at a list of releases while `>=1.2.3-0` will evaluate and find prereleases. + +The reason for the `0` as a pre-release version in the example comparison is +because pre-releases can only contain ASCII alphanumerics and hyphens (along with +`.` separators), per the spec. Sorting happens in ASCII sort order, again per the +spec. The lowest character is a `0` in ASCII sort order +(see an [ASCII Table](http://www.asciitable.com/)) + +Understanding ASCII sort ordering is important because A-Z comes before a-z. That +means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case +sensitivity doesn't apply here. This is due to ASCII sort ordering which is what +the spec specifies. + +### Hyphen Range Comparisons + +There are multiple methods to handle ranges and the first is hyphens ranges. +These look like: + +* `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5` +* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5` + +### Wildcards In Comparisons + +The `x`, `X`, and `*` characters can be used as a wildcard character. This works +for all comparison operators. When used on the `=` operator it falls +back to the patch level comparison (see tilde below). For example, + +* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` +* `>= 1.2.x` is equivalent to `>= 1.2.0` +* `<= 2.x` is equivalent to `< 3` +* `*` is equivalent to `>= 0.0.0` + +### Tilde Range Comparisons (Patch) + +The tilde (`~`) comparison operator is for patch level ranges when a minor +version is specified and major level changes when the minor number is missing. +For example, + +* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0` +* `~1` is equivalent to `>= 1, < 2` +* `~2.3` is equivalent to `>= 2.3, < 2.4` +* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0` +* `~1.x` is equivalent to `>= 1, < 2` + +### Caret Range Comparisons (Major) + +The caret (`^`) comparison operator is for major level changes once a stable +(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts +as the API stability level. This is useful when comparisons of API versions as a +major change is API breaking. For example, + +* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` +* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` +* `^2.3` is equivalent to `>= 2.3, < 3` +* `^2.x` is equivalent to `>= 2.0.0, < 3` +* `^0.2.3` is equivalent to `>=0.2.3 <0.3.0` +* `^0.2` is equivalent to `>=0.2.0 <0.3.0` +* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4` +* `^0.0` is equivalent to `>=0.0.0 <0.1.0` +* `^0` is equivalent to `>=0.0.0 <1.0.0` + +## Validation + +In addition to testing a version against a constraint, a version can be validated +against a constraint. When validation fails a slice of errors containing why a +version didn't meet the constraint is returned. For example, + +```go +c, err := semver.NewConstraint("<= 1.2.3, >= 1.4") +if err != nil { + // Handle constraint not being parseable. +} + +v, err := semver.NewVersion("1.3") +if err != nil { + // Handle version not being parseable. +} + +// Validate a version against a constraint. +a, msgs := c.Validate(v) +// a is false +for _, m := range msgs { + fmt.Println(m) + + // Loops over the errors which would read + // "1.3 is greater than 1.2.3" + // "1.3 is less than 1.4" +} +``` + +## Contribute + +If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues) +or [create a pull request](https://github.com/Masterminds/semver/pulls). + +## Security + +Security is an important consideration for this project. The project currently +uses the following tools to help discover security issues: + +* [CodeQL](https://github.com/Masterminds/semver) +* [gosec](https://github.com/securego/gosec) +* Daily Fuzz testing + +If you believe you have found a security vulnerability you can privately disclose +it through the [GitHub security page](https://github.com/Masterminds/semver/security). diff --git a/vendor/github.com/Masterminds/semver/v3/SECURITY.md b/vendor/github.com/Masterminds/semver/v3/SECURITY.md new file mode 100644 index 000000000..a30a66b1f --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Supported Versions + +The following versions of semver are currently supported: + +| Version | Supported | +| ------- | ------------------ | +| 3.x | :white_check_mark: | +| 2.x | :x: | +| 1.x | :x: | + +Fixes are only released for the latest minor version in the form of a patch release. + +## Reporting a Vulnerability + +You can privately disclose a vulnerability through GitHubs +[private vulnerability reporting](https://github.com/Masterminds/semver/security/advisories) +mechanism. diff --git a/vendor/github.com/Masterminds/semver/v3/collection.go b/vendor/github.com/Masterminds/semver/v3/collection.go new file mode 100644 index 000000000..a78235895 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/collection.go @@ -0,0 +1,24 @@ +package semver + +// Collection is a collection of Version instances and implements the sort +// interface. See the sort package for more details. +// https://golang.org/pkg/sort/ +type Collection []*Version + +// Len returns the length of a collection. The number of Version instances +// on the slice. +func (c Collection) Len() int { + return len(c) +} + +// Less is needed for the sort interface to compare two Version objects on the +// slice. If checks if one is less than the other. +func (c Collection) Less(i, j int) bool { + return c[i].LessThan(c[j]) +} + +// Swap is needed for the sort interface to replace the Version objects +// at two different positions in the slice. +func (c Collection) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} diff --git a/vendor/github.com/Masterminds/semver/v3/constraints.go b/vendor/github.com/Masterminds/semver/v3/constraints.go new file mode 100644 index 000000000..8461c7ed9 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/constraints.go @@ -0,0 +1,594 @@ +package semver + +import ( + "bytes" + "errors" + "fmt" + "regexp" + "strings" +) + +// Constraints is one or more constraint that a semantic version can be +// checked against. +type Constraints struct { + constraints [][]*constraint +} + +// NewConstraint returns a Constraints instance that a Version instance can +// be checked against. If there is a parse error it will be returned. +func NewConstraint(c string) (*Constraints, error) { + + // Rewrite - ranges into a comparison operation. + c = rewriteRange(c) + + ors := strings.Split(c, "||") + or := make([][]*constraint, len(ors)) + for k, v := range ors { + + // TODO: Find a way to validate and fetch all the constraints in a simpler form + + // Validate the segment + if !validConstraintRegex.MatchString(v) { + return nil, fmt.Errorf("improper constraint: %s", v) + } + + cs := findConstraintRegex.FindAllString(v, -1) + if cs == nil { + cs = append(cs, v) + } + result := make([]*constraint, len(cs)) + for i, s := range cs { + pc, err := parseConstraint(s) + if err != nil { + return nil, err + } + + result[i] = pc + } + or[k] = result + } + + o := &Constraints{constraints: or} + return o, nil +} + +// Check tests if a version satisfies the constraints. +func (cs Constraints) Check(v *Version) bool { + // TODO(mattfarina): For v4 of this library consolidate the Check and Validate + // functions as the underlying functions make that possible now. + // loop over the ORs and check the inner ANDs + for _, o := range cs.constraints { + joy := true + for _, c := range o { + if check, _ := c.check(v); !check { + joy = false + break + } + } + + if joy { + return true + } + } + + return false +} + +// Validate checks if a version satisfies a constraint. If not a slice of +// reasons for the failure are returned in addition to a bool. +func (cs Constraints) Validate(v *Version) (bool, []error) { + // loop over the ORs and check the inner ANDs + var e []error + + // Capture the prerelease message only once. When it happens the first time + // this var is marked + var prerelesase bool + for _, o := range cs.constraints { + joy := true + for _, c := range o { + // Before running the check handle the case there the version is + // a prerelease and the check is not searching for prereleases. + if c.con.pre == "" && v.pre != "" { + if !prerelesase { + em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + e = append(e, em) + prerelesase = true + } + joy = false + + } else { + + if _, err := c.check(v); err != nil { + e = append(e, err) + joy = false + } + } + } + + if joy { + return true, []error{} + } + } + + return false, e +} + +func (cs Constraints) String() string { + buf := make([]string, len(cs.constraints)) + var tmp bytes.Buffer + + for k, v := range cs.constraints { + tmp.Reset() + vlen := len(v) + for kk, c := range v { + tmp.WriteString(c.string()) + + // Space separate the AND conditions + if vlen > 1 && kk < vlen-1 { + tmp.WriteString(" ") + } + } + buf[k] = tmp.String() + } + + return strings.Join(buf, " || ") +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (cs *Constraints) UnmarshalText(text []byte) error { + temp, err := NewConstraint(string(text)) + if err != nil { + return err + } + + *cs = *temp + + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (cs Constraints) MarshalText() ([]byte, error) { + return []byte(cs.String()), nil +} + +var constraintOps map[string]cfunc +var constraintRegex *regexp.Regexp +var constraintRangeRegex *regexp.Regexp + +// Used to find individual constraints within a multi-constraint string +var findConstraintRegex *regexp.Regexp + +// Used to validate an segment of ANDs is valid +var validConstraintRegex *regexp.Regexp + +const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` + + `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + +func init() { + constraintOps = map[string]cfunc{ + "": constraintTildeOrEqual, + "=": constraintTildeOrEqual, + "!=": constraintNotEqual, + ">": constraintGreaterThan, + "<": constraintLessThan, + ">=": constraintGreaterThanEqual, + "=>": constraintGreaterThanEqual, + "<=": constraintLessThanEqual, + "=<": constraintLessThanEqual, + "~": constraintTilde, + "~>": constraintTilde, + "^": constraintCaret, + } + + ops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\^` + + constraintRegex = regexp.MustCompile(fmt.Sprintf( + `^\s*(%s)\s*(%s)\s*$`, + ops, + cvRegex)) + + constraintRangeRegex = regexp.MustCompile(fmt.Sprintf( + `\s*(%s)\s+-\s+(%s)\s*`, + cvRegex, cvRegex)) + + findConstraintRegex = regexp.MustCompile(fmt.Sprintf( + `(%s)\s*(%s)`, + ops, + cvRegex)) + + // The first time a constraint shows up will look slightly different from + // future times it shows up due to a leading space or comma in a given + // string. + validConstraintRegex = regexp.MustCompile(fmt.Sprintf( + `^(\s*(%s)\s*(%s)\s*)((?:\s+|,\s*)(%s)\s*(%s)\s*)*$`, + ops, + cvRegex, + ops, + cvRegex)) +} + +// An individual constraint +type constraint struct { + // The version used in the constraint check. For example, if a constraint + // is '<= 2.0.0' the con a version instance representing 2.0.0. + con *Version + + // The original parsed version (e.g., 4.x from != 4.x) + orig string + + // The original operator for the constraint + origfunc string + + // When an x is used as part of the version (e.g., 1.x) + minorDirty bool + dirty bool + patchDirty bool +} + +// Check if a version meets the constraint +func (c *constraint) check(v *Version) (bool, error) { + return constraintOps[c.origfunc](v, c) +} + +// String prints an individual constraint into a string +func (c *constraint) string() string { + return c.origfunc + c.orig +} + +type cfunc func(v *Version, c *constraint) (bool, error) + +func parseConstraint(c string) (*constraint, error) { + if len(c) > 0 { + m := constraintRegex.FindStringSubmatch(c) + if m == nil { + return nil, fmt.Errorf("improper constraint: %s", c) + } + + cs := &constraint{ + orig: m[2], + origfunc: m[1], + } + + ver := m[2] + minorDirty := false + patchDirty := false + dirty := false + if isX(m[3]) || m[3] == "" { + ver = fmt.Sprintf("0.0.0%s", m[6]) + dirty = true + } else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" { + minorDirty = true + dirty = true + ver = fmt.Sprintf("%s.0.0%s", m[3], m[6]) + } else if isX(strings.TrimPrefix(m[5], ".")) || m[5] == "" { + dirty = true + patchDirty = true + ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6]) + } + + con, err := NewVersion(ver) + if err != nil { + + // The constraintRegex should catch any regex parsing errors. So, + // we should never get here. + return nil, errors.New("constraint Parser Error") + } + + cs.con = con + cs.minorDirty = minorDirty + cs.patchDirty = patchDirty + cs.dirty = dirty + + return cs, nil + } + + // The rest is the special case where an empty string was passed in which + // is equivalent to * or >=0.0.0 + con, err := StrictNewVersion("0.0.0") + if err != nil { + + // The constraintRegex should catch any regex parsing errors. So, + // we should never get here. + return nil, errors.New("constraint Parser Error") + } + + cs := &constraint{ + con: con, + orig: c, + origfunc: "", + minorDirty: false, + patchDirty: false, + dirty: true, + } + return cs, nil +} + +// Constraint functions +func constraintNotEqual(v *Version, c *constraint) (bool, error) { + if c.dirty { + + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + if c.con.Major() != v.Major() { + return true, nil + } + if c.con.Minor() != v.Minor() && !c.minorDirty { + return true, nil + } else if c.minorDirty { + return false, fmt.Errorf("%s is equal to %s", v, c.orig) + } else if c.con.Patch() != v.Patch() && !c.patchDirty { + return true, nil + } else if c.patchDirty { + // Need to handle prereleases if present + if v.Prerelease() != "" || c.con.Prerelease() != "" { + eq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is equal to %s", v, c.orig) + } + return false, fmt.Errorf("%s is equal to %s", v, c.orig) + } + } + + eq := v.Equal(c.con) + if eq { + return false, fmt.Errorf("%s is equal to %s", v, c.orig) + } + + return true, nil +} + +func constraintGreaterThan(v *Version, c *constraint) (bool, error) { + + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + var eq bool + + if !c.dirty { + eq = v.Compare(c.con) == 1 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + } + + if v.Major() > c.con.Major() { + return true, nil + } else if v.Major() < c.con.Major() { + return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + } else if c.minorDirty { + // This is a range case such as >11. When the version is something like + // 11.1.0 is it not > 11. For that we would need 12 or higher + return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + } else if c.patchDirty { + // This is for ranges such as >11.1. A version of 11.1.1 is not greater + // which one of 11.2.1 is greater + eq = v.Minor() > c.con.Minor() + if eq { + return true, nil + } + return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + } + + // If we have gotten here we are not comparing pre-preleases and can use the + // Compare function to accomplish that. + eq = v.Compare(c.con) == 1 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) +} + +func constraintLessThan(v *Version, c *constraint) (bool, error) { + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + eq := v.Compare(c.con) < 0 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig) +} + +func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) { + + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + eq := v.Compare(c.con) >= 0 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is less than %s", v, c.orig) +} + +func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + var eq bool + + if !c.dirty { + eq = v.Compare(c.con) <= 0 + if eq { + return true, nil + } + return false, fmt.Errorf("%s is greater than %s", v, c.orig) + } + + if v.Major() > c.con.Major() { + return false, fmt.Errorf("%s is greater than %s", v, c.orig) + } else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty { + return false, fmt.Errorf("%s is greater than %s", v, c.orig) + } + + return true, nil +} + +// ~*, ~>* --> >= 0.0.0 (any) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0 +func constraintTilde(v *Version, c *constraint) (bool, error) { + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + if v.LessThan(c.con) { + return false, fmt.Errorf("%s is less than %s", v, c.orig) + } + + // ~0.0.0 is a special case where all constraints are accepted. It's + // equivalent to >= 0.0.0. + if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 && + !c.minorDirty && !c.patchDirty { + return true, nil + } + + if v.Major() != c.con.Major() { + return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + } + + if v.Minor() != c.con.Minor() && !c.minorDirty { + return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig) + } + + return true, nil +} + +// When there is a .x (dirty) status it automatically opts in to ~. Otherwise +// it's a straight = +func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + if c.dirty { + return constraintTilde(v, c) + } + + eq := v.Equal(c.con) + if eq { + return true, nil + } + + return false, fmt.Errorf("%s is not equal to %s", v, c.orig) +} + +// ^* --> (any) +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2 --> >=1.2.0 <2.0.0 +// ^1 --> >=1.0.0 <2.0.0 +// ^0.2.3 --> >=0.2.3 <0.3.0 +// ^0.2 --> >=0.2.0 <0.3.0 +// ^0.0.3 --> >=0.0.3 <0.0.4 +// ^0.0 --> >=0.0.0 <0.1.0 +// ^0 --> >=0.0.0 <1.0.0 +func constraintCaret(v *Version, c *constraint) (bool, error) { + // If there is a pre-release on the version but the constraint isn't looking + // for them assume that pre-releases are not compatible. See issue 21 for + // more details. + if v.Prerelease() != "" && c.con.Prerelease() == "" { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + + // This less than handles prereleases + if v.LessThan(c.con) { + return false, fmt.Errorf("%s is less than %s", v, c.orig) + } + + var eq bool + + // ^ when the major > 0 is >=x.y.z < x+1 + if c.con.Major() > 0 || c.minorDirty { + + // ^ has to be within a major range for > 0. Everything less than was + // filtered out with the LessThan call above. This filters out those + // that greater but not within the same major range. + eq = v.Major() == c.con.Major() + if eq { + return true, nil + } + return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + } + + // ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1 + if c.con.Major() == 0 && v.Major() > 0 { + return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + } + // If the con Minor is > 0 it is not dirty + if c.con.Minor() > 0 || c.patchDirty { + eq = v.Minor() == c.con.Minor() + if eq { + return true, nil + } + return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig) + } + // ^ when the minor is 0 and minor > 0 is =0.0.z + if c.con.Minor() == 0 && v.Minor() > 0 { + return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig) + } + + // At this point the major is 0 and the minor is 0 and not dirty. The patch + // is not dirty so we need to check if they are equal. If they are not equal + eq = c.con.Patch() == v.Patch() + if eq { + return true, nil + } + return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig) +} + +func isX(x string) bool { + switch x { + case "x", "*", "X": + return true + default: + return false + } +} + +func rewriteRange(i string) string { + m := constraintRangeRegex.FindAllStringSubmatch(i, -1) + if m == nil { + return i + } + o := i + for _, v := range m { + t := fmt.Sprintf(">= %s, <= %s ", v[1], v[11]) + o = strings.Replace(o, v[0], t, 1) + } + + return o +} diff --git a/vendor/github.com/Masterminds/semver/v3/doc.go b/vendor/github.com/Masterminds/semver/v3/doc.go new file mode 100644 index 000000000..74f97caa5 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/doc.go @@ -0,0 +1,184 @@ +/* +Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go. + +Specifically it provides the ability to: + + - Parse semantic versions + - Sort semantic versions + - Check if a semantic version fits within a set of constraints + - Optionally work with a `v` prefix + +# Parsing Semantic Versions + +There are two functions that can parse semantic versions. The `StrictNewVersion` +function only parses valid version 2 semantic versions as outlined in the +specification. The `NewVersion` function attempts to coerce a version into a +semantic version and parse it. For example, if there is a leading v or a version +listed without all 3 parts (e.g. 1.2) it will attempt to coerce it into a valid +semantic version (e.g., 1.2.0). In both cases a `Version` object is returned +that can be sorted, compared, and used in constraints. + +When parsing a version an optional error can be returned if there is an issue +parsing the version. For example, + + v, err := semver.NewVersion("1.2.3-beta.1+b345") + +The version object has methods to get the parts of the version, compare it to +other versions, convert the version back into a string, and get the original +string. For more details please see the documentation +at https://godoc.org/github.com/Masterminds/semver. + +# Sorting Semantic Versions + +A set of versions can be sorted using the `sort` package from the standard library. +For example, + + raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",} + vs := make([]*semver.Version, len(raw)) + for i, r := range raw { + v, err := semver.NewVersion(r) + if err != nil { + t.Errorf("Error parsing version: %s", err) + } + + vs[i] = v + } + + sort.Sort(semver.Collection(vs)) + +# Checking Version Constraints and Comparing Versions + +There are two methods for comparing versions. One uses comparison methods on +`Version` instances and the other is using Constraints. There are some important +differences to notes between these two methods of comparison. + + 1. When two versions are compared using functions such as `Compare`, `LessThan`, + and others it will follow the specification and always include prereleases + within the comparison. It will provide an answer valid with the comparison + spec section at https://semver.org/#spec-item-11 + 2. When constraint checking is used for checks or validation it will follow a + different set of rules that are common for ranges with tools like npm/js + and Rust/Cargo. This includes considering prereleases to be invalid if the + ranges does not include on. If you want to have it include pre-releases a + simple solution is to include `-0` in your range. + 3. Constraint ranges can have some complex rules including the shorthard use of + ~ and ^. For more details on those see the options below. + +There are differences between the two methods or checking versions because the +comparison methods on `Version` follow the specification while comparison ranges +are not part of the specification. Different packages and tools have taken it +upon themselves to come up with range rules. This has resulted in differences. +For example, npm/js and Cargo/Rust follow similar patterns which PHP has a +different pattern for ^. The comparison features in this package follow the +npm/js and Cargo/Rust lead because applications using it have followed similar +patters with their versions. + +Checking a version against version constraints is one of the most featureful +parts of the package. + + c, err := semver.NewConstraint(">= 1.2.3") + if err != nil { + // Handle constraint not being parsable. + } + + v, err := semver.NewVersion("1.3") + if err != nil { + // Handle version not being parsable. + } + // Check if the version meets the constraints. The a variable will be true. + a := c.Check(v) + +# Basic Comparisons + +There are two elements to the comparisons. First, a comparison string is a list +of comma or space separated AND comparisons. These are then separated by || (OR) +comparisons. For example, `">= 1.2 < 3.0.0 || >= 4.2.3"` is looking for a +comparison that's greater than or equal to 1.2 and less than 3.0.0 or is +greater than or equal to 4.2.3. This can also be written as +`">= 1.2, < 3.0.0 || >= 4.2.3"` + +The basic comparisons are: + + - `=`: equal (aliased to no operator) + - `!=`: not equal + - `>`: greater than + - `<`: less than + - `>=`: greater than or equal to + - `<=`: less than or equal to + +# Hyphen Range Comparisons + +There are multiple methods to handle ranges and the first is hyphens ranges. +These look like: + + - `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5` + - `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5` + +# Wildcards In Comparisons + +The `x`, `X`, and `*` characters can be used as a wildcard character. This works +for all comparison operators. When used on the `=` operator it falls +back to the tilde operation. For example, + + - `1.2.x` is equivalent to `>= 1.2.0 < 1.3.0` + - `>= 1.2.x` is equivalent to `>= 1.2.0` + - `<= 2.x` is equivalent to `<= 3` + - `*` is equivalent to `>= 0.0.0` + +Tilde Range Comparisons (Patch) + +The tilde (`~`) comparison operator is for patch level ranges when a minor +version is specified and major level changes when the minor number is missing. +For example, + + - `~1.2.3` is equivalent to `>= 1.2.3 < 1.3.0` + - `~1` is equivalent to `>= 1, < 2` + - `~2.3` is equivalent to `>= 2.3 < 2.4` + - `~1.2.x` is equivalent to `>= 1.2.0 < 1.3.0` + - `~1.x` is equivalent to `>= 1 < 2` + +Caret Range Comparisons (Major) + +The caret (`^`) comparison operator is for major level changes once a stable +(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts +as the API stability level. This is useful when comparisons of API versions as a +major change is API breaking. For example, + + - `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0` + - `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0` + - `^2.3` is equivalent to `>= 2.3, < 3` + - `^2.x` is equivalent to `>= 2.0.0, < 3` + - `^0.2.3` is equivalent to `>=0.2.3 <0.3.0` + - `^0.2` is equivalent to `>=0.2.0 <0.3.0` + - `^0.0.3` is equivalent to `>=0.0.3 <0.0.4` + - `^0.0` is equivalent to `>=0.0.0 <0.1.0` + - `^0` is equivalent to `>=0.0.0 <1.0.0` + +# Validation + +In addition to testing a version against a constraint, a version can be validated +against a constraint. When validation fails a slice of errors containing why a +version didn't meet the constraint is returned. For example, + + c, err := semver.NewConstraint("<= 1.2.3, >= 1.4") + if err != nil { + // Handle constraint not being parseable. + } + + v, _ := semver.NewVersion("1.3") + if err != nil { + // Handle version not being parseable. + } + + // Validate a version against a constraint. + a, msgs := c.Validate(v) + // a is false + for _, m := range msgs { + fmt.Println(m) + + // Loops over the errors which would read + // "1.3 is greater than 1.2.3" + // "1.3 is less than 1.4" + } +*/ +package semver diff --git a/vendor/github.com/Masterminds/semver/v3/version.go b/vendor/github.com/Masterminds/semver/v3/version.go new file mode 100644 index 000000000..7c4bed334 --- /dev/null +++ b/vendor/github.com/Masterminds/semver/v3/version.go @@ -0,0 +1,639 @@ +package semver + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + "regexp" + "strconv" + "strings" +) + +// The compiled version of the regex created at init() is cached here so it +// only needs to be created once. +var versionRegex *regexp.Regexp + +var ( + // ErrInvalidSemVer is returned a version is found to be invalid when + // being parsed. + ErrInvalidSemVer = errors.New("Invalid Semantic Version") + + // ErrEmptyString is returned when an empty string is passed in for parsing. + ErrEmptyString = errors.New("Version string empty") + + // ErrInvalidCharacters is returned when invalid characters are found as + // part of a version + ErrInvalidCharacters = errors.New("Invalid characters in version") + + // ErrSegmentStartsZero is returned when a version segment starts with 0. + // This is invalid in SemVer. + ErrSegmentStartsZero = errors.New("Version segment starts with 0") + + // ErrInvalidMetadata is returned when the metadata is an invalid format + ErrInvalidMetadata = errors.New("Invalid Metadata string") + + // ErrInvalidPrerelease is returned when the pre-release is an invalid format + ErrInvalidPrerelease = errors.New("Invalid Prerelease string") +) + +// semVerRegex is the regular expression used to parse a semantic version. +const semVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + + `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + +// Version represents a single semantic version. +type Version struct { + major, minor, patch uint64 + pre string + metadata string + original string +} + +func init() { + versionRegex = regexp.MustCompile("^" + semVerRegex + "$") +} + +const ( + num string = "0123456789" + allowed string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + num +) + +// StrictNewVersion parses a given version and returns an instance of Version or +// an error if unable to parse the version. Only parses valid semantic versions. +// Performs checking that can find errors within the version. +// If you want to coerce a version such as 1 or 1.2 and parse it as the 1.x +// releases of semver did, use the NewVersion() function. +func StrictNewVersion(v string) (*Version, error) { + // Parsing here does not use RegEx in order to increase performance and reduce + // allocations. + + if len(v) == 0 { + return nil, ErrEmptyString + } + + // Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build + parts := strings.SplitN(v, ".", 3) + if len(parts) != 3 { + return nil, ErrInvalidSemVer + } + + sv := &Version{ + original: v, + } + + // check for prerelease or build metadata + var extra []string + if strings.ContainsAny(parts[2], "-+") { + // Start with the build metadata first as it needs to be on the right + extra = strings.SplitN(parts[2], "+", 2) + if len(extra) > 1 { + // build metadata found + sv.metadata = extra[1] + parts[2] = extra[0] + } + + extra = strings.SplitN(parts[2], "-", 2) + if len(extra) > 1 { + // prerelease found + sv.pre = extra[1] + parts[2] = extra[0] + } + } + + // Validate the number segments are valid. This includes only having positive + // numbers and no leading 0's. + for _, p := range parts { + if !containsOnly(p, num) { + return nil, ErrInvalidCharacters + } + + if len(p) > 1 && p[0] == '0' { + return nil, ErrSegmentStartsZero + } + } + + // Extract the major, minor, and patch elements onto the returned Version + var err error + sv.major, err = strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return nil, err + } + + sv.minor, err = strconv.ParseUint(parts[1], 10, 64) + if err != nil { + return nil, err + } + + sv.patch, err = strconv.ParseUint(parts[2], 10, 64) + if err != nil { + return nil, err + } + + // No prerelease or build metadata found so returning now as a fastpath. + if sv.pre == "" && sv.metadata == "" { + return sv, nil + } + + if sv.pre != "" { + if err = validatePrerelease(sv.pre); err != nil { + return nil, err + } + } + + if sv.metadata != "" { + if err = validateMetadata(sv.metadata); err != nil { + return nil, err + } + } + + return sv, nil +} + +// NewVersion parses a given version and returns an instance of Version or +// an error if unable to parse the version. If the version is SemVer-ish it +// attempts to convert it to SemVer. If you want to validate it was a strict +// semantic version at parse time see StrictNewVersion(). +func NewVersion(v string) (*Version, error) { + m := versionRegex.FindStringSubmatch(v) + if m == nil { + return nil, ErrInvalidSemVer + } + + sv := &Version{ + metadata: m[8], + pre: m[5], + original: v, + } + + var err error + sv.major, err = strconv.ParseUint(m[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("Error parsing version segment: %s", err) + } + + if m[2] != "" { + sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64) + if err != nil { + return nil, fmt.Errorf("Error parsing version segment: %s", err) + } + } else { + sv.minor = 0 + } + + if m[3] != "" { + sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64) + if err != nil { + return nil, fmt.Errorf("Error parsing version segment: %s", err) + } + } else { + sv.patch = 0 + } + + // Perform some basic due diligence on the extra parts to ensure they are + // valid. + + if sv.pre != "" { + if err = validatePrerelease(sv.pre); err != nil { + return nil, err + } + } + + if sv.metadata != "" { + if err = validateMetadata(sv.metadata); err != nil { + return nil, err + } + } + + return sv, nil +} + +// New creates a new instance of Version with each of the parts passed in as +// arguments instead of parsing a version string. +func New(major, minor, patch uint64, pre, metadata string) *Version { + v := Version{ + major: major, + minor: minor, + patch: patch, + pre: pre, + metadata: metadata, + original: "", + } + + v.original = v.String() + + return &v +} + +// MustParse parses a given version and panics on error. +func MustParse(v string) *Version { + sv, err := NewVersion(v) + if err != nil { + panic(err) + } + return sv +} + +// String converts a Version object to a string. +// Note, if the original version contained a leading v this version will not. +// See the Original() method to retrieve the original value. Semantic Versions +// don't contain a leading v per the spec. Instead it's optional on +// implementation. +func (v Version) String() string { + var buf bytes.Buffer + + fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch) + if v.pre != "" { + fmt.Fprintf(&buf, "-%s", v.pre) + } + if v.metadata != "" { + fmt.Fprintf(&buf, "+%s", v.metadata) + } + + return buf.String() +} + +// Original returns the original value passed in to be parsed. +func (v *Version) Original() string { + return v.original +} + +// Major returns the major version. +func (v Version) Major() uint64 { + return v.major +} + +// Minor returns the minor version. +func (v Version) Minor() uint64 { + return v.minor +} + +// Patch returns the patch version. +func (v Version) Patch() uint64 { + return v.patch +} + +// Prerelease returns the pre-release version. +func (v Version) Prerelease() string { + return v.pre +} + +// Metadata returns the metadata on the version. +func (v Version) Metadata() string { + return v.metadata +} + +// originalVPrefix returns the original 'v' prefix if any. +func (v Version) originalVPrefix() string { + // Note, only lowercase v is supported as a prefix by the parser. + if v.original != "" && v.original[:1] == "v" { + return v.original[:1] + } + return "" +} + +// IncPatch produces the next patch version. +// If the current version does not have prerelease/metadata information, +// it unsets metadata and prerelease values, increments patch number. +// If the current version has any of prerelease or metadata information, +// it unsets both values and keeps current patch value +func (v Version) IncPatch() Version { + vNext := v + // according to http://semver.org/#spec-item-9 + // Pre-release versions have a lower precedence than the associated normal version. + // according to http://semver.org/#spec-item-10 + // Build metadata SHOULD be ignored when determining version precedence. + if v.pre != "" { + vNext.metadata = "" + vNext.pre = "" + } else { + vNext.metadata = "" + vNext.pre = "" + vNext.patch = v.patch + 1 + } + vNext.original = v.originalVPrefix() + "" + vNext.String() + return vNext +} + +// IncMinor produces the next minor version. +// Sets patch to 0. +// Increments minor number. +// Unsets metadata. +// Unsets prerelease status. +func (v Version) IncMinor() Version { + vNext := v + vNext.metadata = "" + vNext.pre = "" + vNext.patch = 0 + vNext.minor = v.minor + 1 + vNext.original = v.originalVPrefix() + "" + vNext.String() + return vNext +} + +// IncMajor produces the next major version. +// Sets patch to 0. +// Sets minor to 0. +// Increments major number. +// Unsets metadata. +// Unsets prerelease status. +func (v Version) IncMajor() Version { + vNext := v + vNext.metadata = "" + vNext.pre = "" + vNext.patch = 0 + vNext.minor = 0 + vNext.major = v.major + 1 + vNext.original = v.originalVPrefix() + "" + vNext.String() + return vNext +} + +// SetPrerelease defines the prerelease value. +// Value must not include the required 'hyphen' prefix. +func (v Version) SetPrerelease(prerelease string) (Version, error) { + vNext := v + if len(prerelease) > 0 { + if err := validatePrerelease(prerelease); err != nil { + return vNext, err + } + } + vNext.pre = prerelease + vNext.original = v.originalVPrefix() + "" + vNext.String() + return vNext, nil +} + +// SetMetadata defines metadata value. +// Value must not include the required 'plus' prefix. +func (v Version) SetMetadata(metadata string) (Version, error) { + vNext := v + if len(metadata) > 0 { + if err := validateMetadata(metadata); err != nil { + return vNext, err + } + } + vNext.metadata = metadata + vNext.original = v.originalVPrefix() + "" + vNext.String() + return vNext, nil +} + +// LessThan tests if one version is less than another one. +func (v *Version) LessThan(o *Version) bool { + return v.Compare(o) < 0 +} + +// GreaterThan tests if one version is greater than another one. +func (v *Version) GreaterThan(o *Version) bool { + return v.Compare(o) > 0 +} + +// Equal tests if two versions are equal to each other. +// Note, versions can be equal with different metadata since metadata +// is not considered part of the comparable version. +func (v *Version) Equal(o *Version) bool { + return v.Compare(o) == 0 +} + +// Compare compares this version to another one. It returns -1, 0, or 1 if +// the version smaller, equal, or larger than the other version. +// +// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is +// lower than the version without a prerelease. Compare always takes into account +// prereleases. If you want to work with ranges using typical range syntaxes that +// skip prereleases if the range is not looking for them use constraints. +func (v *Version) Compare(o *Version) int { + // Compare the major, minor, and patch version for differences. If a + // difference is found return the comparison. + if d := compareSegment(v.Major(), o.Major()); d != 0 { + return d + } + if d := compareSegment(v.Minor(), o.Minor()); d != 0 { + return d + } + if d := compareSegment(v.Patch(), o.Patch()); d != 0 { + return d + } + + // At this point the major, minor, and patch versions are the same. + ps := v.pre + po := o.Prerelease() + + if ps == "" && po == "" { + return 0 + } + if ps == "" { + return 1 + } + if po == "" { + return -1 + } + + return comparePrerelease(ps, po) +} + +// UnmarshalJSON implements JSON.Unmarshaler interface. +func (v *Version) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + temp, err := NewVersion(s) + if err != nil { + return err + } + v.major = temp.major + v.minor = temp.minor + v.patch = temp.patch + v.pre = temp.pre + v.metadata = temp.metadata + v.original = temp.original + return nil +} + +// MarshalJSON implements JSON.Marshaler interface. +func (v Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (v *Version) UnmarshalText(text []byte) error { + temp, err := NewVersion(string(text)) + if err != nil { + return err + } + + *v = *temp + + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (v Version) MarshalText() ([]byte, error) { + return []byte(v.String()), nil +} + +// Scan implements the SQL.Scanner interface. +func (v *Version) Scan(value interface{}) error { + var s string + s, _ = value.(string) + temp, err := NewVersion(s) + if err != nil { + return err + } + v.major = temp.major + v.minor = temp.minor + v.patch = temp.patch + v.pre = temp.pre + v.metadata = temp.metadata + v.original = temp.original + return nil +} + +// Value implements the Driver.Valuer interface. +func (v Version) Value() (driver.Value, error) { + return v.String(), nil +} + +func compareSegment(v, o uint64) int { + if v < o { + return -1 + } + if v > o { + return 1 + } + + return 0 +} + +func comparePrerelease(v, o string) int { + // split the prelease versions by their part. The separator, per the spec, + // is a . + sparts := strings.Split(v, ".") + oparts := strings.Split(o, ".") + + // Find the longer length of the parts to know how many loop iterations to + // go through. + slen := len(sparts) + olen := len(oparts) + + l := slen + if olen > slen { + l = olen + } + + // Iterate over each part of the prereleases to compare the differences. + for i := 0; i < l; i++ { + // Since the lentgh of the parts can be different we need to create + // a placeholder. This is to avoid out of bounds issues. + stemp := "" + if i < slen { + stemp = sparts[i] + } + + otemp := "" + if i < olen { + otemp = oparts[i] + } + + d := comparePrePart(stemp, otemp) + if d != 0 { + return d + } + } + + // Reaching here means two versions are of equal value but have different + // metadata (the part following a +). They are not identical in string form + // but the version comparison finds them to be equal. + return 0 +} + +func comparePrePart(s, o string) int { + // Fastpath if they are equal + if s == o { + return 0 + } + + // When s or o are empty we can use the other in an attempt to determine + // the response. + if s == "" { + if o != "" { + return -1 + } + return 1 + } + + if o == "" { + if s != "" { + return 1 + } + return -1 + } + + // When comparing strings "99" is greater than "103". To handle + // cases like this we need to detect numbers and compare them. According + // to the semver spec, numbers are always positive. If there is a - at the + // start like -99 this is to be evaluated as an alphanum. numbers always + // have precedence over alphanum. Parsing as Uints because negative numbers + // are ignored. + + oi, n1 := strconv.ParseUint(o, 10, 64) + si, n2 := strconv.ParseUint(s, 10, 64) + + // The case where both are strings compare the strings + if n1 != nil && n2 != nil { + if s > o { + return 1 + } + return -1 + } else if n1 != nil { + // o is a string and s is a number + return -1 + } else if n2 != nil { + // s is a string and o is a number + return 1 + } + // Both are numbers + if si > oi { + return 1 + } + return -1 +} + +// Like strings.ContainsAny but does an only instead of any. +func containsOnly(s string, comp string) bool { + return strings.IndexFunc(s, func(r rune) bool { + return !strings.ContainsRune(comp, r) + }) == -1 +} + +// From the spec, "Identifiers MUST comprise only +// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. +// Numeric identifiers MUST NOT include leading zeroes.". These segments can +// be dot separated. +func validatePrerelease(p string) error { + eparts := strings.Split(p, ".") + for _, p := range eparts { + if containsOnly(p, num) { + if len(p) > 1 && p[0] == '0' { + return ErrSegmentStartsZero + } + } else if !containsOnly(p, allowed) { + return ErrInvalidPrerelease + } + } + + return nil +} + +// From the spec, "Build metadata MAY be denoted by +// appending a plus sign and a series of dot separated identifiers immediately +// following the patch or pre-release version. Identifiers MUST comprise only +// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty." +func validateMetadata(m string) error { + eparts := strings.Split(m, ".") + for _, p := range eparts { + if !containsOnly(p, allowed) { + return ErrInvalidMetadata + } + } + return nil +} diff --git a/vendor/github.com/Masterminds/sprig/v3/.gitignore b/vendor/github.com/Masterminds/sprig/v3/.gitignore new file mode 100644 index 000000000..5e3002f88 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/.gitignore @@ -0,0 +1,2 @@ +vendor/ +/.glide diff --git a/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md new file mode 100644 index 000000000..fcdd4e88a --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md @@ -0,0 +1,370 @@ +# Changelog + +## Release 3.2.1 (2021-02-04) + +### Changed + +- Upgraded `Masterminds/goutils` to `v1.1.1`. see the [Security Advisory](https://github.com/Masterminds/goutils/security/advisories/GHSA-xg2h-wx96-xgxr) + +## Release 3.2.0 (2020-12-14) + +### Added + +- #211: Added randInt function (thanks @kochurovro) +- #223: Added fromJson and mustFromJson functions (thanks @mholt) +- #242: Added a bcrypt function (thanks @robbiet480) +- #253: Added randBytes function (thanks @MikaelSmith) +- #254: Added dig function for dicts (thanks @nyarly) +- #257: Added regexQuoteMeta for quoting regex metadata (thanks @rheaton) +- #261: Added filepath functions osBase, osDir, osExt, osClean, osIsAbs (thanks @zugl) +- #268: Added and and all functions for testing conditions (thanks @phuslu) +- #181: Added float64 arithmetic addf, add1f, subf, divf, mulf, maxf, and minf + (thanks @andrewmostello) +- #265: Added chunk function to split array into smaller arrays (thanks @karelbilek) +- #270: Extend certificate functions to handle non-RSA keys + add support for + ed25519 keys (thanks @misberner) + +### Changed + +- Removed testing and support for Go 1.12. ed25519 support requires Go 1.13 or newer +- Using semver 3.1.1 and mergo 0.3.11 + +### Fixed + +- #249: Fix htmlDateInZone example (thanks @spawnia) + +NOTE: The dependency github.com/imdario/mergo reverted the breaking change in +0.3.9 via 0.3.10 release. + +## Release 3.1.0 (2020-04-16) + +NOTE: The dependency github.com/imdario/mergo made a behavior change in 0.3.9 +that impacts sprig functionality. Do not use sprig with a version newer than 0.3.8. + +### Added + +- #225: Added support for generating htpasswd hash (thanks @rustycl0ck) +- #224: Added duration filter (thanks @frebib) +- #205: Added `seq` function (thanks @thadc23) + +### Changed + +- #203: Unlambda functions with correct signature (thanks @muesli) +- #236: Updated the license formatting for GitHub display purposes +- #238: Updated package dependency versions. Note, mergo not updated to 0.3.9 + as it causes a breaking change for sprig. That issue is tracked at + https://github.com/imdario/mergo/issues/139 + +### Fixed + +- #229: Fix `seq` example in docs (thanks @kalmant) + +## Release 3.0.2 (2019-12-13) + +### Fixed + +- #220: Updating to semver v3.0.3 to fix issue with <= ranges +- #218: fix typo elyptical->elliptic in ecdsa key description (thanks @laverya) + +## Release 3.0.1 (2019-12-08) + +### Fixed + +- #212: Updated semver fixing broken constraint checking with ^0.0 + +## Release 3.0.0 (2019-10-02) + +### Added + +- #187: Added durationRound function (thanks @yjp20) +- #189: Added numerous template functions that return errors rather than panic (thanks @nrvnrvn) +- #193: Added toRawJson support (thanks @Dean-Coakley) +- #197: Added get support to dicts (thanks @Dean-Coakley) + +### Changed + +- #186: Moving dependency management to Go modules +- #186: Updated semver to v3. This has changes in the way ^ is handled +- #194: Updated documentation on merging and how it copies. Added example using deepCopy +- #196: trunc now supports negative values (thanks @Dean-Coakley) + +## Release 2.22.0 (2019-10-02) + +### Added + +- #173: Added getHostByName function to resolve dns names to ips (thanks @fcgravalos) +- #195: Added deepCopy function for use with dicts + +### Changed + +- Updated merge and mergeOverwrite documentation to explain copying and how to + use deepCopy with it + +## Release 2.21.0 (2019-09-18) + +### Added + +- #122: Added encryptAES/decryptAES functions (thanks @n0madic) +- #128: Added toDecimal support (thanks @Dean-Coakley) +- #169: Added list contcat (thanks @astorath) +- #174: Added deepEqual function (thanks @bonifaido) +- #170: Added url parse and join functions (thanks @astorath) + +### Changed + +- #171: Updated glide config for Google UUID to v1 and to add ranges to semver and testify + +### Fixed + +- #172: Fix semver wildcard example (thanks @piepmatz) +- #175: Fix dateInZone doc example (thanks @s3than) + +## Release 2.20.0 (2019-06-18) + +### Added + +- #164: Adding function to get unix epoch for a time (@mattfarina) +- #166: Adding tests for date_in_zone (@mattfarina) + +### Changed + +- #144: Fix function comments based on best practices from Effective Go (@CodeLingoTeam) +- #150: Handles pointer type for time.Time in "htmlDate" (@mapreal19) +- #161, #157, #160, #153, #158, #156, #155, #159, #152 documentation updates (@badeadan) + +### Fixed + +## Release 2.19.0 (2019-03-02) + +IMPORTANT: This release reverts a change from 2.18.0 + +In the previous release (2.18), we prematurely merged a partial change to the crypto functions that led to creating two sets of crypto functions (I blame @technosophos -- since that's me). This release rolls back that change, and does what was originally intended: It alters the existing crypto functions to use secure random. + +We debated whether this classifies as a change worthy of major revision, but given the proximity to the last release, we have decided that treating 2.18 as a faulty release is the correct course of action. We apologize for any inconvenience. + +### Changed + +- Fix substr panic 35fb796 (Alexey igrychev) +- Remove extra period 1eb7729 (Matthew Lorimor) +- Make random string functions use crypto by default 6ceff26 (Matthew Lorimor) +- README edits/fixes/suggestions 08fe136 (Lauri Apple) + + +## Release 2.18.0 (2019-02-12) + +### Added + +- Added mergeOverwrite function +- cryptographic functions that use secure random (see fe1de12) + +### Changed + +- Improve documentation of regexMatch function, resolves #139 90b89ce (Jan Tagscherer) +- Handle has for nil list 9c10885 (Daniel Cohen) +- Document behaviour of mergeOverwrite fe0dbe9 (Lukas Rieder) +- doc: adds missing documentation. 4b871e6 (Fernandez Ludovic) +- Replace outdated goutils imports 01893d2 (Matthew Lorimor) +- Surface crypto secure random strings from goutils fe1de12 (Matthew Lorimor) +- Handle untyped nil values as paramters to string functions 2b2ec8f (Morten Torkildsen) + +### Fixed + +- Fix dict merge issue and provide mergeOverwrite .dst .src1 to overwrite from src -> dst 4c59c12 (Lukas Rieder) +- Fix substr var names and comments d581f80 (Dean Coakley) +- Fix substr documentation 2737203 (Dean Coakley) + +## Release 2.17.1 (2019-01-03) + +### Fixed + +The 2.17.0 release did not have a version pinned for xstrings, which caused compilation failures when xstrings < 1.2 was used. This adds the correct version string to glide.yaml. + +## Release 2.17.0 (2019-01-03) + +### Added + +- adds alder32sum function and test 6908fc2 (marshallford) +- Added kebabcase function ca331a1 (Ilyes512) + +### Changed + +- Update goutils to 1.1.0 4e1125d (Matt Butcher) + +### Fixed + +- Fix 'has' documentation e3f2a85 (dean-coakley) +- docs(dict): fix typo in pick example dc424f9 (Dustin Specker) +- fixes spelling errors... not sure how that happened 4cf188a (marshallford) + +## Release 2.16.0 (2018-08-13) + +### Added + +- add splitn function fccb0b0 (Helgi Þorbjörnsson) +- Add slice func df28ca7 (gongdo) +- Generate serial number a3bdffd (Cody Coons) +- Extract values of dict with values function df39312 (Lawrence Jones) + +### Changed + +- Modify panic message for list.slice ae38335 (gongdo) +- Minor improvement in code quality - Removed an unreachable piece of code at defaults.go#L26:6 - Resolve formatting issues. 5834241 (Abhishek Kashyap) +- Remove duplicated documentation 1d97af1 (Matthew Fisher) +- Test on go 1.11 49df809 (Helgi Þormar Þorbjörnsson) + +### Fixed + +- Fix file permissions c5f40b5 (gongdo) +- Fix example for buildCustomCert 7779e0d (Tin Lam) + +## Release 2.15.0 (2018-04-02) + +### Added + +- #68 and #69: Add json helpers to docs (thanks @arunvelsriram) +- #66: Add ternary function (thanks @binoculars) +- #67: Allow keys function to take multiple dicts (thanks @binoculars) +- #89: Added sha1sum to crypto function (thanks @benkeil) +- #81: Allow customizing Root CA that used by genSignedCert (thanks @chenzhiwei) +- #92: Add travis testing for go 1.10 +- #93: Adding appveyor config for windows testing + +### Changed + +- #90: Updating to more recent dependencies +- #73: replace satori/go.uuid with google/uuid (thanks @petterw) + +### Fixed + +- #76: Fixed documentation typos (thanks @Thiht) +- Fixed rounding issue on the `ago` function. Note, the removes support for Go 1.8 and older + +## Release 2.14.1 (2017-12-01) + +### Fixed + +- #60: Fix typo in function name documentation (thanks @neil-ca-moore) +- #61: Removing line with {{ due to blocking github pages genertion +- #64: Update the list functions to handle int, string, and other slices for compatibility + +## Release 2.14.0 (2017-10-06) + +This new version of Sprig adds a set of functions for generating and working with SSL certificates. + +- `genCA` generates an SSL Certificate Authority +- `genSelfSignedCert` generates an SSL self-signed certificate +- `genSignedCert` generates an SSL certificate and key based on a given CA + +## Release 2.13.0 (2017-09-18) + +This release adds new functions, including: + +- `regexMatch`, `regexFindAll`, `regexFind`, `regexReplaceAll`, `regexReplaceAllLiteral`, and `regexSplit` to work with regular expressions +- `floor`, `ceil`, and `round` math functions +- `toDate` converts a string to a date +- `nindent` is just like `indent` but also prepends a new line +- `ago` returns the time from `time.Now` + +### Added + +- #40: Added basic regex functionality (thanks @alanquillin) +- #41: Added ceil floor and round functions (thanks @alanquillin) +- #48: Added toDate function (thanks @andreynering) +- #50: Added nindent function (thanks @binoculars) +- #46: Added ago function (thanks @slayer) + +### Changed + +- #51: Updated godocs to include new string functions (thanks @curtisallen) +- #49: Added ability to merge multiple dicts (thanks @binoculars) + +## Release 2.12.0 (2017-05-17) + +- `snakecase`, `camelcase`, and `shuffle` are three new string functions +- `fail` allows you to bail out of a template render when conditions are not met + +## Release 2.11.0 (2017-05-02) + +- Added `toJson` and `toPrettyJson` +- Added `merge` +- Refactored documentation + +## Release 2.10.0 (2017-03-15) + +- Added `semver` and `semverCompare` for Semantic Versions +- `list` replaces `tuple` +- Fixed issue with `join` +- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` + +## Release 2.9.0 (2017-02-23) + +- Added `splitList` to split a list +- Added crypto functions of `genPrivateKey` and `derivePassword` + +## Release 2.8.0 (2016-12-21) + +- Added access to several path functions (`base`, `dir`, `clean`, `ext`, and `abs`) +- Added functions for _mutating_ dictionaries (`set`, `unset`, `hasKey`) + +## Release 2.7.0 (2016-12-01) + +- Added `sha256sum` to generate a hash of an input +- Added functions to convert a numeric or string to `int`, `int64`, `float64` + +## Release 2.6.0 (2016-10-03) + +- Added a `uuidv4` template function for generating UUIDs inside of a template. + +## Release 2.5.0 (2016-08-19) + +- New `trimSuffix`, `trimPrefix`, `hasSuffix`, and `hasPrefix` functions +- New aliases have been added for a few functions that didn't follow the naming conventions (`trimAll` and `abbrevBoth`) +- `trimall` and `abbrevboth` (notice the case) are deprecated and will be removed in 3.0.0 + +## Release 2.4.0 (2016-08-16) + +- Adds two functions: `until` and `untilStep` + +## Release 2.3.0 (2016-06-21) + +- cat: Concatenate strings with whitespace separators. +- replace: Replace parts of a string: `replace " " "-" "Me First"` renders "Me-First" +- plural: Format plurals: `len "foo" | plural "one foo" "many foos"` renders "many foos" +- indent: Indent blocks of text in a way that is sensitive to "\n" characters. + +## Release 2.2.0 (2016-04-21) + +- Added a `genPrivateKey` function (Thanks @bacongobbler) + +## Release 2.1.0 (2016-03-30) + +- `default` now prints the default value when it does not receive a value down the pipeline. It is much safer now to do `{{.Foo | default "bar"}}`. +- Added accessors for "hermetic" functions. These return only functions that, when given the same input, produce the same output. + +## Release 2.0.0 (2016-03-29) + +Because we switched from `int` to `int64` as the return value for all integer math functions, the library's major version number has been incremented. + +- `min` complements `max` (formerly `biggest`) +- `empty` indicates that a value is the empty value for its type +- `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}` +- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` +- Date formatters have been added for HTML dates (as used in `date` input fields) +- Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`). + +## Release 1.2.0 (2016-02-01) + +- Added quote and squote +- Added b32enc and b32dec +- add now takes varargs +- biggest now takes varargs + +## Release 1.1.0 (2015-12-29) + +- Added #4: Added contains function. strings.Contains, but with the arguments + switched to simplify common pipelines. (thanks krancour) +- Added Travis-CI testing support + +## Release 1.0.0 (2015-12-23) + +- Initial release diff --git a/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt b/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt new file mode 100644 index 000000000..f311b1eaa --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2013-2020 Masterminds + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/Masterminds/sprig/v3/Makefile b/vendor/github.com/Masterminds/sprig/v3/Makefile new file mode 100644 index 000000000..78d409cde --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/Makefile @@ -0,0 +1,9 @@ +.PHONY: test +test: + @echo "==> Running tests" + GO111MODULE=on go test -v + +.PHONY: test-cover +test-cover: + @echo "==> Running Tests with coverage" + GO111MODULE=on go test -cover . diff --git a/vendor/github.com/Masterminds/sprig/v3/README.md b/vendor/github.com/Masterminds/sprig/v3/README.md new file mode 100644 index 000000000..c37ba01c2 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/README.md @@ -0,0 +1,101 @@ +# Sprig: Template functions for Go templates + +[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/Masterminds/sprig/v3) +[![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/sprig)](https://goreportcard.com/report/github.com/Masterminds/sprig) +[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html) +[![](https://github.com/Masterminds/sprig/workflows/Tests/badge.svg)](https://github.com/Masterminds/sprig/actions) + +The Go language comes with a [built-in template +language](http://golang.org/pkg/text/template/), but not +very many template functions. Sprig is a library that provides more than 100 commonly +used template functions. + +It is inspired by the template functions found in +[Twig](http://twig.sensiolabs.org/documentation) and in various +JavaScript libraries, such as [underscore.js](http://underscorejs.org/). + +## IMPORTANT NOTES + +Sprig leverages [mergo](https://github.com/imdario/mergo) to handle merges. In +its v0.3.9 release there was a behavior change that impacts merging template +functions in sprig. It is currently recommended to use v0.3.8 of that package. +Using v0.3.9 will cause sprig tests to fail. The issue in mergo is tracked at +https://github.com/imdario/mergo/issues/139. + +## Package Versions + +There are two active major versions of the `sprig` package. + +* v3 is currently stable release series on the `master` branch. The Go API should + remain compatible with v2, the current stable version. Behavior change behind + some functions is the reason for the new major version. +* v2 is the previous stable release series. It has been more than three years since + the initial release of v2. You can read the documentation and see the code + on the [release-2](https://github.com/Masterminds/sprig/tree/release-2) branch. + Bug fixes to this major version will continue for some time. + +## Usage + +**Template developers**: Please use Sprig's [function documentation](http://masterminds.github.io/sprig/) for +detailed instructions and code snippets for the >100 template functions available. + +**Go developers**: If you'd like to include Sprig as a library in your program, +our API documentation is available [at GoDoc.org](http://godoc.org/github.com/Masterminds/sprig). + +For standard usage, read on. + +### Load the Sprig library + +To load the Sprig `FuncMap`: + +```go + +import ( + "github.com/Masterminds/sprig" + "html/template" +) + +// This example illustrates that the FuncMap *must* be set before the +// templates themselves are loaded. +tpl := template.Must( + template.New("base").Funcs(sprig.FuncMap()).ParseGlob("*.html") +) + + +``` + +### Calling the functions inside of templates + +By convention, all functions are lowercase. This seems to follow the Go +idiom for template functions (as opposed to template methods, which are +TitleCase). For example, this: + +``` +{{ "hello!" | upper | repeat 5 }} +``` + +produces this: + +``` +HELLO!HELLO!HELLO!HELLO!HELLO! +``` + +## Principles Driving Our Function Selection + +We followed these principles to decide which functions to add and how to implement them: + +- Use template functions to build layout. The following + types of operations are within the domain of template functions: + - Formatting + - Layout + - Simple type conversions + - Utilities that assist in handling common formatting and layout needs (e.g. arithmetic) +- Template functions should not return errors unless there is no way to print + a sensible value. For example, converting a string to an integer should not + produce an error if conversion fails. Instead, it should display a default + value. +- Simple math is necessary for grid layouts, pagers, and so on. Complex math + (anything other than arithmetic) should be done outside of templates. +- Template functions only deal with the data passed into them. They never retrieve + data from a source. +- Finally, do not override core Go template functions. diff --git a/vendor/github.com/Masterminds/sprig/v3/crypto.go b/vendor/github.com/Masterminds/sprig/v3/crypto.go new file mode 100644 index 000000000..13a5cd559 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/crypto.go @@ -0,0 +1,653 @@ +package sprig + +import ( + "bytes" + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/dsa" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/hmac" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/base64" + "encoding/binary" + "encoding/hex" + "encoding/pem" + "errors" + "fmt" + "hash/adler32" + "io" + "math/big" + "net" + "time" + + "strings" + + "github.com/google/uuid" + bcrypt_lib "golang.org/x/crypto/bcrypt" + "golang.org/x/crypto/scrypt" +) + +func sha256sum(input string) string { + hash := sha256.Sum256([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +func sha1sum(input string) string { + hash := sha1.Sum([]byte(input)) + return hex.EncodeToString(hash[:]) +} + +func adler32sum(input string) string { + hash := adler32.Checksum([]byte(input)) + return fmt.Sprintf("%d", hash) +} + +func bcrypt(input string) string { + hash, err := bcrypt_lib.GenerateFromPassword([]byte(input), bcrypt_lib.DefaultCost) + if err != nil { + return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err) + } + + return string(hash) +} + +func htpasswd(username string, password string) string { + if strings.Contains(username, ":") { + return fmt.Sprintf("invalid username: %s", username) + } + return fmt.Sprintf("%s:%s", username, bcrypt(password)) +} + +func randBytes(count int) (string, error) { + buf := make([]byte, count) + if _, err := rand.Read(buf); err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(buf), nil +} + +// uuidv4 provides a safe and secure UUID v4 implementation +func uuidv4() string { + return uuid.New().String() +} + +var masterPasswordSeed = "com.lyndir.masterpassword" + +var passwordTypeTemplates = map[string][][]byte{ + "maximum": {[]byte("anoxxxxxxxxxxxxxxxxx"), []byte("axxxxxxxxxxxxxxxxxno")}, + "long": {[]byte("CvcvnoCvcvCvcv"), []byte("CvcvCvcvnoCvcv"), []byte("CvcvCvcvCvcvno"), []byte("CvccnoCvcvCvcv"), []byte("CvccCvcvnoCvcv"), + []byte("CvccCvcvCvcvno"), []byte("CvcvnoCvccCvcv"), []byte("CvcvCvccnoCvcv"), []byte("CvcvCvccCvcvno"), []byte("CvcvnoCvcvCvcc"), + []byte("CvcvCvcvnoCvcc"), []byte("CvcvCvcvCvccno"), []byte("CvccnoCvccCvcv"), []byte("CvccCvccnoCvcv"), []byte("CvccCvccCvcvno"), + []byte("CvcvnoCvccCvcc"), []byte("CvcvCvccnoCvcc"), []byte("CvcvCvccCvccno"), []byte("CvccnoCvcvCvcc"), []byte("CvccCvcvnoCvcc"), + []byte("CvccCvcvCvccno")}, + "medium": {[]byte("CvcnoCvc"), []byte("CvcCvcno")}, + "short": {[]byte("Cvcn")}, + "basic": {[]byte("aaanaaan"), []byte("aannaaan"), []byte("aaannaaa")}, + "pin": {[]byte("nnnn")}, +} + +var templateCharacters = map[byte]string{ + 'V': "AEIOU", + 'C': "BCDFGHJKLMNPQRSTVWXYZ", + 'v': "aeiou", + 'c': "bcdfghjklmnpqrstvwxyz", + 'A': "AEIOUBCDFGHJKLMNPQRSTVWXYZ", + 'a': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz", + 'n': "0123456789", + 'o': "@&%?,=[]_:-+*$#!'^~;()/.", + 'x': "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()", +} + +func derivePassword(counter uint32, passwordType, password, user, site string) string { + var templates = passwordTypeTemplates[passwordType] + if templates == nil { + return fmt.Sprintf("cannot find password template %s", passwordType) + } + + var buffer bytes.Buffer + buffer.WriteString(masterPasswordSeed) + binary.Write(&buffer, binary.BigEndian, uint32(len(user))) + buffer.WriteString(user) + + salt := buffer.Bytes() + key, err := scrypt.Key([]byte(password), salt, 32768, 8, 2, 64) + if err != nil { + return fmt.Sprintf("failed to derive password: %s", err) + } + + buffer.Truncate(len(masterPasswordSeed)) + binary.Write(&buffer, binary.BigEndian, uint32(len(site))) + buffer.WriteString(site) + binary.Write(&buffer, binary.BigEndian, counter) + + var hmacv = hmac.New(sha256.New, key) + hmacv.Write(buffer.Bytes()) + var seed = hmacv.Sum(nil) + var temp = templates[int(seed[0])%len(templates)] + + buffer.Truncate(0) + for i, element := range temp { + passChars := templateCharacters[element] + passChar := passChars[int(seed[i+1])%len(passChars)] + buffer.WriteByte(passChar) + } + + return buffer.String() +} + +func generatePrivateKey(typ string) string { + var priv interface{} + var err error + switch typ { + case "", "rsa": + // good enough for government work + priv, err = rsa.GenerateKey(rand.Reader, 4096) + case "dsa": + key := new(dsa.PrivateKey) + // again, good enough for government work + if err = dsa.GenerateParameters(&key.Parameters, rand.Reader, dsa.L2048N256); err != nil { + return fmt.Sprintf("failed to generate dsa params: %s", err) + } + err = dsa.GenerateKey(key, rand.Reader) + priv = key + case "ecdsa": + // again, good enough for government work + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case "ed25519": + _, priv, err = ed25519.GenerateKey(rand.Reader) + default: + return "Unknown type " + typ + } + if err != nil { + return fmt.Sprintf("failed to generate private key: %s", err) + } + + return string(pem.EncodeToMemory(pemBlockForKey(priv))) +} + +// DSAKeyFormat stores the format for DSA keys. +// Used by pemBlockForKey +type DSAKeyFormat struct { + Version int + P, Q, G, Y, X *big.Int +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *dsa.PrivateKey: + val := DSAKeyFormat{ + P: k.P, Q: k.Q, G: k.G, + Y: k.Y, X: k.X, + } + bytes, _ := asn1.Marshal(val) + return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes} + case *ecdsa.PrivateKey: + b, _ := x509.MarshalECPrivateKey(k) + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + // attempt PKCS#8 format for all other keys + b, err := x509.MarshalPKCS8PrivateKey(k) + if err != nil { + return nil + } + return &pem.Block{Type: "PRIVATE KEY", Bytes: b} + } +} + +func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) { + block, _ := pem.Decode([]byte(pemBlock)) + if block == nil { + return nil, errors.New("no PEM data in input") + } + + if block.Type == "PRIVATE KEY" { + priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err) + } + return priv, nil + } else if !strings.HasSuffix(block.Type, " PRIVATE KEY") { + return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type) + } + + switch block.Type[:len(block.Type)-12] { // strip " PRIVATE KEY" + case "RSA": + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err) + } + return priv, nil + case "EC": + priv, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parsing EC private key from PEM: %s", err) + } + return priv, nil + case "DSA": + var k DSAKeyFormat + _, err := asn1.Unmarshal(block.Bytes, &k) + if err != nil { + return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err) + } + priv := &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: k.P, Q: k.Q, G: k.G, + }, + Y: k.Y, + }, + X: k.X, + } + return priv, nil + default: + return nil, fmt.Errorf("invalid private key type %s", block.Type) + } +} + +func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) { + switch k := priv.(type) { + case interface{ Public() crypto.PublicKey }: + return k.Public(), nil + case *dsa.PrivateKey: + return &k.PublicKey, nil + default: + return nil, fmt.Errorf("unable to get public key for type %T", priv) + } +} + +type certificate struct { + Cert string + Key string +} + +func buildCustomCertificate(b64cert string, b64key string) (certificate, error) { + crt := certificate{} + + cert, err := base64.StdEncoding.DecodeString(b64cert) + if err != nil { + return crt, errors.New("unable to decode base64 certificate") + } + + key, err := base64.StdEncoding.DecodeString(b64key) + if err != nil { + return crt, errors.New("unable to decode base64 private key") + } + + decodedCert, _ := pem.Decode(cert) + if decodedCert == nil { + return crt, errors.New("unable to decode certificate") + } + _, err = x509.ParseCertificate(decodedCert.Bytes) + if err != nil { + return crt, fmt.Errorf( + "error parsing certificate: decodedCert.Bytes: %s", + err, + ) + } + + _, err = parsePrivateKeyPEM(string(key)) + if err != nil { + return crt, fmt.Errorf( + "error parsing private key: %s", + err, + ) + } + + crt.Cert = string(cert) + crt.Key = string(key) + + return crt, nil +} + +func generateCertificateAuthority( + cn string, + daysValid int, +) (certificate, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return certificate{}, fmt.Errorf("error generating rsa key: %s", err) + } + + return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv) +} + +func generateCertificateAuthorityWithPEMKey( + cn string, + daysValid int, + privPEM string, +) (certificate, error) { + priv, err := parsePrivateKeyPEM(privPEM) + if err != nil { + return certificate{}, fmt.Errorf("parsing private key: %s", err) + } + return generateCertificateAuthorityWithKeyInternal(cn, daysValid, priv) +} + +func generateCertificateAuthorityWithKeyInternal( + cn string, + daysValid int, + priv crypto.PrivateKey, +) (certificate, error) { + ca := certificate{} + + template, err := getBaseCertTemplate(cn, nil, nil, daysValid) + if err != nil { + return ca, err + } + // Override KeyUsage and IsCA + template.KeyUsage = x509.KeyUsageKeyEncipherment | + x509.KeyUsageDigitalSignature | + x509.KeyUsageCertSign + template.IsCA = true + + ca.Cert, ca.Key, err = getCertAndKey(template, priv, template, priv) + + return ca, err +} + +func generateSelfSignedCertificate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, +) (certificate, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return certificate{}, fmt.Errorf("error generating rsa key: %s", err) + } + return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv) +} + +func generateSelfSignedCertificateWithPEMKey( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + privPEM string, +) (certificate, error) { + priv, err := parsePrivateKeyPEM(privPEM) + if err != nil { + return certificate{}, fmt.Errorf("parsing private key: %s", err) + } + return generateSelfSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, priv) +} + +func generateSelfSignedCertificateWithKeyInternal( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + priv crypto.PrivateKey, +) (certificate, error) { + cert := certificate{} + + template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) + if err != nil { + return cert, err + } + + cert.Cert, cert.Key, err = getCertAndKey(template, priv, template, priv) + + return cert, err +} + +func generateSignedCertificate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + ca certificate, +) (certificate, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return certificate{}, fmt.Errorf("error generating rsa key: %s", err) + } + return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv) +} + +func generateSignedCertificateWithPEMKey( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + ca certificate, + privPEM string, +) (certificate, error) { + priv, err := parsePrivateKeyPEM(privPEM) + if err != nil { + return certificate{}, fmt.Errorf("parsing private key: %s", err) + } + return generateSignedCertificateWithKeyInternal(cn, ips, alternateDNS, daysValid, ca, priv) +} + +func generateSignedCertificateWithKeyInternal( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, + ca certificate, + priv crypto.PrivateKey, +) (certificate, error) { + cert := certificate{} + + decodedSignerCert, _ := pem.Decode([]byte(ca.Cert)) + if decodedSignerCert == nil { + return cert, errors.New("unable to decode certificate") + } + signerCert, err := x509.ParseCertificate(decodedSignerCert.Bytes) + if err != nil { + return cert, fmt.Errorf( + "error parsing certificate: decodedSignerCert.Bytes: %s", + err, + ) + } + signerKey, err := parsePrivateKeyPEM(ca.Key) + if err != nil { + return cert, fmt.Errorf( + "error parsing private key: %s", + err, + ) + } + + template, err := getBaseCertTemplate(cn, ips, alternateDNS, daysValid) + if err != nil { + return cert, err + } + + cert.Cert, cert.Key, err = getCertAndKey( + template, + priv, + signerCert, + signerKey, + ) + + return cert, err +} + +func getCertAndKey( + template *x509.Certificate, + signeeKey crypto.PrivateKey, + parent *x509.Certificate, + signingKey crypto.PrivateKey, +) (string, string, error) { + signeePubKey, err := getPublicKey(signeeKey) + if err != nil { + return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err) + } + derBytes, err := x509.CreateCertificate( + rand.Reader, + template, + parent, + signeePubKey, + signingKey, + ) + if err != nil { + return "", "", fmt.Errorf("error creating certificate: %s", err) + } + + certBuffer := bytes.Buffer{} + if err := pem.Encode( + &certBuffer, + &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}, + ); err != nil { + return "", "", fmt.Errorf("error pem-encoding certificate: %s", err) + } + + keyBuffer := bytes.Buffer{} + if err := pem.Encode( + &keyBuffer, + pemBlockForKey(signeeKey), + ); err != nil { + return "", "", fmt.Errorf("error pem-encoding key: %s", err) + } + + return certBuffer.String(), keyBuffer.String(), nil +} + +func getBaseCertTemplate( + cn string, + ips []interface{}, + alternateDNS []interface{}, + daysValid int, +) (*x509.Certificate, error) { + ipAddresses, err := getNetIPs(ips) + if err != nil { + return nil, err + } + dnsNames, err := getAlternateDNSStrs(alternateDNS) + if err != nil { + return nil, err + } + serialNumberUpperBound := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberUpperBound) + if err != nil { + return nil, err + } + return &x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: cn, + }, + IPAddresses: ipAddresses, + DNSNames: dnsNames, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * time.Duration(daysValid)), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{ + x509.ExtKeyUsageServerAuth, + x509.ExtKeyUsageClientAuth, + }, + BasicConstraintsValid: true, + }, nil +} + +func getNetIPs(ips []interface{}) ([]net.IP, error) { + if ips == nil { + return []net.IP{}, nil + } + var ipStr string + var ok bool + var netIP net.IP + netIPs := make([]net.IP, len(ips)) + for i, ip := range ips { + ipStr, ok = ip.(string) + if !ok { + return nil, fmt.Errorf("error parsing ip: %v is not a string", ip) + } + netIP = net.ParseIP(ipStr) + if netIP == nil { + return nil, fmt.Errorf("error parsing ip: %s", ipStr) + } + netIPs[i] = netIP + } + return netIPs, nil +} + +func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) { + if alternateDNS == nil { + return []string{}, nil + } + var dnsStr string + var ok bool + alternateDNSStrs := make([]string, len(alternateDNS)) + for i, dns := range alternateDNS { + dnsStr, ok = dns.(string) + if !ok { + return nil, fmt.Errorf( + "error processing alternate dns name: %v is not a string", + dns, + ) + } + alternateDNSStrs[i] = dnsStr + } + return alternateDNSStrs, nil +} + +func encryptAES(password string, plaintext string) (string, error) { + if plaintext == "" { + return "", nil + } + + key := make([]byte, 32) + copy(key, []byte(password)) + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + content := []byte(plaintext) + blockSize := block.BlockSize() + padding := blockSize - len(content)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + content = append(content, padtext...) + + ciphertext := make([]byte, aes.BlockSize+len(content)) + + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], content) + + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + +func decryptAES(password string, crypt64 string) (string, error) { + if crypt64 == "" { + return "", nil + } + + key := make([]byte, 32) + copy(key, []byte(password)) + + crypt, err := base64.StdEncoding.DecodeString(crypt64) + if err != nil { + return "", err + } + + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + iv := crypt[:aes.BlockSize] + crypt = crypt[aes.BlockSize:] + decrypted := make([]byte, len(crypt)) + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(decrypted, crypt) + + return string(decrypted[:len(decrypted)-int(decrypted[len(decrypted)-1])]), nil +} diff --git a/vendor/github.com/Masterminds/sprig/v3/date.go b/vendor/github.com/Masterminds/sprig/v3/date.go new file mode 100644 index 000000000..ed022ddac --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/date.go @@ -0,0 +1,152 @@ +package sprig + +import ( + "strconv" + "time" +) + +// Given a format and a date, format the date string. +// +// Date can be a `time.Time` or an `int, int32, int64`. +// In the later case, it is treated as seconds since UNIX +// epoch. +func date(fmt string, date interface{}) string { + return dateInZone(fmt, date, "Local") +} + +func htmlDate(date interface{}) string { + return dateInZone("2006-01-02", date, "Local") +} + +func htmlDateInZone(date interface{}, zone string) string { + return dateInZone("2006-01-02", date, zone) +} + +func dateInZone(fmt string, date interface{}, zone string) string { + var t time.Time + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case *time.Time: + t = *date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + case int32: + t = time.Unix(int64(date), 0) + } + + loc, err := time.LoadLocation(zone) + if err != nil { + loc, _ = time.LoadLocation("UTC") + } + + return t.In(loc).Format(fmt) +} + +func dateModify(fmt string, date time.Time) time.Time { + d, err := time.ParseDuration(fmt) + if err != nil { + return date + } + return date.Add(d) +} + +func mustDateModify(fmt string, date time.Time) (time.Time, error) { + d, err := time.ParseDuration(fmt) + if err != nil { + return time.Time{}, err + } + return date.Add(d), nil +} + +func dateAgo(date interface{}) string { + var t time.Time + + switch date := date.(type) { + default: + t = time.Now() + case time.Time: + t = date + case int64: + t = time.Unix(date, 0) + case int: + t = time.Unix(int64(date), 0) + } + // Drop resolution to seconds + duration := time.Since(t).Round(time.Second) + return duration.String() +} + +func duration(sec interface{}) string { + var n int64 + switch value := sec.(type) { + default: + n = 0 + case string: + n, _ = strconv.ParseInt(value, 10, 64) + case int64: + n = value + } + return (time.Duration(n) * time.Second).String() +} + +func durationRound(duration interface{}) string { + var d time.Duration + switch duration := duration.(type) { + default: + d = 0 + case string: + d, _ = time.ParseDuration(duration) + case int64: + d = time.Duration(duration) + case time.Time: + d = time.Since(duration) + } + + u := uint64(d) + neg := d < 0 + if neg { + u = -u + } + + var ( + year = uint64(time.Hour) * 24 * 365 + month = uint64(time.Hour) * 24 * 30 + day = uint64(time.Hour) * 24 + hour = uint64(time.Hour) + minute = uint64(time.Minute) + second = uint64(time.Second) + ) + switch { + case u > year: + return strconv.FormatUint(u/year, 10) + "y" + case u > month: + return strconv.FormatUint(u/month, 10) + "mo" + case u > day: + return strconv.FormatUint(u/day, 10) + "d" + case u > hour: + return strconv.FormatUint(u/hour, 10) + "h" + case u > minute: + return strconv.FormatUint(u/minute, 10) + "m" + case u > second: + return strconv.FormatUint(u/second, 10) + "s" + } + return "0s" +} + +func toDate(fmt, str string) time.Time { + t, _ := time.ParseInLocation(fmt, str, time.Local) + return t +} + +func mustToDate(fmt, str string) (time.Time, error) { + return time.ParseInLocation(fmt, str, time.Local) +} + +func unixEpoch(date time.Time) string { + return strconv.FormatInt(date.Unix(), 10) +} diff --git a/vendor/github.com/Masterminds/sprig/v3/defaults.go b/vendor/github.com/Masterminds/sprig/v3/defaults.go new file mode 100644 index 000000000..b9f979666 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/defaults.go @@ -0,0 +1,163 @@ +package sprig + +import ( + "bytes" + "encoding/json" + "math/rand" + "reflect" + "strings" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// dfault checks whether `given` is set, and returns default if not set. +// +// This returns `d` if `given` appears not to be set, and `given` otherwise. +// +// For numeric types 0 is unset. +// For strings, maps, arrays, and slices, len() = 0 is considered unset. +// For bool, false is unset. +// Structs are never considered unset. +// +// For everything else, including pointers, a nil value is unset. +func dfault(d interface{}, given ...interface{}) interface{} { + + if empty(given) || empty(given[0]) { + return d + } + return given[0] +} + +// empty returns true if the given value has the zero value for its type. +func empty(given interface{}) bool { + g := reflect.ValueOf(given) + if !g.IsValid() { + return true + } + + // Basically adapted from text/template.isTrue + switch g.Kind() { + default: + return g.IsNil() + case reflect.Array, reflect.Slice, reflect.Map, reflect.String: + return g.Len() == 0 + case reflect.Bool: + return !g.Bool() + case reflect.Complex64, reflect.Complex128: + return g.Complex() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return g.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return g.Uint() == 0 + case reflect.Float32, reflect.Float64: + return g.Float() == 0 + case reflect.Struct: + return false + } +} + +// coalesce returns the first non-empty value. +func coalesce(v ...interface{}) interface{} { + for _, val := range v { + if !empty(val) { + return val + } + } + return nil +} + +// all returns true if empty(x) is false for all values x in the list. +// If the list is empty, return true. +func all(v ...interface{}) bool { + for _, val := range v { + if empty(val) { + return false + } + } + return true +} + +// any returns true if empty(x) is false for any x in the list. +// If the list is empty, return false. +func any(v ...interface{}) bool { + for _, val := range v { + if !empty(val) { + return true + } + } + return false +} + +// fromJson decodes JSON into a structured value, ignoring errors. +func fromJson(v string) interface{} { + output, _ := mustFromJson(v) + return output +} + +// mustFromJson decodes JSON into a structured value, returning errors. +func mustFromJson(v string) (interface{}, error) { + var output interface{} + err := json.Unmarshal([]byte(v), &output) + return output, err +} + +// toJson encodes an item into a JSON string +func toJson(v interface{}) string { + output, _ := json.Marshal(v) + return string(output) +} + +func mustToJson(v interface{}) (string, error) { + output, err := json.Marshal(v) + if err != nil { + return "", err + } + return string(output), nil +} + +// toPrettyJson encodes an item into a pretty (indented) JSON string +func toPrettyJson(v interface{}) string { + output, _ := json.MarshalIndent(v, "", " ") + return string(output) +} + +func mustToPrettyJson(v interface{}) (string, error) { + output, err := json.MarshalIndent(v, "", " ") + if err != nil { + return "", err + } + return string(output), nil +} + +// toRawJson encodes an item into a JSON string with no escaping of HTML characters. +func toRawJson(v interface{}) string { + output, err := mustToRawJson(v) + if err != nil { + panic(err) + } + return string(output) +} + +// mustToRawJson encodes an item into a JSON string with no escaping of HTML characters. +func mustToRawJson(v interface{}) (string, error) { + buf := new(bytes.Buffer) + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + err := enc.Encode(&v) + if err != nil { + return "", err + } + return strings.TrimSuffix(buf.String(), "\n"), nil +} + +// ternary returns the first value if the last value is true, otherwise returns the second value. +func ternary(vt interface{}, vf interface{}, v bool) interface{} { + if v { + return vt + } + + return vf +} diff --git a/vendor/github.com/Masterminds/sprig/v3/dict.go b/vendor/github.com/Masterminds/sprig/v3/dict.go new file mode 100644 index 000000000..ade889698 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/dict.go @@ -0,0 +1,174 @@ +package sprig + +import ( + "github.com/imdario/mergo" + "github.com/mitchellh/copystructure" +) + +func get(d map[string]interface{}, key string) interface{} { + if val, ok := d[key]; ok { + return val + } + return "" +} + +func set(d map[string]interface{}, key string, value interface{}) map[string]interface{} { + d[key] = value + return d +} + +func unset(d map[string]interface{}, key string) map[string]interface{} { + delete(d, key) + return d +} + +func hasKey(d map[string]interface{}, key string) bool { + _, ok := d[key] + return ok +} + +func pluck(key string, d ...map[string]interface{}) []interface{} { + res := []interface{}{} + for _, dict := range d { + if val, ok := dict[key]; ok { + res = append(res, val) + } + } + return res +} + +func keys(dicts ...map[string]interface{}) []string { + k := []string{} + for _, dict := range dicts { + for key := range dict { + k = append(k, key) + } + } + return k +} + +func pick(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + for _, k := range keys { + if v, ok := dict[k]; ok { + res[k] = v + } + } + return res +} + +func omit(dict map[string]interface{}, keys ...string) map[string]interface{} { + res := map[string]interface{}{} + + omit := make(map[string]bool, len(keys)) + for _, k := range keys { + omit[k] = true + } + + for k, v := range dict { + if _, ok := omit[k]; !ok { + res[k] = v + } + } + return res +} + +func dict(v ...interface{}) map[string]interface{} { + dict := map[string]interface{}{} + lenv := len(v) + for i := 0; i < lenv; i += 2 { + key := strval(v[i]) + if i+1 >= lenv { + dict[key] = "" + continue + } + dict[key] = v[i+1] + } + return dict +} + +func merge(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} { + for _, src := range srcs { + if err := mergo.Merge(&dst, src); err != nil { + // Swallow errors inside of a template. + return "" + } + } + return dst +} + +func mustMerge(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) { + for _, src := range srcs { + if err := mergo.Merge(&dst, src); err != nil { + return nil, err + } + } + return dst, nil +} + +func mergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) interface{} { + for _, src := range srcs { + if err := mergo.MergeWithOverwrite(&dst, src); err != nil { + // Swallow errors inside of a template. + return "" + } + } + return dst +} + +func mustMergeOverwrite(dst map[string]interface{}, srcs ...map[string]interface{}) (interface{}, error) { + for _, src := range srcs { + if err := mergo.MergeWithOverwrite(&dst, src); err != nil { + return nil, err + } + } + return dst, nil +} + +func values(dict map[string]interface{}) []interface{} { + values := []interface{}{} + for _, value := range dict { + values = append(values, value) + } + + return values +} + +func deepCopy(i interface{}) interface{} { + c, err := mustDeepCopy(i) + if err != nil { + panic("deepCopy error: " + err.Error()) + } + + return c +} + +func mustDeepCopy(i interface{}) (interface{}, error) { + return copystructure.Copy(i) +} + +func dig(ps ...interface{}) (interface{}, error) { + if len(ps) < 3 { + panic("dig needs at least three arguments") + } + dict := ps[len(ps)-1].(map[string]interface{}) + def := ps[len(ps)-2] + ks := make([]string, len(ps)-2) + for i := 0; i < len(ks); i++ { + ks[i] = ps[i].(string) + } + + return digFromDict(dict, def, ks) +} + +func digFromDict(dict map[string]interface{}, d interface{}, ks []string) (interface{}, error) { + k, ns := ks[0], ks[1:len(ks)] + step, has := dict[k] + if !has { + return d, nil + } + if len(ns) == 0 { + return step, nil + } + return digFromDict(step.(map[string]interface{}), d, ns) +} diff --git a/vendor/github.com/Masterminds/sprig/v3/doc.go b/vendor/github.com/Masterminds/sprig/v3/doc.go new file mode 100644 index 000000000..aabb9d448 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/doc.go @@ -0,0 +1,19 @@ +/* +Package sprig provides template functions for Go. + +This package contains a number of utility functions for working with data +inside of Go `html/template` and `text/template` files. + +To add these functions, use the `template.Funcs()` method: + + t := templates.New("foo").Funcs(sprig.FuncMap()) + +Note that you should add the function map before you parse any template files. + + In several cases, Sprig reverses the order of arguments from the way they + appear in the standard library. This is to make it easier to pipe + arguments into functions. + +See http://masterminds.github.io/sprig/ for more detailed documentation on each of the available functions. +*/ +package sprig diff --git a/vendor/github.com/Masterminds/sprig/v3/functions.go b/vendor/github.com/Masterminds/sprig/v3/functions.go new file mode 100644 index 000000000..57fcec1d9 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/functions.go @@ -0,0 +1,382 @@ +package sprig + +import ( + "errors" + "html/template" + "math/rand" + "os" + "path" + "path/filepath" + "reflect" + "strconv" + "strings" + ttemplate "text/template" + "time" + + util "github.com/Masterminds/goutils" + "github.com/huandu/xstrings" + "github.com/shopspring/decimal" +) + +// FuncMap produces the function map. +// +// Use this to pass the functions into the template engine: +// +// tpl := template.New("foo").Funcs(sprig.FuncMap())) +// +func FuncMap() template.FuncMap { + return HtmlFuncMap() +} + +// HermeticTxtFuncMap returns a 'text/template'.FuncMap with only repeatable functions. +func HermeticTxtFuncMap() ttemplate.FuncMap { + r := TxtFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// HermeticHtmlFuncMap returns an 'html/template'.Funcmap with only repeatable functions. +func HermeticHtmlFuncMap() template.FuncMap { + r := HtmlFuncMap() + for _, name := range nonhermeticFunctions { + delete(r, name) + } + return r +} + +// TxtFuncMap returns a 'text/template'.FuncMap +func TxtFuncMap() ttemplate.FuncMap { + return ttemplate.FuncMap(GenericFuncMap()) +} + +// HtmlFuncMap returns an 'html/template'.Funcmap +func HtmlFuncMap() template.FuncMap { + return template.FuncMap(GenericFuncMap()) +} + +// GenericFuncMap returns a copy of the basic function map as a map[string]interface{}. +func GenericFuncMap() map[string]interface{} { + gfm := make(map[string]interface{}, len(genericMap)) + for k, v := range genericMap { + gfm[k] = v + } + return gfm +} + +// These functions are not guaranteed to evaluate to the same result for given input, because they +// refer to the environment or global state. +var nonhermeticFunctions = []string{ + // Date functions + "date", + "date_in_zone", + "date_modify", + "now", + "htmlDate", + "htmlDateInZone", + "dateInZone", + "dateModify", + + // Strings + "randAlphaNum", + "randAlpha", + "randAscii", + "randNumeric", + "randBytes", + "uuidv4", + + // OS + "env", + "expandenv", + + // Network + "getHostByName", +} + +var genericMap = map[string]interface{}{ + "hello": func() string { return "Hello!" }, + + // Date functions + "ago": dateAgo, + "date": date, + "date_in_zone": dateInZone, + "date_modify": dateModify, + "dateInZone": dateInZone, + "dateModify": dateModify, + "duration": duration, + "durationRound": durationRound, + "htmlDate": htmlDate, + "htmlDateInZone": htmlDateInZone, + "must_date_modify": mustDateModify, + "mustDateModify": mustDateModify, + "mustToDate": mustToDate, + "now": time.Now, + "toDate": toDate, + "unixEpoch": unixEpoch, + + // Strings + "abbrev": abbrev, + "abbrevboth": abbrevboth, + "trunc": trunc, + "trim": strings.TrimSpace, + "upper": strings.ToUpper, + "lower": strings.ToLower, + "title": strings.Title, + "untitle": untitle, + "substr": substring, + // Switch order so that "foo" | repeat 5 + "repeat": func(count int, str string) string { return strings.Repeat(str, count) }, + // Deprecated: Use trimAll. + "trimall": func(a, b string) string { return strings.Trim(b, a) }, + // Switch order so that "$foo" | trimall "$" + "trimAll": func(a, b string) string { return strings.Trim(b, a) }, + "trimSuffix": func(a, b string) string { return strings.TrimSuffix(b, a) }, + "trimPrefix": func(a, b string) string { return strings.TrimPrefix(b, a) }, + "nospace": util.DeleteWhiteSpace, + "initials": initials, + "randAlphaNum": randAlphaNumeric, + "randAlpha": randAlpha, + "randAscii": randAscii, + "randNumeric": randNumeric, + "swapcase": util.SwapCase, + "shuffle": xstrings.Shuffle, + "snakecase": xstrings.ToSnakeCase, + "camelcase": xstrings.ToCamelCase, + "kebabcase": xstrings.ToKebabCase, + "wrap": func(l int, s string) string { return util.Wrap(s, l) }, + "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, + // Switch order so that "foobar" | contains "foo" + "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, + "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, + "hasSuffix": func(substr string, str string) bool { return strings.HasSuffix(str, substr) }, + "quote": quote, + "squote": squote, + "cat": cat, + "indent": indent, + "nindent": nindent, + "replace": replace, + "plural": plural, + "sha1sum": sha1sum, + "sha256sum": sha256sum, + "adler32sum": adler32sum, + "toString": strval, + + // Wrap Atoi to stop errors. + "atoi": func(a string) int { i, _ := strconv.Atoi(a); return i }, + "int64": toInt64, + "int": toInt, + "float64": toFloat64, + "seq": seq, + "toDecimal": toDecimal, + + //"gt": func(a, b int) bool {return a > b}, + //"gte": func(a, b int) bool {return a >= b}, + //"lt": func(a, b int) bool {return a < b}, + //"lte": func(a, b int) bool {return a <= b}, + + // split "/" foo/bar returns map[int]string{0: foo, 1: bar} + "split": split, + "splitList": func(sep, orig string) []string { return strings.Split(orig, sep) }, + // splitn "/" foo/bar/fuu returns map[int]string{0: foo, 1: bar/fuu} + "splitn": splitn, + "toStrings": strslice, + + "until": until, + "untilStep": untilStep, + + // VERY basic arithmetic. + "add1": func(i interface{}) int64 { return toInt64(i) + 1 }, + "add": func(i ...interface{}) int64 { + var a int64 = 0 + for _, b := range i { + a += toInt64(b) + } + return a + }, + "sub": func(a, b interface{}) int64 { return toInt64(a) - toInt64(b) }, + "div": func(a, b interface{}) int64 { return toInt64(a) / toInt64(b) }, + "mod": func(a, b interface{}) int64 { return toInt64(a) % toInt64(b) }, + "mul": func(a interface{}, v ...interface{}) int64 { + val := toInt64(a) + for _, b := range v { + val = val * toInt64(b) + } + return val + }, + "randInt": func(min, max int) int { return rand.Intn(max-min) + min }, + "add1f": func(i interface{}) float64 { + return execDecimalOp(i, []interface{}{1}, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) }) + }, + "addf": func(i ...interface{}) float64 { + a := interface{}(float64(0)) + return execDecimalOp(a, i, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Add(d2) }) + }, + "subf": func(a interface{}, v ...interface{}) float64 { + return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Sub(d2) }) + }, + "divf": func(a interface{}, v ...interface{}) float64 { + return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Div(d2) }) + }, + "mulf": func(a interface{}, v ...interface{}) float64 { + return execDecimalOp(a, v, func(d1, d2 decimal.Decimal) decimal.Decimal { return d1.Mul(d2) }) + }, + "biggest": max, + "max": max, + "min": min, + "maxf": maxf, + "minf": minf, + "ceil": ceil, + "floor": floor, + "round": round, + + // string slices. Note that we reverse the order b/c that's better + // for template processing. + "join": join, + "sortAlpha": sortAlpha, + + // Defaults + "default": dfault, + "empty": empty, + "coalesce": coalesce, + "all": all, + "any": any, + "compact": compact, + "mustCompact": mustCompact, + "fromJson": fromJson, + "toJson": toJson, + "toPrettyJson": toPrettyJson, + "toRawJson": toRawJson, + "mustFromJson": mustFromJson, + "mustToJson": mustToJson, + "mustToPrettyJson": mustToPrettyJson, + "mustToRawJson": mustToRawJson, + "ternary": ternary, + "deepCopy": deepCopy, + "mustDeepCopy": mustDeepCopy, + + // Reflection + "typeOf": typeOf, + "typeIs": typeIs, + "typeIsLike": typeIsLike, + "kindOf": kindOf, + "kindIs": kindIs, + "deepEqual": reflect.DeepEqual, + + // OS: + "env": os.Getenv, + "expandenv": os.ExpandEnv, + + // Network: + "getHostByName": getHostByName, + + // Paths: + "base": path.Base, + "dir": path.Dir, + "clean": path.Clean, + "ext": path.Ext, + "isAbs": path.IsAbs, + + // Filepaths: + "osBase": filepath.Base, + "osClean": filepath.Clean, + "osDir": filepath.Dir, + "osExt": filepath.Ext, + "osIsAbs": filepath.IsAbs, + + // Encoding: + "b64enc": base64encode, + "b64dec": base64decode, + "b32enc": base32encode, + "b32dec": base32decode, + + // Data Structures: + "tuple": list, // FIXME: with the addition of append/prepend these are no longer immutable. + "list": list, + "dict": dict, + "get": get, + "set": set, + "unset": unset, + "hasKey": hasKey, + "pluck": pluck, + "keys": keys, + "pick": pick, + "omit": omit, + "merge": merge, + "mergeOverwrite": mergeOverwrite, + "mustMerge": mustMerge, + "mustMergeOverwrite": mustMergeOverwrite, + "values": values, + + "append": push, "push": push, + "mustAppend": mustPush, "mustPush": mustPush, + "prepend": prepend, + "mustPrepend": mustPrepend, + "first": first, + "mustFirst": mustFirst, + "rest": rest, + "mustRest": mustRest, + "last": last, + "mustLast": mustLast, + "initial": initial, + "mustInitial": mustInitial, + "reverse": reverse, + "mustReverse": mustReverse, + "uniq": uniq, + "mustUniq": mustUniq, + "without": without, + "mustWithout": mustWithout, + "has": has, + "mustHas": mustHas, + "slice": slice, + "mustSlice": mustSlice, + "concat": concat, + "dig": dig, + "chunk": chunk, + "mustChunk": mustChunk, + + // Crypto: + "bcrypt": bcrypt, + "htpasswd": htpasswd, + "genPrivateKey": generatePrivateKey, + "derivePassword": derivePassword, + "buildCustomCert": buildCustomCertificate, + "genCA": generateCertificateAuthority, + "genCAWithKey": generateCertificateAuthorityWithPEMKey, + "genSelfSignedCert": generateSelfSignedCertificate, + "genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey, + "genSignedCert": generateSignedCertificate, + "genSignedCertWithKey": generateSignedCertificateWithPEMKey, + "encryptAES": encryptAES, + "decryptAES": decryptAES, + "randBytes": randBytes, + + // UUIDs: + "uuidv4": uuidv4, + + // SemVer: + "semver": semver, + "semverCompare": semverCompare, + + // Flow Control: + "fail": func(msg string) (string, error) { return "", errors.New(msg) }, + + // Regex + "regexMatch": regexMatch, + "mustRegexMatch": mustRegexMatch, + "regexFindAll": regexFindAll, + "mustRegexFindAll": mustRegexFindAll, + "regexFind": regexFind, + "mustRegexFind": mustRegexFind, + "regexReplaceAll": regexReplaceAll, + "mustRegexReplaceAll": mustRegexReplaceAll, + "regexReplaceAllLiteral": regexReplaceAllLiteral, + "mustRegexReplaceAllLiteral": mustRegexReplaceAllLiteral, + "regexSplit": regexSplit, + "mustRegexSplit": mustRegexSplit, + "regexQuoteMeta": regexQuoteMeta, + + // URLs: + "urlParse": urlParse, + "urlJoin": urlJoin, +} diff --git a/vendor/github.com/Masterminds/sprig/v3/list.go b/vendor/github.com/Masterminds/sprig/v3/list.go new file mode 100644 index 000000000..ca0fbb789 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/list.go @@ -0,0 +1,464 @@ +package sprig + +import ( + "fmt" + "math" + "reflect" + "sort" +) + +// Reflection is used in these functions so that slices and arrays of strings, +// ints, and other types not implementing []interface{} can be worked with. +// For example, this is useful if you need to work on the output of regexs. + +func list(v ...interface{}) []interface{} { + return v +} + +func push(list interface{}, v interface{}) []interface{} { + l, err := mustPush(list, v) + if err != nil { + panic(err) + } + + return l +} + +func mustPush(list interface{}, v interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } + + return append(nl, v), nil + + default: + return nil, fmt.Errorf("Cannot push on type %s", tp) + } +} + +func prepend(list interface{}, v interface{}) []interface{} { + l, err := mustPrepend(list, v) + if err != nil { + panic(err) + } + + return l +} + +func mustPrepend(list interface{}, v interface{}) ([]interface{}, error) { + //return append([]interface{}{v}, list...) + + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[i] = l2.Index(i).Interface() + } + + return append([]interface{}{v}, nl...), nil + + default: + return nil, fmt.Errorf("Cannot prepend on type %s", tp) + } +} + +func chunk(size int, list interface{}) [][]interface{} { + l, err := mustChunk(size, list) + if err != nil { + panic(err) + } + + return l +} + +func mustChunk(size int, list interface{}) ([][]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + + cs := int(math.Floor(float64(l-1)/float64(size)) + 1) + nl := make([][]interface{}, cs) + + for i := 0; i < cs; i++ { + clen := size + if i == cs-1 { + clen = int(math.Floor(math.Mod(float64(l), float64(size)))) + if clen == 0 { + clen = size + } + } + + nl[i] = make([]interface{}, clen) + + for j := 0; j < clen; j++ { + ix := i*size + j + nl[i][j] = l2.Index(ix).Interface() + } + } + + return nl, nil + + default: + return nil, fmt.Errorf("Cannot chunk type %s", tp) + } +} + +func last(list interface{}) interface{} { + l, err := mustLast(list) + if err != nil { + panic(err) + } + + return l +} + +func mustLast(list interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + return l2.Index(l - 1).Interface(), nil + default: + return nil, fmt.Errorf("Cannot find last on type %s", tp) + } +} + +func first(list interface{}) interface{} { + l, err := mustFirst(list) + if err != nil { + panic(err) + } + + return l +} + +func mustFirst(list interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + return l2.Index(0).Interface(), nil + default: + return nil, fmt.Errorf("Cannot find first on type %s", tp) + } +} + +func rest(list interface{}) []interface{} { + l, err := mustRest(list) + if err != nil { + panic(err) + } + + return l +} + +func mustRest(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + nl := make([]interface{}, l-1) + for i := 1; i < l; i++ { + nl[i-1] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find rest on type %s", tp) + } +} + +func initial(list interface{}) []interface{} { + l, err := mustInitial(list) + if err != nil { + panic(err) + } + + return l +} + +func mustInitial(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + nl := make([]interface{}, l-1) + for i := 0; i < l-1; i++ { + nl[i] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find initial on type %s", tp) + } +} + +func sortAlpha(list interface{}) []string { + k := reflect.Indirect(reflect.ValueOf(list)).Kind() + switch k { + case reflect.Slice, reflect.Array: + a := strslice(list) + s := sort.StringSlice(a) + s.Sort() + return s + } + return []string{strval(list)} +} + +func reverse(v interface{}) []interface{} { + l, err := mustReverse(v) + if err != nil { + panic(err) + } + + return l +} + +func mustReverse(v interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(v).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(v) + + l := l2.Len() + // We do not sort in place because the incoming array should not be altered. + nl := make([]interface{}, l) + for i := 0; i < l; i++ { + nl[l-i-1] = l2.Index(i).Interface() + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot find reverse on type %s", tp) + } +} + +func compact(list interface{}) []interface{} { + l, err := mustCompact(list) + if err != nil { + panic(err) + } + + return l +} + +func mustCompact(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + nl := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !empty(item) { + nl = append(nl, item) + } + } + + return nl, nil + default: + return nil, fmt.Errorf("Cannot compact on type %s", tp) + } +} + +func uniq(list interface{}) []interface{} { + l, err := mustUniq(list) + if err != nil { + panic(err) + } + + return l +} + +func mustUniq(list interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + dest := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(dest, item) { + dest = append(dest, item) + } + } + + return dest, nil + default: + return nil, fmt.Errorf("Cannot find uniq on type %s", tp) + } +} + +func inList(haystack []interface{}, needle interface{}) bool { + for _, h := range haystack { + if reflect.DeepEqual(needle, h) { + return true + } + } + return false +} + +func without(list interface{}, omit ...interface{}) []interface{} { + l, err := mustWithout(list, omit...) + if err != nil { + panic(err) + } + + return l +} + +func mustWithout(list interface{}, omit ...interface{}) ([]interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + res := []interface{}{} + var item interface{} + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if !inList(omit, item) { + res = append(res, item) + } + } + + return res, nil + default: + return nil, fmt.Errorf("Cannot find without on type %s", tp) + } +} + +func has(needle interface{}, haystack interface{}) bool { + l, err := mustHas(needle, haystack) + if err != nil { + panic(err) + } + + return l +} + +func mustHas(needle interface{}, haystack interface{}) (bool, error) { + if haystack == nil { + return false, nil + } + tp := reflect.TypeOf(haystack).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(haystack) + var item interface{} + l := l2.Len() + for i := 0; i < l; i++ { + item = l2.Index(i).Interface() + if reflect.DeepEqual(needle, item) { + return true, nil + } + } + + return false, nil + default: + return false, fmt.Errorf("Cannot find has on type %s", tp) + } +} + +// $list := [1, 2, 3, 4, 5] +// slice $list -> list[0:5] = list[:] +// slice $list 0 3 -> list[0:3] = list[:3] +// slice $list 3 5 -> list[3:5] +// slice $list 3 -> list[3:5] = list[3:] +func slice(list interface{}, indices ...interface{}) interface{} { + l, err := mustSlice(list, indices...) + if err != nil { + panic(err) + } + + return l +} + +func mustSlice(list interface{}, indices ...interface{}) (interface{}, error) { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + + l := l2.Len() + if l == 0 { + return nil, nil + } + + var start, end int + if len(indices) > 0 { + start = toInt(indices[0]) + } + if len(indices) < 2 { + end = l + } else { + end = toInt(indices[1]) + } + + return l2.Slice(start, end).Interface(), nil + default: + return nil, fmt.Errorf("list should be type of slice or array but %s", tp) + } +} + +func concat(lists ...interface{}) interface{} { + var res []interface{} + for _, list := range lists { + tp := reflect.TypeOf(list).Kind() + switch tp { + case reflect.Slice, reflect.Array: + l2 := reflect.ValueOf(list) + for i := 0; i < l2.Len(); i++ { + res = append(res, l2.Index(i).Interface()) + } + default: + panic(fmt.Sprintf("Cannot concat type %s as list", tp)) + } + } + return res +} diff --git a/vendor/github.com/Masterminds/sprig/v3/network.go b/vendor/github.com/Masterminds/sprig/v3/network.go new file mode 100644 index 000000000..108d78a94 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/network.go @@ -0,0 +1,12 @@ +package sprig + +import ( + "math/rand" + "net" +) + +func getHostByName(name string) string { + addrs, _ := net.LookupHost(name) + //TODO: add error handing when release v3 comes out + return addrs[rand.Intn(len(addrs))] +} diff --git a/vendor/github.com/Masterminds/sprig/v3/numeric.go b/vendor/github.com/Masterminds/sprig/v3/numeric.go new file mode 100644 index 000000000..f68e4182e --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/numeric.go @@ -0,0 +1,186 @@ +package sprig + +import ( + "fmt" + "math" + "strconv" + "strings" + + "github.com/spf13/cast" + "github.com/shopspring/decimal" +) + +// toFloat64 converts 64-bit floats +func toFloat64(v interface{}) float64 { + return cast.ToFloat64(v) +} + +func toInt(v interface{}) int { + return cast.ToInt(v) +} + +// toInt64 converts integer types to 64-bit integers +func toInt64(v interface{}) int64 { + return cast.ToInt64(v) +} + +func max(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb > aa { + aa = bb + } + } + return aa +} + +func maxf(a interface{}, i ...interface{}) float64 { + aa := toFloat64(a) + for _, b := range i { + bb := toFloat64(b) + aa = math.Max(aa, bb) + } + return aa +} + +func min(a interface{}, i ...interface{}) int64 { + aa := toInt64(a) + for _, b := range i { + bb := toInt64(b) + if bb < aa { + aa = bb + } + } + return aa +} + +func minf(a interface{}, i ...interface{}) float64 { + aa := toFloat64(a) + for _, b := range i { + bb := toFloat64(b) + aa = math.Min(aa, bb) + } + return aa +} + +func until(count int) []int { + step := 1 + if count < 0 { + step = -1 + } + return untilStep(0, count, step) +} + +func untilStep(start, stop, step int) []int { + v := []int{} + + if stop < start { + if step >= 0 { + return v + } + for i := start; i > stop; i += step { + v = append(v, i) + } + return v + } + + if step <= 0 { + return v + } + for i := start; i < stop; i += step { + v = append(v, i) + } + return v +} + +func floor(a interface{}) float64 { + aa := toFloat64(a) + return math.Floor(aa) +} + +func ceil(a interface{}) float64 { + aa := toFloat64(a) + return math.Ceil(aa) +} + +func round(a interface{}, p int, rOpt ...float64) float64 { + roundOn := .5 + if len(rOpt) > 0 { + roundOn = rOpt[0] + } + val := toFloat64(a) + places := toFloat64(p) + + var round float64 + pow := math.Pow(10, places) + digit := pow * val + _, div := math.Modf(digit) + if div >= roundOn { + round = math.Ceil(digit) + } else { + round = math.Floor(digit) + } + return round / pow +} + +// converts unix octal to decimal +func toDecimal(v interface{}) int64 { + result, err := strconv.ParseInt(fmt.Sprint(v), 8, 64) + if err != nil { + return 0 + } + return result +} + +func seq(params ...int) string { + increment := 1 + switch len(params) { + case 0: + return "" + case 1: + start := 1 + end := params[0] + if end < start { + increment = -1 + } + return intArrayToString(untilStep(start, end+increment, increment), " ") + case 3: + start := params[0] + end := params[2] + step := params[1] + if end < start { + increment = -1 + if step > 0 { + return "" + } + } + return intArrayToString(untilStep(start, end+increment, step), " ") + case 2: + start := params[0] + end := params[1] + step := 1 + if end < start { + step = -1 + } + return intArrayToString(untilStep(start, end+step, step), " ") + default: + return "" + } +} + +func intArrayToString(slice []int, delimeter string) string { + return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]") +} + +// performs a float and subsequent decimal.Decimal conversion on inputs, +// and iterates through a and b executing the mathmetical operation f +func execDecimalOp(a interface{}, b []interface{}, f func(d1, d2 decimal.Decimal) decimal.Decimal) float64 { + prt := decimal.NewFromFloat(toFloat64(a)) + for _, x := range b { + dx := decimal.NewFromFloat(toFloat64(x)) + prt = f(prt, dx) + } + rslt, _ := prt.Float64() + return rslt +} diff --git a/vendor/github.com/Masterminds/sprig/v3/reflect.go b/vendor/github.com/Masterminds/sprig/v3/reflect.go new file mode 100644 index 000000000..8a65c132f --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/reflect.go @@ -0,0 +1,28 @@ +package sprig + +import ( + "fmt" + "reflect" +) + +// typeIs returns true if the src is the type named in target. +func typeIs(target string, src interface{}) bool { + return target == typeOf(src) +} + +func typeIsLike(target string, src interface{}) bool { + t := typeOf(src) + return target == t || "*"+target == t +} + +func typeOf(src interface{}) string { + return fmt.Sprintf("%T", src) +} + +func kindIs(target string, src interface{}) bool { + return target == kindOf(src) +} + +func kindOf(src interface{}) string { + return reflect.ValueOf(src).Kind().String() +} diff --git a/vendor/github.com/Masterminds/sprig/v3/regex.go b/vendor/github.com/Masterminds/sprig/v3/regex.go new file mode 100644 index 000000000..fab551018 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/regex.go @@ -0,0 +1,83 @@ +package sprig + +import ( + "regexp" +) + +func regexMatch(regex string, s string) bool { + match, _ := regexp.MatchString(regex, s) + return match +} + +func mustRegexMatch(regex string, s string) (bool, error) { + return regexp.MatchString(regex, s) +} + +func regexFindAll(regex string, s string, n int) []string { + r := regexp.MustCompile(regex) + return r.FindAllString(s, n) +} + +func mustRegexFindAll(regex string, s string, n int) ([]string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return []string{}, err + } + return r.FindAllString(s, n), nil +} + +func regexFind(regex string, s string) string { + r := regexp.MustCompile(regex) + return r.FindString(s) +} + +func mustRegexFind(regex string, s string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.FindString(s), nil +} + +func regexReplaceAll(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllString(s, repl) +} + +func mustRegexReplaceAll(regex string, s string, repl string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.ReplaceAllString(s, repl), nil +} + +func regexReplaceAllLiteral(regex string, s string, repl string) string { + r := regexp.MustCompile(regex) + return r.ReplaceAllLiteralString(s, repl) +} + +func mustRegexReplaceAllLiteral(regex string, s string, repl string) (string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return "", err + } + return r.ReplaceAllLiteralString(s, repl), nil +} + +func regexSplit(regex string, s string, n int) []string { + r := regexp.MustCompile(regex) + return r.Split(s, n) +} + +func mustRegexSplit(regex string, s string, n int) ([]string, error) { + r, err := regexp.Compile(regex) + if err != nil { + return []string{}, err + } + return r.Split(s, n), nil +} + +func regexQuoteMeta(s string) string { + return regexp.QuoteMeta(s) +} diff --git a/vendor/github.com/Masterminds/sprig/v3/semver.go b/vendor/github.com/Masterminds/sprig/v3/semver.go new file mode 100644 index 000000000..3fbe08aa6 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/semver.go @@ -0,0 +1,23 @@ +package sprig + +import ( + sv2 "github.com/Masterminds/semver/v3" +) + +func semverCompare(constraint, version string) (bool, error) { + c, err := sv2.NewConstraint(constraint) + if err != nil { + return false, err + } + + v, err := sv2.NewVersion(version) + if err != nil { + return false, err + } + + return c.Check(v), nil +} + +func semver(version string) (*sv2.Version, error) { + return sv2.NewVersion(version) +} diff --git a/vendor/github.com/Masterminds/sprig/v3/strings.go b/vendor/github.com/Masterminds/sprig/v3/strings.go new file mode 100644 index 000000000..e0ae628c8 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/strings.go @@ -0,0 +1,236 @@ +package sprig + +import ( + "encoding/base32" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + + util "github.com/Masterminds/goutils" +) + +func base64encode(v string) string { + return base64.StdEncoding.EncodeToString([]byte(v)) +} + +func base64decode(v string) string { + data, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func base32encode(v string) string { + return base32.StdEncoding.EncodeToString([]byte(v)) +} + +func base32decode(v string) string { + data, err := base32.StdEncoding.DecodeString(v) + if err != nil { + return err.Error() + } + return string(data) +} + +func abbrev(width int, s string) string { + if width < 4 { + return s + } + r, _ := util.Abbreviate(s, width) + return r +} + +func abbrevboth(left, right int, s string) string { + if right < 4 || left > 0 && right < 7 { + return s + } + r, _ := util.AbbreviateFull(s, left, right) + return r +} +func initials(s string) string { + // Wrap this just to eliminate the var args, which templates don't do well. + return util.Initials(s) +} + +func randAlphaNumeric(count int) string { + // It is not possible, it appears, to actually generate an error here. + r, _ := util.CryptoRandomAlphaNumeric(count) + return r +} + +func randAlpha(count int) string { + r, _ := util.CryptoRandomAlphabetic(count) + return r +} + +func randAscii(count int) string { + r, _ := util.CryptoRandomAscii(count) + return r +} + +func randNumeric(count int) string { + r, _ := util.CryptoRandomNumeric(count) + return r +} + +func untitle(str string) string { + return util.Uncapitalize(str) +} + +func quote(str ...interface{}) string { + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("%q", strval(s))) + } + } + return strings.Join(out, " ") +} + +func squote(str ...interface{}) string { + out := make([]string, 0, len(str)) + for _, s := range str { + if s != nil { + out = append(out, fmt.Sprintf("'%v'", s)) + } + } + return strings.Join(out, " ") +} + +func cat(v ...interface{}) string { + v = removeNilElements(v) + r := strings.TrimSpace(strings.Repeat("%v ", len(v))) + return fmt.Sprintf(r, v...) +} + +func indent(spaces int, v string) string { + pad := strings.Repeat(" ", spaces) + return pad + strings.Replace(v, "\n", "\n"+pad, -1) +} + +func nindent(spaces int, v string) string { + return "\n" + indent(spaces, v) +} + +func replace(old, new, src string) string { + return strings.Replace(src, old, new, -1) +} + +func plural(one, many string, count int) string { + if count == 1 { + return one + } + return many +} + +func strslice(v interface{}) []string { + switch v := v.(type) { + case []string: + return v + case []interface{}: + b := make([]string, 0, len(v)) + for _, s := range v { + if s != nil { + b = append(b, strval(s)) + } + } + return b + default: + val := reflect.ValueOf(v) + switch val.Kind() { + case reflect.Array, reflect.Slice: + l := val.Len() + b := make([]string, 0, l) + for i := 0; i < l; i++ { + value := val.Index(i).Interface() + if value != nil { + b = append(b, strval(value)) + } + } + return b + default: + if v == nil { + return []string{} + } + + return []string{strval(v)} + } + } +} + +func removeNilElements(v []interface{}) []interface{} { + newSlice := make([]interface{}, 0, len(v)) + for _, i := range v { + if i != nil { + newSlice = append(newSlice, i) + } + } + return newSlice +} + +func strval(v interface{}) string { + switch v := v.(type) { + case string: + return v + case []byte: + return string(v) + case error: + return v.Error() + case fmt.Stringer: + return v.String() + default: + return fmt.Sprintf("%v", v) + } +} + +func trunc(c int, s string) string { + if c < 0 && len(s)+c > 0 { + return s[len(s)+c:] + } + if c >= 0 && len(s) > c { + return s[:c] + } + return s +} + +func join(sep string, v interface{}) string { + return strings.Join(strslice(v), sep) +} + +func split(sep, orig string) map[string]string { + parts := strings.Split(orig, sep) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + +func splitn(sep string, n int, orig string) map[string]string { + parts := strings.SplitN(orig, sep, n) + res := make(map[string]string, len(parts)) + for i, v := range parts { + res["_"+strconv.Itoa(i)] = v + } + return res +} + +// substring creates a substring of the given string. +// +// If start is < 0, this calls string[:end]. +// +// If start is >= 0 and end < 0 or end bigger than s length, this calls string[start:] +// +// Otherwise, this calls string[start, end]. +func substring(start, end int, s string) string { + if start < 0 { + return s[:end] + } + if end < 0 || end > len(s) { + return s[start:] + } + return s[start:end] +} diff --git a/vendor/github.com/Masterminds/sprig/v3/url.go b/vendor/github.com/Masterminds/sprig/v3/url.go new file mode 100644 index 000000000..b8e120e19 --- /dev/null +++ b/vendor/github.com/Masterminds/sprig/v3/url.go @@ -0,0 +1,66 @@ +package sprig + +import ( + "fmt" + "net/url" + "reflect" +) + +func dictGetOrEmpty(dict map[string]interface{}, key string) string { + value, ok := dict[key] + if !ok { + return "" + } + tp := reflect.TypeOf(value).Kind() + if tp != reflect.String { + panic(fmt.Sprintf("unable to parse %s key, must be of type string, but %s found", key, tp.String())) + } + return reflect.ValueOf(value).String() +} + +// parses given URL to return dict object +func urlParse(v string) map[string]interface{} { + dict := map[string]interface{}{} + parsedURL, err := url.Parse(v) + if err != nil { + panic(fmt.Sprintf("unable to parse url: %s", err)) + } + dict["scheme"] = parsedURL.Scheme + dict["host"] = parsedURL.Host + dict["hostname"] = parsedURL.Hostname() + dict["path"] = parsedURL.Path + dict["query"] = parsedURL.RawQuery + dict["opaque"] = parsedURL.Opaque + dict["fragment"] = parsedURL.Fragment + if parsedURL.User != nil { + dict["userinfo"] = parsedURL.User.String() + } else { + dict["userinfo"] = "" + } + + return dict +} + +// join given dict to URL string +func urlJoin(d map[string]interface{}) string { + resURL := url.URL{ + Scheme: dictGetOrEmpty(d, "scheme"), + Host: dictGetOrEmpty(d, "host"), + Path: dictGetOrEmpty(d, "path"), + RawQuery: dictGetOrEmpty(d, "query"), + Opaque: dictGetOrEmpty(d, "opaque"), + Fragment: dictGetOrEmpty(d, "fragment"), + } + userinfo := dictGetOrEmpty(d, "userinfo") + var user *url.Userinfo + if userinfo != "" { + tempURL, err := url.Parse(fmt.Sprintf("proto://%s@host", userinfo)) + if err != nil { + panic(fmt.Sprintf("unable to parse userinfo in dict: %s", err)) + } + user = tempURL.User + } + + resURL.User = user + return resURL.String() +} diff --git a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md index 02a73ccfd..5edd5a7ca 100644 --- a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md +++ b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md @@ -1,6 +1,15 @@ # Change history of go-restful -## [v3.10.1] - 2022-11-19 +## [v3.11.0] - 2023-08-19 + +- restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled. + +## [v3.10.2] - 2023-03-09 - DO NOT USE + +- introduced MergePathStrategy to be able to revert behaviour of path concatenation to 3.9.0 + see comment in Readme how to customize this behaviour. + +## [v3.10.1] - 2022-11-19 - DO NOT USE - fix broken 3.10.0 by using path package for joining paths diff --git a/vendor/github.com/emicklei/go-restful/v3/README.md b/vendor/github.com/emicklei/go-restful/v3/README.md index 0625359dc..e3e30080e 100644 --- a/vendor/github.com/emicklei/go-restful/v3/README.md +++ b/vendor/github.com/emicklei/go-restful/v3/README.md @@ -79,7 +79,7 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo - Content encoding (gzip,deflate) of request and response payloads - Automatic responses on OPTIONS (using a filter) - Automatic CORS request handling (using a filter) -- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi), see [go-restful-swagger12](https://github.com/emicklei/go-restful-swagger12)) +- API declaration for Swagger UI ([go-restful-openapi](https://github.com/emicklei/go-restful-openapi)) - Panic recovery to produce HTTP 500, customizable using RecoverHandler(...) - Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...) - Configurable (trace) logging @@ -96,6 +96,7 @@ There are several hooks to customize the behavior of the go-restful package. - Compression - Encoders for other serializers - Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .` +- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/` ## Resources @@ -108,4 +109,4 @@ There are several hooks to customize the behavior of the go-restful package. Type ```git shortlog -s``` for a full list of contributors. -© 2012 - 2022, http://ernestmicklei.com. MIT License. Contributions are welcome. +© 2012 - 2023, http://ernestmicklei.com. MIT License. Contributions are welcome. diff --git a/vendor/github.com/emicklei/go-restful/v3/route.go b/vendor/github.com/emicklei/go-restful/v3/route.go index ea05b3da8..306c44be7 100644 --- a/vendor/github.com/emicklei/go-restful/v3/route.go +++ b/vendor/github.com/emicklei/go-restful/v3/route.go @@ -40,7 +40,8 @@ type Route struct { ParameterDocs []*Parameter ResponseErrors map[int]ResponseError DefaultResponse *ResponseError - ReadSample, WriteSample interface{} // structs that model an example request or response payload + ReadSample, WriteSample interface{} // structs that model an example request or response payload + WriteSamples []interface{} // if more than one return types is possible (oneof) then this will contain multiple values // Extra information used to store custom information about the route. Metadata map[string]interface{} @@ -164,7 +165,13 @@ func tokenizePath(path string) []string { if "/" == path { return nil } - return strings.Split(strings.TrimLeft(path, "/"), "/") + if TrimRightSlashEnabled { + // 3.9.0 + return strings.Split(strings.Trim(path, "/"), "/") + } else { + // 3.10.2 + return strings.Split(strings.TrimLeft(path, "/"), "/") + } } // for debugging @@ -177,4 +184,8 @@ func (r *Route) EnableContentEncoding(enabled bool) { r.contentEncodingEnabled = &enabled } -var TrimRightSlashEnabled = false +// TrimRightSlashEnabled controls whether +// - path on route building is using path.Join +// - the path of the incoming request is trimmed of its slash suffux. +// Value of true matches the behavior of <= 3.9.0 +var TrimRightSlashEnabled = true diff --git a/vendor/github.com/emicklei/go-restful/v3/route_builder.go b/vendor/github.com/emicklei/go-restful/v3/route_builder.go index 830ebf148..75168c12e 100644 --- a/vendor/github.com/emicklei/go-restful/v3/route_builder.go +++ b/vendor/github.com/emicklei/go-restful/v3/route_builder.go @@ -31,17 +31,18 @@ type RouteBuilder struct { typeNameHandleFunc TypeNameHandleFunction // required // documentation - doc string - notes string - operation string - readSample, writeSample interface{} - parameters []*Parameter - errorMap map[int]ResponseError - defaultResponse *ResponseError - metadata map[string]interface{} - extensions map[string]interface{} - deprecated bool - contentEncodingEnabled *bool + doc string + notes string + operation string + readSample interface{} + writeSamples []interface{} + parameters []*Parameter + errorMap map[int]ResponseError + defaultResponse *ResponseError + metadata map[string]interface{} + extensions map[string]interface{} + deprecated bool + contentEncodingEnabled *bool } // Do evaluates each argument with the RouteBuilder itself. @@ -135,9 +136,9 @@ func (b RouteBuilder) ParameterNamed(name string) (p *Parameter) { return p } -// Writes tells what resource type will be written as the response payload. Optional. -func (b *RouteBuilder) Writes(sample interface{}) *RouteBuilder { - b.writeSample = sample +// Writes tells which one of the resource types will be written as the response payload. Optional. +func (b *RouteBuilder) Writes(samples ...interface{}) *RouteBuilder { + b.writeSamples = samples // oneof return b } @@ -342,19 +343,29 @@ func (b *RouteBuilder) Build() Route { ResponseErrors: b.errorMap, DefaultResponse: b.defaultResponse, ReadSample: b.readSample, - WriteSample: b.writeSample, + WriteSamples: b.writeSamples, Metadata: b.metadata, Deprecated: b.deprecated, contentEncodingEnabled: b.contentEncodingEnabled, allowedMethodsWithoutContentType: b.allowedMethodsWithoutContentType, } + // set WriteSample if one specified + if len(b.writeSamples) == 1 { + route.WriteSample = b.writeSamples[0] + } route.Extensions = b.extensions route.postBuild() return route } -func concatPath(path1, path2 string) string { - return path.Join(path1, path2) +// merge two paths using the current (package global) merge path strategy. +func concatPath(rootPath, routePath string) string { + + if TrimRightSlashEnabled { + return strings.TrimRight(rootPath, "/") + "/" + strings.TrimLeft(routePath, "/") + } else { + return path.Join(rootPath, routePath) + } } var anonymousFuncCount int32 diff --git a/vendor/github.com/gardener/etcd-druid/api/v1alpha1/types_etcd.go b/vendor/github.com/gardener/etcd-druid/api/v1alpha1/types_etcd.go index d899b1f53..a4686d4e3 100644 --- a/vendor/github.com/gardener/etcd-druid/api/v1alpha1/types_etcd.go +++ b/vendor/github.com/gardener/etcd-druid/api/v1alpha1/types_etcd.go @@ -178,6 +178,13 @@ type BackupSpec struct { // DeltaSnapshotMemoryLimit defines the memory limit after which delta snapshots will be taken // +optional DeltaSnapshotMemoryLimit *resource.Quantity `json:"deltaSnapshotMemoryLimit,omitempty"` + // DeltaSnapshotRetentionPeriod defines the duration for which delta snapshots will be retained, excluding the latest snapshot set. + // The value should be a string formatted as a duration (e.g., '1s', '2m', '3h', '4d') + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9][0-9]*([.][0-9]+)?(s|m|h|d))+$" + // +optional + DeltaSnapshotRetentionPeriod *metav1.Duration `json:"deltaSnapshotRetentionPeriod,omitempty"` + // SnapshotCompression defines the specification for compression of Snapshots. // +optional SnapshotCompression *CompressionSpec `json:"compression,omitempty"` @@ -437,7 +444,7 @@ func (e *Etcd) GetConfigmapName() string { // GetCompactionJobName returns the compaction job name for the Etcd. func (e *Etcd) GetCompactionJobName() string { - return fmt.Sprintf("%s-compact-job", string(e.UID[:6])) + return fmt.Sprintf("%s-compactor", e.Name) } // GetOrdinalPodName returns the Etcd pod name based on the ordinal. diff --git a/vendor/github.com/gardener/etcd-druid/api/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/gardener/etcd-druid/api/v1alpha1/zz_generated.deepcopy.go index 563aae732..b8f81b5e1 100644 --- a/vendor/github.com/gardener/etcd-druid/api/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/etcd-druid/api/v1alpha1/zz_generated.deepcopy.go @@ -83,6 +83,11 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) { x := (*in).DeepCopy() *out = &x } + if in.DeltaSnapshotRetentionPeriod != nil { + in, out := &in.DeltaSnapshotRetentionPeriod, &out.DeltaSnapshotRetentionPeriod + *out = new(metav1.Duration) + **out = **in + } if in.SnapshotCompression != nil { in, out := &in.SnapshotCompression, &out.SnapshotCompression *out = new(CompressionSpec) diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/cmd/options.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/cmd/options.go index c5139a47a..edfcd5751 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/cmd/options.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/cmd/options.go @@ -73,9 +73,10 @@ const ( // GardenerVersionFlag is the name of the command line flag containing the Gardener version. GardenerVersionFlag = "gardener-version" - // GardenletManagesMCMFlag is the name of the command line flag containing the Gardener version. - // TODO(rfranzke): Remove this flag when the MachineControllerManagerDeployment feature gate is promoted to GA. - GardenletManagesMCMFlag = "gardenlet-manages-mcm" + // GardenletUsesGardenerNodeAgentFlag is the name of the command line flag specifying whether gardenlet's feature gate + // 'UseGardenerNodeAgent' is activated. + // TODO(rfranzke): Remove this flag when the UseGardenerNodeAgent feature gate is promoted to GA. + GardenletUsesGardenerNodeAgentFlag = "gardenlet-uses-gardener-node-agent" // LogLevelFlag is the name of the command line flag containing the log level. LogLevelFlag = "log-level" @@ -473,8 +474,8 @@ type SwitchConfig struct { type GeneralOptions struct { // GardenerVersion is the version of the Gardener. GardenerVersion string - // GardenletManagesMCM specifies whether gardenlet manages the machine-controller-manager. - GardenletManagesMCM bool + // GardenletUsesGardenerNodeAgent specifies whether gardenlet's feature gate 'UseGardenerNodeAgent' is activated. + GardenletUsesGardenerNodeAgent bool config *GeneralConfig } @@ -483,13 +484,13 @@ type GeneralOptions struct { type GeneralConfig struct { // GardenerVersion is the version of the Gardener. GardenerVersion string - // GardenletManagesMCM specifies whether gardenlet manages the machine-controller-manager. - GardenletManagesMCM bool + // GardenletUsesGardenerNodeAgent specifies whether gardenlet's feature gate 'UseGardenerNodeAgent' is activated. + GardenletUsesGardenerNodeAgent bool } // Complete implements Complete. func (r *GeneralOptions) Complete() error { - r.config = &GeneralConfig{r.GardenerVersion, r.GardenletManagesMCM} + r.config = &GeneralConfig{r.GardenerVersion, r.GardenletUsesGardenerNodeAgent} return nil } @@ -501,5 +502,5 @@ func (r *GeneralOptions) Completed() *GeneralConfig { // AddFlags implements Flagger.AddFlags. func (r *GeneralOptions) AddFlags(fs *pflag.FlagSet) { fs.StringVar(&r.GardenerVersion, GardenerVersionFlag, "", "Version of the gardenlet.") - fs.BoolVar(&r.GardenletManagesMCM, GardenletManagesMCMFlag, false, "Specifies whether gardenlet manages the machine-controller-manager.") + fs.BoolVar(&r.GardenletUsesGardenerNodeAgent, GardenletUsesGardenerNodeAgentFlag, false, "Specifies whether gardenlet's feature gate 'UseGardenerNodeAgent' is activated.") } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/actuator.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/actuator.go index 1ec5b5773..f2c7a1854 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/actuator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/actuator.go @@ -29,6 +29,8 @@ type Actuator interface { Reconcile(context.Context, logr.Logger, *extensionsv1alpha1.ControlPlane, *extensionscontroller.Cluster) (bool, error) // Delete deletes the ControlPlane. Delete(context.Context, logr.Logger, *extensionsv1alpha1.ControlPlane, *extensionscontroller.Cluster) error + // ForceDelete forcefully deletes the ControlPlane. + ForceDelete(context.Context, logr.Logger, *extensionsv1alpha1.ControlPlane, *extensionscontroller.Cluster) error // Restore restores the ControlPlane. Restore(context.Context, logr.Logger, *extensionsv1alpha1.ControlPlane, *extensionscontroller.Cluster) (bool, error) // Migrate migrates the ControlPlane. diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/genericactuator/actuator.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/genericactuator/actuator.go index 3593000e0..bc6bc54b3 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/genericactuator/actuator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/genericactuator/actuator.go @@ -35,6 +35,7 @@ import ( extensionsshootwebhook "github.com/gardener/gardener/extensions/pkg/webhook/shoot" gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" + v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" kubernetesclient "github.com/gardener/gardener/pkg/client/kubernetes" "github.com/gardener/gardener/pkg/utils/chart" @@ -76,8 +77,10 @@ func NewActuator( configName string, atomicShootWebhookConfig *atomic.Value, webhookServerNamespace string, - webhookServerPort int, -) (controlplane.Actuator, error) { +) ( + controlplane.Actuator, + error, +) { gardenerClientset, err := kubernetesclient.NewWithConfig(kubernetesclient.WithRESTConfig(mgr.GetConfig())) if err != nil { return nil, err @@ -104,7 +107,6 @@ func NewActuator( configName: configName, atomicShootWebhookConfig: atomicShootWebhookConfig, webhookServerNamespace: webhookServerNamespace, - webhookServerPort: webhookServerPort, gardenerClientset: gardenerClientset, client: mgr.GetClient(), @@ -137,7 +139,6 @@ type actuator struct { configName string atomicShootWebhookConfig *atomic.Value webhookServerNamespace string - webhookServerPort int gardenerClientset kubernetesclient.Interface client client.Client @@ -248,7 +249,7 @@ func (a *actuator) reconcileControlPlane( return false, fmt.Errorf("expected *admissionregistrationv1.MutatingWebhookConfiguration, got %T", value) } - if err := extensionsshootwebhook.ReconcileWebhookConfig(ctx, a.client, cp.Namespace, a.webhookServerNamespace, a.providerName, ShootWebhooksResourceName, a.webhookServerPort, webhookConfig, cluster); err != nil { + if err := extensionsshootwebhook.ReconcileWebhookConfig(ctx, a.client, cp.Namespace, a.webhookServerNamespace, a.providerName, ShootWebhooksResourceName, webhookConfig, cluster); err != nil { return false, fmt.Errorf("could not reconcile shoot webhooks: %w", err) } } @@ -404,6 +405,16 @@ func (a *actuator) Delete( return sm.Cleanup(ctx) } +// ForceDelete forcefully deletes the controlplane. +func (a *actuator) ForceDelete( + ctx context.Context, + log logr.Logger, + cp *extensionsv1alpha1.ControlPlane, + cluster *extensionscontroller.Cluster, +) error { + return a.Delete(ctx, log, cp, cluster) +} + func (a *actuator) delete(ctx context.Context, log logr.Logger, cp *extensionsv1alpha1.ControlPlane, cluster *extensionscontroller.Cluster) error { if cp.Spec.Purpose != nil && *cp.Spec.Purpose == extensionsv1alpha1.Exposure { return a.deleteControlPlaneExposure(ctx, log, cp) @@ -446,6 +457,8 @@ func (a *actuator) deleteControlPlane( cp *extensionsv1alpha1.ControlPlane, cluster *extensionscontroller.Cluster, ) error { + forceDelete := cluster != nil && v1beta1helper.ShootNeedsForceDeletion(cluster.Shoot) + // Get config chart values if a.configChart != nil { values, err := a.vp.GetConfigChartValues(ctx, cp, cluster) @@ -469,27 +482,31 @@ func (a *actuator) deleteControlPlane( return fmt.Errorf("could not delete managed resource containing shoot CRDs chart for controlplane '%s': %w", kubernetesutils.ObjectName(cp), err) } - // Wait for shoot CRDs chart ManagedResource deletion before deleting the shoot chart ManagedResource - timeoutCtx1, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := managedresources.WaitUntilDeleted(timeoutCtx1, a.client, cp.Namespace, ControlPlaneShootCRDsChartResourceName); err != nil { - return fmt.Errorf("error while waiting for managed resource containing shoot CRDs chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + if !forceDelete { + // Wait for shoot CRDs chart ManagedResource deletion before deleting the shoot chart ManagedResource + timeoutCtx1, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + if err := managedresources.WaitUntilDeleted(timeoutCtx1, a.client, cp.Namespace, ControlPlaneShootCRDsChartResourceName); err != nil { + return fmt.Errorf("error while waiting for managed resource containing shoot CRDs chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + } } } if err := managedresources.Delete(ctx, a.client, cp.Namespace, ControlPlaneShootChartResourceName, false); err != nil { return fmt.Errorf("could not delete managed resource containing shoot chart for controlplane '%s': %w", kubernetesutils.ObjectName(cp), err) } - timeoutCtx2, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := managedresources.WaitUntilDeleted(timeoutCtx2, a.client, cp.Namespace, StorageClassesChartResourceName); err != nil { - return fmt.Errorf("error while waiting for managed resource containing storage classes chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) - } + if !forceDelete { + timeoutCtx2, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + if err := managedresources.WaitUntilDeleted(timeoutCtx2, a.client, cp.Namespace, StorageClassesChartResourceName); err != nil { + return fmt.Errorf("error while waiting for managed resource containing storage classes chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + } - timeoutCtx3, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := managedresources.WaitUntilDeleted(timeoutCtx3, a.client, cp.Namespace, ControlPlaneShootChartResourceName); err != nil { - return fmt.Errorf("error while waiting for managed resource containing shoot chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + timeoutCtx3, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + if err := managedresources.WaitUntilDeleted(timeoutCtx3, a.client, cp.Namespace, ControlPlaneShootChartResourceName); err != nil { + return fmt.Errorf("error while waiting for managed resource containing shoot chart for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + } } // Delete control plane objects @@ -517,19 +534,16 @@ func (a *actuator) deleteControlPlane( } if a.atomicShootWebhookConfig != nil { - networkPolicy := extensionsshootwebhook.GetNetworkPolicyMeta(cp.Namespace, a.providerName) - if err := a.client.Delete(ctx, networkPolicy); client.IgnoreNotFound(err) != nil { - return fmt.Errorf("could not delete network policy for shoot webhooks in namespace '%s': %w", cp.Namespace, err) - } - if err := managedresources.Delete(ctx, a.client, cp.Namespace, ShootWebhooksResourceName, false); err != nil { return fmt.Errorf("could not delete managed resource containing shoot webhooks for controlplane '%s': %w", kubernetesutils.ObjectName(cp), err) } - timeoutCtx4, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := managedresources.WaitUntilDeleted(timeoutCtx4, a.client, cp.Namespace, ShootWebhooksResourceName); err != nil { - return fmt.Errorf("error while waiting for managed resource containing shoot webhooks for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + if !forceDelete { + timeoutCtx4, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + if err := managedresources.WaitUntilDeleted(timeoutCtx4, a.client, cp.Namespace, ShootWebhooksResourceName); err != nil { + return fmt.Errorf("error while waiting for managed resource containing shoot webhooks for controlplane '%s' to be deleted: %w", kubernetesutils.ObjectName(cp), err) + } } } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/reconciler.go index 6b6aae01f..8c9ef3085 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/controlplane/reconciler.go @@ -234,7 +234,13 @@ func (r *reconciler) delete( } log.Info("Starting the deletion of ControlPlane") - if err := r.actuator.Delete(ctx, log, cp, cluster); err != nil { + var err error + if cluster != nil && v1beta1helper.ShootNeedsForceDeletion(cluster.Shoot) { + err = r.actuator.ForceDelete(ctx, log, cp, cluster) + } else { + err = r.actuator.Delete(ctx, log, cp, cluster) + } + if err != nil { _ = r.statusUpdater.Error(ctx, log, cp, reconcilerutils.ReconcileErrCauseOrErr(err), operationType, "Error deleting ControlPlane") return reconcilerutils.ReconcileErr(err) } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/reconciler.go index 9aaf7420d..855b94242 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/reconciler.go @@ -176,7 +176,7 @@ func (r *reconciler) performHealthCheck(ctx context.Context, log logr.Logger, re if healthCheckResult.Status == gardencorev1beta1.ConditionTrue { logger.Info("Health check for extension resource successful", "kind", r.registeredExtension.groupVersionKind.Kind, "conditionType", healthCheckResult.HealthConditionType) - conditions = append(conditions, extensionConditionSuccessful(conditionBuilder, healthCheckResult.HealthConditionType, healthCheckResult)) + conditions = append(conditions, extensionConditionSuccessful(conditionBuilder, healthCheckResult.HealthConditionType)) continue } @@ -250,7 +250,7 @@ func extensionConditionUnsuccessful(conditionBuilder v1beta1helper.ConditionBuil } } -func extensionConditionSuccessful(conditionBuilder v1beta1helper.ConditionBuilder, healthConditionType string, healthCheckResult Result) condition { +func extensionConditionSuccessful(conditionBuilder v1beta1helper.ConditionBuilder, healthConditionType string) condition { conditionBuilder. WithStatus(gardencorev1beta1.ConditionTrue). WithReason(ReasonSuccessful). diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/helpers.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/helpers.go index 391374b25..30c7c983f 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/helpers.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/helpers.go @@ -18,10 +18,7 @@ import ( "fmt" machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" "github.com/gardener/gardener/pkg/utils/kubernetes/health" ) @@ -39,79 +36,6 @@ func checkMachineDeploymentsHealthy(machineDeployments []machinev1alpha1.Machine return true, nil } -func checkNodesScalingUp(machineList *machinev1alpha1.MachineList, readyNodes, desiredMachines int) (gardencorev1beta1.ConditionStatus, error) { - if readyNodes == desiredMachines { - return gardencorev1beta1.ConditionTrue, nil - } - - if machineObjects := len(machineList.Items); machineObjects < desiredMachines { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("not enough machine objects created yet (%d/%d)", machineObjects, desiredMachines) - } - - var pendingMachines, erroneousMachines int - for _, machine := range machineList.Items { - switch machine.Status.CurrentStatus.Phase { - case machinev1alpha1.MachineRunning, machinev1alpha1.MachineAvailable: - // machine is already running fine - continue - case machinev1alpha1.MachinePending, "": // https://github.com/gardener/machine-controller-manager/issues/466 - // machine is in the process of being created - pendingMachines++ - default: - // undesired machine phase - erroneousMachines++ - } - } - - if erroneousMachines > 0 { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("%s erroneous", cosmeticMachineMessage(erroneousMachines)) - } - if pendingMachines == 0 { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("not enough ready worker nodes registered in the cluster (%d/%d)", readyNodes, desiredMachines) - } - - return gardencorev1beta1.ConditionProgressing, fmt.Errorf("%s provisioning and should join the cluster soon", cosmeticMachineMessage(pendingMachines)) -} - -func checkNodesScalingDown(machineList *machinev1alpha1.MachineList, nodeList *corev1.NodeList, registeredNodes, desiredMachines int) (gardencorev1beta1.ConditionStatus, error) { - if registeredNodes == desiredMachines { - return gardencorev1beta1.ConditionTrue, nil - } - - // Check if all nodes that are cordoned map to machines with a deletion timestamp. This might be the case during - // a rolling update. - nodeNameToMachine := map[string]machinev1alpha1.Machine{} - for _, machine := range machineList.Items { - if machine.Labels != nil && machine.Labels["node"] != "" { - nodeNameToMachine[machine.Labels["node"]] = machine - } - } - - var cordonedNodes int - for _, node := range nodeList.Items { - if metav1.HasAnnotation(node.ObjectMeta, AnnotationKeyNotManagedByMCM) && node.Annotations[AnnotationKeyNotManagedByMCM] == "1" { - continue - } - if node.Spec.Unschedulable { - machine, ok := nodeNameToMachine[node.Name] - if !ok { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("machine object for cordoned node %q not found", node.Name) - } - if machine.DeletionTimestamp == nil { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("cordoned node %q found but corresponding machine object does not have a deletion timestamp", node.Name) - } - cordonedNodes++ - } - } - - // If there are still more nodes than desired then report an error. - if registeredNodes-cordonedNodes != desiredMachines { - return gardencorev1beta1.ConditionFalse, fmt.Errorf("too many worker nodes are registered. Exceeding maximum desired machine count (%d/%d)", registeredNodes, desiredMachines) - } - - return gardencorev1beta1.ConditionProgressing, fmt.Errorf("%s waiting to be completely drained from pods. If this persists, check your pod disruption budgets and pending finalizers. Please note, that nodes that fail to be drained will be deleted automatically", cosmeticMachineMessage(cordonedNodes)) -} - func getDesiredMachineCount(machineDeployments []machinev1alpha1.MachineDeployment) int { desiredMachines := 0 for _, deployment := range machineDeployments { @@ -121,10 +45,3 @@ func getDesiredMachineCount(machineDeployments []machinev1alpha1.MachineDeployme } return desiredMachines } - -func cosmeticMachineMessage(numberOfMachines int) string { - if numberOfMachines == 1 { - return fmt.Sprintf("%d machine is", numberOfMachines) - } - return fmt.Sprintf("%d machines are", numberOfMachines) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/nodes.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/nodes.go index f32a63bf8..753cf5b59 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/nodes.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/healthcheck/worker/nodes.go @@ -148,13 +148,6 @@ func (h *DefaultHealthChecker) Check(ctx context.Context, request types.Namespac } } - // First check if the MachineDeployments report failed machines. If false then check if the MachineDeployments are - // "available". If false then check if there is a regular scale-up happening or if there are machines with an erroneous - // phase. Only then check the other MachineDeployment conditions. As last check, check if there is a scale-down happening - // (e.g., in case of an rolling-update). - - checkScaleUp := false - for _, deployment := range machineDeploymentList.Items { for _, failedMachine := range deployment.Status.FailedMachines { err := fmt.Errorf("machine %q failed: %s", failedMachine.Name, failedMachine.LastOperation.Description) @@ -164,25 +157,6 @@ func (h *DefaultHealthChecker) Check(ctx context.Context, request types.Namespac Detail: err.Error(), }, nil } - - for _, condition := range deployment.Status.Conditions { - if condition.Type == machinev1alpha1.MachineDeploymentAvailable && condition.Status != machinev1alpha1.ConditionTrue { - checkScaleUp = true - break - } - } - } - - if checkScaleUp { - // TODO(rfranzke): Remove this flag when the MachineControllerManagerDeployment feature gate is promoted to GA. - if status, err := checkNodesScalingUp(machineList, readyNodes, desiredMachines); status != gardencorev1beta1.ConditionTrue { - h.logger.Error(err, "Health check failed") - return &healthcheck.SingleCheckResult{ - Status: status, - Detail: err.Error(), - ProgressingThreshold: h.scaleUpProgressingThreshold, - }, nil - } } if isHealthy, err := checkMachineDeploymentsHealthy(machineDeploymentList.Items); !isHealthy { @@ -193,15 +167,5 @@ func (h *DefaultHealthChecker) Check(ctx context.Context, request types.Namespac }, nil } - // TODO(rfranzke): Remove this flag when the MachineControllerManagerDeployment feature gate is promoted to GA. - if status, err := checkNodesScalingDown(machineList, nodeList, registeredNodes, desiredMachines); status != gardencorev1beta1.ConditionTrue { - h.logger.Error(err, "Health check failed") - return &healthcheck.SingleCheckResult{ - Status: status, - Detail: err.Error(), - ProgressingThreshold: h.scaleDownProgressingThreshold, - }, nil - } - return &healthcheck.SingleCheckResult{Status: gardencorev1beta1.ConditionTrue}, nil } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/heartbeat/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/heartbeat/reconciler.go index 5c47d5606..e3ef8fca7 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/heartbeat/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/heartbeat/reconciler.go @@ -50,7 +50,7 @@ func NewReconciler(mgr manager.Manager, extensionName string, namespace string, } // Reconcile renews the heartbeat lease resource. -func (r *reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { +func (r *reconciler) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) { log := logf.FromContext(ctx) lease := &coordinationv1.Lease{ ObjectMeta: metav1.ObjectMeta{ diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/actuator.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/actuator.go index 4ab641549..7b8e2e12b 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/actuator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/actuator.go @@ -29,7 +29,9 @@ type Actuator interface { Reconcile(context.Context, logr.Logger, *extensionsv1alpha1.Infrastructure, *extensionscontroller.Cluster) error // Delete the Infrastructure config. Delete(context.Context, logr.Logger, *extensionsv1alpha1.Infrastructure, *extensionscontroller.Cluster) error - // Restore takes the state of the Infrastrucure resource and applies it to the terraform pod's output state + // ForceDelete forcefully deletes the Infrastructure config. + ForceDelete(context.Context, logr.Logger, *extensionsv1alpha1.Infrastructure, *extensionscontroller.Cluster) error + // Restore takes the state of the Infrastructure resource and applies it to the terraform pod's output state Restore(context.Context, logr.Logger, *extensionsv1alpha1.Infrastructure, *extensionscontroller.Cluster) error // Migrate deletes the terraform k8s resources without deleting the corresponding resources in the IaaS provider Migrate(context.Context, logr.Logger, *extensionsv1alpha1.Infrastructure, *extensionscontroller.Cluster) error diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/reconciler.go index 6c37fd887..f04a48ae3 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/infrastructure/reconciler.go @@ -156,7 +156,14 @@ func (r *reconciler) delete( return reconcile.Result{}, err } - if err := r.actuator.Delete(ctx, log, infrastructure, cluster); err != nil { + var err error + if cluster != nil && v1beta1helper.ShootNeedsForceDeletion(cluster.Shoot) { + err = r.actuator.ForceDelete(ctx, log, infrastructure, cluster) + } else { + err = r.actuator.Delete(ctx, log, infrastructure, cluster) + } + + if err != nil { _ = r.statusUpdater.Error(ctx, log, infrastructure, reconcilerutils.ReconcileErrCauseOrErr(err), gardencorev1beta1.LastOperationTypeDelete, "Error deleting Infrastructure") return reconcilerutils.ReconcileErr(err) } @@ -165,8 +172,7 @@ func (r *reconciler) delete( return reconcile.Result{}, err } - err := r.removeFinalizerFromInfrastructure(ctx, log, infrastructure) - return reconcile.Result{}, err + return reconcile.Result{}, r.removeFinalizerFromInfrastructure(ctx, log, infrastructure) } func (r *reconciler) migrate( diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/utils.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/utils.go index 9118bc155..7259dde54 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/utils.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/utils.go @@ -158,21 +158,3 @@ func ShouldSkipOperation(operationType gardencorev1beta1.LastOperationType, obj func GetObjectByReference(ctx context.Context, c client.Client, ref *autoscalingv1.CrossVersionObjectReference, namespace string, obj client.Object) error { return c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: v1beta1constants.ReferencedResourcesPrefix + ref.Name}, obj) } - -// UseTokenRequestor returns true when the provided Gardener version is large enough for supporting acquiring tokens -// for shoot cluster control plane components running in the seed based on the TokenRequestor controller of -// gardener-resource-manager (https://github.com/gardener/gardener/blob/master/docs/concepts/resource-manager.md#tokenrequestor). -// Deprecated: new extension versions need to require at least Gardener version v1.36 and use the token requestor by -// default which makes this function obsolete. -func UseTokenRequestor(gardenerVersion string) (bool, error) { - return true, nil -} - -// UseServiceAccountTokenVolumeProjection returns true when the provided Gardener version is large enough for supporting -// automatic token volume projection for components running in the seed and shoot clusters based on the respective -// webhook part of gardener-resource-manager (https://github.com/gardener/gardener/blob/master/docs/concepts/resource-manager.md#auto-mounting-projected-serviceaccount-tokens). -// Deprecated: new extension versions need to require at least Gardener version v1.37 and use projected service account -// token volumes by default which makes this function obsolete. -func UseServiceAccountTokenVolumeProjection(gardenerVersion string) (bool, error) { - return true, nil -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/actuator.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/actuator.go index 14bf7c530..68a0b647c 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/actuator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/actuator.go @@ -29,6 +29,8 @@ type Actuator interface { Reconcile(context.Context, logr.Logger, *extensionsv1alpha1.Worker, *extensionscontroller.Cluster) error // Delete deletes the Worker. Delete(context.Context, logr.Logger, *extensionsv1alpha1.Worker, *extensionscontroller.Cluster) error + // ForceDelete forcefully deletes the Worker. + ForceDelete(context.Context, logr.Logger, *extensionsv1alpha1.Worker, *extensionscontroller.Cluster) error // Restore reads from the worker.status.state field and deploys the machines and machineSet Restore(context.Context, logr.Logger, *extensionsv1alpha1.Worker, *extensionscontroller.Cluster) error // Migrate deletes the MCM, machineDeployments, machineClasses, machineClassSecrets, diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/controller.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/controller.go index a91396958..82b706466 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/controller.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/controller.go @@ -17,7 +17,6 @@ package worker import ( "context" - machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -34,8 +33,6 @@ const ( FinalizerName = "extensions.gardener.cloud/worker" // ControllerName is the name of the controller. ControllerName = "worker" - // ControllerNameState is the name of the controller responsible for updating the worker's state. - ControllerNameState = "worker-state" ) // AddArgs are arguments for adding an worker controller to a manager. @@ -68,15 +65,7 @@ func Add(ctx context.Context, mgr manager.Manager, args AddArgs) error { args.ControllerOptions.Reconciler = NewReconciler(mgr, args.Actuator) predicates := extensionspredicate.AddTypePredicate(args.Predicates, args.Type) - if err := add(ctx, mgr, args, predicates); err != nil { - return err - } - - return addStateUpdatingController(ctx, mgr, args.ControllerOptions, args.Type) -} -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func add(ctx context.Context, mgr manager.Manager, args AddArgs, predicates []predicate.Predicate) error { ctrl, err := controller.New(ControllerName, mgr, args.ControllerOptions) if err != nil { return err @@ -93,40 +82,3 @@ func add(ctx context.Context, mgr manager.Manager, args AddArgs, predicates []pr return ctrl.Watch(source.Kind(mgr.GetCache(), &extensionsv1alpha1.Worker{}), &handler.EnqueueRequestForObject{}, predicates...) } - -func addStateUpdatingController(ctx context.Context, mgr manager.Manager, options controller.Options, extensionType string) error { - var ( - machinePredicates = []predicate.Predicate{ - predicate.Or( - MachineNodeInfoHasChanged(), - predicate.GenerationChangedPredicate{}, - ), - } - workerPredicates = []predicate.Predicate{ - extensionspredicate.HasType(extensionType), - WorkerStateUpdateIsNotSkipped(), - } - ) - - ctrl, err := controller.New(ControllerNameState, mgr, controller.Options{ - MaxConcurrentReconciles: options.MaxConcurrentReconciles, - Reconciler: NewStateReconciler(mgr), - }) - if err != nil { - return err - } - - if err := ctrl.Watch( - source.Kind(mgr.GetCache(), &machinev1alpha1.MachineSet{}), - mapper.EnqueueRequestsFrom(ctx, mgr.GetCache(), MachineSetToWorkerMapper(workerPredicates), mapper.UpdateWithNew, ctrl.GetLogger()), - machinePredicates..., - ); err != nil { - return err - } - - return ctrl.Watch( - source.Kind(mgr.GetCache(), &machinev1alpha1.Machine{}), - mapper.EnqueueRequestsFrom(ctx, mgr.GetCache(), MachineToWorkerMapper(workerPredicates), mapper.UpdateWithNew, ctrl.GetLogger()), - machinePredicates..., - ) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator.go index c17ca402a..10c347027 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator.go @@ -17,95 +17,56 @@ package genericactuator import ( "context" "fmt" - "strings" "time" machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/cluster" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/manager" - extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" "github.com/gardener/gardener/extensions/pkg/controller/healthcheck" "github.com/gardener/gardener/extensions/pkg/controller/worker" extensionsworkerhelper "github.com/gardener/gardener/extensions/pkg/controller/worker/helper" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" - kubernetesclient "github.com/gardener/gardener/pkg/client/kubernetes" - "github.com/gardener/gardener/pkg/controllerutils" - "github.com/gardener/gardener/pkg/utils/chart" - "github.com/gardener/gardener/pkg/utils/imagevector" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" + gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" ) -// GardenPurposeMachineClass is a constant for the 'machineclass' value in a label. -const GardenPurposeMachineClass = "machineclass" - type genericActuator struct { - delegateFactory DelegateFactory - mcmManaged bool - mcmName string - mcmSeedChart chart.Interface - mcmShootChart chart.Interface - imageVector imagevector.ImageVector - - client client.Client - reader client.Reader - scheme *runtime.Scheme - gardenerClientset kubernetesclient.Interface - chartApplier kubernetesclient.ChartApplier - chartRendererFactory extensionscontroller.ChartRendererFactory - errorCodeCheckFunc healthcheck.ErrorCodeCheckFunc + delegateFactory DelegateFactory + gardenReader client.Reader + seedClient client.Client + seedReader client.Reader + scheme *runtime.Scheme + errorCodeCheckFunc healthcheck.ErrorCodeCheckFunc } // NewActuator creates a new Actuator that reconciles // Worker resources of Gardener's `extensions.gardener.cloud` API group. // It provides a default implementation that allows easier integration of providers. // If machine-controller-manager should not be managed then only the delegateFactory must be provided. -func NewActuator( - mgr manager.Manager, - delegateFactory DelegateFactory, - mcmName string, - mcmSeedChart, - mcmShootChart chart.Interface, - imageVector imagevector.ImageVector, - chartRendererFactory extensionscontroller.ChartRendererFactory, - errorCodeCheckFunc healthcheck.ErrorCodeCheckFunc, -) (worker.Actuator, error) { - gardenerClientset, err := kubernetesclient.NewWithConfig(kubernetesclient.WithRESTConfig(mgr.GetConfig())) - if err != nil { - return nil, err - } - +func NewActuator(mgr manager.Manager, gardenCluster cluster.Cluster, delegateFactory DelegateFactory, errorCodeCheckFunc healthcheck.ErrorCodeCheckFunc) worker.Actuator { return &genericActuator{ - delegateFactory: delegateFactory, - mcmManaged: mcmName != "" && mcmSeedChart != nil && mcmShootChart != nil && imageVector != nil && chartRendererFactory != nil, - mcmName: mcmName, - mcmSeedChart: mcmSeedChart, - mcmShootChart: mcmShootChart, - imageVector: imageVector, - client: mgr.GetClient(), - reader: mgr.GetAPIReader(), - scheme: mgr.GetScheme(), - gardenerClientset: gardenerClientset, - chartApplier: gardenerClientset.ChartApplier(), - chartRendererFactory: chartRendererFactory, - errorCodeCheckFunc: errorCodeCheckFunc, - }, nil + delegateFactory: delegateFactory, + gardenReader: gardenCluster.GetAPIReader(), + seedClient: mgr.GetClient(), + seedReader: mgr.GetAPIReader(), + scheme: mgr.GetScheme(), + errorCodeCheckFunc: errorCodeCheckFunc, + } } func (a *genericActuator) cleanupMachineDeployments(ctx context.Context, logger logr.Logger, existingMachineDeployments *machinev1alpha1.MachineDeploymentList, wantedMachineDeployments worker.MachineDeployments) error { logger.Info("Cleaning up machine deployments") for _, existingMachineDeployment := range existingMachineDeployments.Items { if !wantedMachineDeployments.HasDeployment(existingMachineDeployment.Name) { - if err := a.client.Delete(ctx, &existingMachineDeployment); err != nil { + if err := a.seedClient.Delete(ctx, &existingMachineDeployment); err != nil { return err } } @@ -113,8 +74,9 @@ func (a *genericActuator) cleanupMachineDeployments(ctx context.Context, logger return nil } -func (a *genericActuator) listMachineClassNames(ctx context.Context, namespace string, machineClassList client.ObjectList) (sets.Set[string], error) { - if err := a.client.List(ctx, machineClassList, client.InNamespace(namespace)); err != nil { +func (a *genericActuator) listMachineClassNames(ctx context.Context, namespace string) (sets.Set[string], error) { + machineClassList := &machinev1alpha1.MachineClassList{} + if err := a.seedClient.List(ctx, machineClassList, client.InNamespace(namespace)); err != nil { return nil, err } @@ -135,9 +97,10 @@ func (a *genericActuator) listMachineClassNames(ctx context.Context, namespace s return classNames, nil } -func (a *genericActuator) cleanupMachineClasses(ctx context.Context, logger logr.Logger, namespace string, machineClassList client.ObjectList, wantedMachineDeployments worker.MachineDeployments) error { +func (a *genericActuator) cleanupMachineClasses(ctx context.Context, logger logr.Logger, namespace string, wantedMachineDeployments worker.MachineDeployments) error { logger.Info("Cleaning up machine classes") - if err := a.client.List(ctx, machineClassList, client.InNamespace(namespace)); err != nil { + machineClassList := &machinev1alpha1.MachineClassList{} + if err := a.seedClient.List(ctx, machineClassList, client.InNamespace(namespace)); err != nil { return err } @@ -145,7 +108,7 @@ func (a *genericActuator) cleanupMachineClasses(ctx context.Context, logger logr machineClass := obj.(client.Object) if !wantedMachineDeployments.HasClass(machineClass.GetName()) { logger.Info("Deleting machine class", "machineClass", machineClass) - if err := a.client.Delete(ctx, machineClass); err != nil { + if err := a.seedClient.Delete(ctx, machineClass); err != nil { return err } } @@ -155,12 +118,12 @@ func (a *genericActuator) cleanupMachineClasses(ctx context.Context, logger logr } func getMachineClassSecretLabels() map[string]string { - return map[string]string{v1beta1constants.GardenerPurpose: GardenPurposeMachineClass} + return map[string]string{v1beta1constants.GardenerPurpose: v1beta1constants.GardenPurposeMachineClass} } func (a *genericActuator) listMachineClassSecrets(ctx context.Context, namespace string) (*corev1.SecretList, error) { secretList := &corev1.SecretList{} - if err := a.client.List(ctx, secretList, client.InNamespace(namespace), client.MatchingLabels(getMachineClassSecretLabels())); err != nil { + if err := a.seedClient.List(ctx, secretList, client.InNamespace(namespace), client.MatchingLabels(getMachineClassSecretLabels())); err != nil { return nil, err } @@ -179,7 +142,7 @@ func (a *genericActuator) cleanupMachineClassSecrets(ctx context.Context, logger // Cleanup all secrets which were used for machine classes that do not exist anymore. for _, secret := range secretList.Items { if !wantedMachineDeployments.HasSecret(secret.Name) { - if err := a.client.Delete(ctx, &secret); err != nil { + if err := a.seedClient.Delete(ctx, &secret); err != nil { return err } } @@ -188,73 +151,18 @@ func (a *genericActuator) cleanupMachineClassSecrets(ctx context.Context, logger return nil } -// shallowDeleteMachineClassSecrets deletes all unused machine class secrets (i.e., those which are not part -// of the provided list ) without waiting for MCM to do this. -func (a *genericActuator) shallowDeleteMachineClassSecrets(ctx context.Context, log logr.Logger, namespace string, wantedMachineDeployments worker.MachineDeployments) error { - log.Info("Shallow deleting machine class secrets") - secretList, err := a.listMachineClassSecrets(ctx, namespace) - if err != nil { - return err - } - // Delete the finalizers to all secrets which were used for machine classes that do not exist anymore. - for _, secret := range secretList.Items { - if !wantedMachineDeployments.HasSecret(secret.Name) { - log.Info("Removing all finalizers from machine class secret", "secret", client.ObjectKeyFromObject(&secret)) - if err := controllerutils.RemoveAllFinalizers(ctx, a.client, &secret); err != nil { - return fmt.Errorf("error removing all finalizers from machine class secret: %s/%s: %w", secret.Namespace, secret.Name, err) - } - if err := a.client.Delete(ctx, &secret); err != nil { - return err - } - } - } - - return nil -} - -// removeFinalizerFromWorkerSecretRef removes the MCM finalizers from the secret that is referenced by the worker -func (a *genericActuator) removeFinalizerFromWorkerSecretRef(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker) error { - secret, err := kubernetesutils.GetSecretByReference(ctx, a.client, &worker.Spec.SecretRef) - if err != nil { - if apierrors.IsNotFound(err) { - return nil - } - return err - } - - finalizersToRemove := []string{} - if controllerutil.ContainsFinalizer(secret, mcmFinalizer) { - finalizersToRemove = append(finalizersToRemove, mcmFinalizer) - } - if controllerutil.ContainsFinalizer(secret, mcmProviderFinalizer) { - finalizersToRemove = append(finalizersToRemove, mcmProviderFinalizer) - } - if len(finalizersToRemove) == 0 { - return nil - } - - if len(finalizersToRemove) > 0 { - log.Info("Removing finalizers from secret", "secret", client.ObjectKeyFromObject(secret)) - if err := controllerutils.RemoveFinalizers(ctx, a.client, secret, finalizersToRemove...); err != nil { - return fmt.Errorf("failed to remove finalizer from secret: %w", err) - } - } - - return nil -} - // cleanupMachineSets deletes MachineSets having number of desired and actual replicas equaling 0 func (a *genericActuator) cleanupMachineSets(ctx context.Context, logger logr.Logger, namespace string) error { logger.Info("Cleaning up machine sets") machineSetList := &machinev1alpha1.MachineSetList{} - if err := a.client.List(ctx, machineSetList, client.InNamespace(namespace)); err != nil { + if err := a.seedClient.List(ctx, machineSetList, client.InNamespace(namespace)); err != nil { return err } for _, machineSet := range machineSetList.Items { if machineSet.Spec.Replicas == 0 && machineSet.Status.Replicas == 0 { logger.Info("Deleting MachineSet as the number of desired and actual replicas is 0", "machineSet", &machineSet) - if err := a.client.Delete(ctx, machineSet.DeepCopy()); client.IgnoreNotFound(err) != nil { + if err := a.seedClient.Delete(ctx, machineSet.DeepCopy()); client.IgnoreNotFound(err) != nil { return err } } @@ -262,44 +170,15 @@ func (a *genericActuator) cleanupMachineSets(ctx context.Context, logger logr.Lo return nil } -func (a *genericActuator) shallowDeleteAllObjects(ctx context.Context, log logr.Logger, namespace string, objectList client.ObjectList) error { - var objectKind interface{} = strings.TrimSuffix(fmt.Sprintf("%T", objectList), "List") - if gvk, err := apiutil.GVKForObject(objectList, a.scheme); err == nil { - objectKind = gvk - } - - log = log.WithValues("kind", objectKind) - log.Info("Shallow deleting all objects of kind") - - if err := a.client.List(ctx, objectList, client.InNamespace(namespace)); err != nil { - return err - } - - return meta.EachListItem(objectList, func(obj runtime.Object) error { - object := obj.(client.Object) - if err := controllerutils.RemoveAllFinalizers(ctx, a.client, object); err != nil { - return err - } - log.Info("Removing all finalizers from object", "object", client.ObjectKeyFromObject(object)) - if err := controllerutils.RemoveAllFinalizers(ctx, a.client, object); err != nil { - return fmt.Errorf("error removing all finalizers from object: %s/%s: %w", object.GetNamespace(), object.GetName(), err) - } - if err := a.client.Delete(ctx, object); client.IgnoreNotFound(err) != nil { - return err - } - return nil - }) -} - // IsMachineControllerStuck determines if the machine controller pod is stuck. func (a *genericActuator) IsMachineControllerStuck(ctx context.Context, worker *extensionsv1alpha1.Worker) (bool, *string, error) { machineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := a.client.List(ctx, machineDeployments, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, machineDeployments, client.InNamespace(worker.Namespace)); err != nil { return false, nil, err } machineSets := &machinev1alpha1.MachineSetList{} - if err := a.client.List(ctx, machineSets, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, machineSets, client.InNamespace(worker.Namespace)); err != nil { return false, nil, err } @@ -325,7 +204,7 @@ const ( // - the machine set does not have a status that indicates (attempted) machine creation func isMachineControllerStuck(machineSets []machinev1alpha1.MachineSet, machineDeployments []machinev1alpha1.MachineDeployment) (bool, *string) { // map the owner reference to the existing machine sets - ownerReferenceToMachineSet := extensionsworkerhelper.BuildOwnerToMachineSetsMap(machineSets) + ownerReferenceToMachineSet := gardenerutils.BuildOwnerToMachineSetsMap(machineSets) for _, machineDeployment := range machineDeployments { if !controllerutil.ContainsFinalizer(&machineDeployment, mcmFinalizer) { diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_delete.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_delete.go index f13d996d6..3dccacde6 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_delete.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_delete.go @@ -18,13 +18,11 @@ import ( "context" "errors" "fmt" - "strings" "time" machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/meta" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -32,6 +30,7 @@ import ( v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/utils/flow" + gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" retryutils "github.com/gardener/gardener/pkg/utils/retry" ) @@ -54,13 +53,8 @@ func (a *genericActuator) Delete(ctx context.Context, log logr.Logger, worker *e return fmt.Errorf("pre worker deletion hook failed: %w", err) } - // Make sure machine-controller-manager is awake before deleting the machines. - var replicaFunc = func() int32 { - return 1 - } - - // Deploy the machine-controller-manager into the cluster to make sure worker nodes can be removed. - if err := a.deployMachineControllerManager(ctx, log, worker, cluster, workerDelegate, replicaFunc); err != nil { + // Cleanup legacy machine-controller-manager resources. + if err := a.cleanupLegacyMachineControllerManagerResources(ctx, log, worker); err != nil { return err } @@ -72,36 +66,36 @@ func (a *genericActuator) Delete(ctx context.Context, log logr.Logger, worker *e // Wait until the machine class credentials secret has been acquired. log.Info("Waiting until the machine class credentials secret has been acquired") - if err := a.waitUntilCredentialsSecretAcquiredOrReleased(ctx, true, worker, workerDelegate); err != nil { + if err := a.waitUntilCredentialsSecretAcquiredOrReleased(ctx, true, worker); err != nil { return fmt.Errorf("failed while waiting for the machine class credentials secret to be acquired: %w", err) } // Mark all existing machines to become forcefully deleted. log.Info("Marking all machines to become forcefully deleted") - if err := markAllMachinesForcefulDeletion(ctx, log, a.client, worker.Namespace); err != nil { + if err := markAllMachinesForcefulDeletion(ctx, log, a.seedClient, worker.Namespace); err != nil { return fmt.Errorf("marking all machines for forceful deletion failed: %w", err) } // Delete all machine deployments. log.Info("Deleting all machine deployments") - if err := a.client.DeleteAllOf(ctx, &machinev1alpha1.MachineDeployment{}, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.DeleteAllOf(ctx, &machinev1alpha1.MachineDeployment{}, client.InNamespace(worker.Namespace)); err != nil { return fmt.Errorf("cleaning up all machine deployments failed: %w", err) } // Delete all machine classes. log.Info("Deleting all machine classes") - if err := a.client.DeleteAllOf(ctx, workerDelegate.MachineClass(), client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.DeleteAllOf(ctx, &machinev1alpha1.MachineClass{}, client.InNamespace(worker.Namespace)); err != nil { return fmt.Errorf("cleaning up all machine classes failed: %w", err) } // Delete all machine class secrets. log.Info("Deleting all machine class secrets") - if err := a.client.DeleteAllOf(ctx, &corev1.Secret{}, client.InNamespace(worker.Namespace), client.MatchingLabels(getMachineClassSecretLabels())); err != nil { + if err := a.seedClient.DeleteAllOf(ctx, &corev1.Secret{}, client.InNamespace(worker.Namespace), client.MatchingLabels(getMachineClassSecretLabels())); err != nil { return fmt.Errorf("cleaning up all machine class secrets failed: %w", err) } // Wait until all machine resources have been properly deleted. - if err := a.waitUntilMachineResourcesDeleted(ctx, log, worker, workerDelegate); err != nil { + if err := gardenerutils.WaitUntilMachineResourcesDeleted(ctx, log, a.seedClient, worker.Namespace); err != nil { newError := fmt.Errorf("failed while waiting for all machine resources to be deleted: %w", err) if a.errorCodeCheckFunc != nil { return v1beta1helper.NewErrorWithCodes(newError, a.errorCodeCheckFunc(err)...) @@ -111,15 +105,10 @@ func (a *genericActuator) Delete(ctx context.Context, log logr.Logger, worker *e // Wait until the machine class credentials secret has been released. log.Info("Waiting until the machine class credentials secret has been released") - if err := a.waitUntilCredentialsSecretAcquiredOrReleased(ctx, false, worker, workerDelegate); err != nil { + if err := a.waitUntilCredentialsSecretAcquiredOrReleased(ctx, false, worker); err != nil { return fmt.Errorf("failed while waiting for the machine class credentials secret to be released: %w", err) } - // Delete the machine-controller-manager. - if err := a.deleteMachineControllerManager(ctx, log, worker); err != nil { - return fmt.Errorf("failed deleting machine-controller-manager: %w", err) - } - // Call post deletion hook after Worker deletion has happened. if err := workerDelegate.PostDeleteHook(ctx); err != nil { return fmt.Errorf("post worker deletion hook failed: %w", err) @@ -128,6 +117,12 @@ func (a *genericActuator) Delete(ctx context.Context, log logr.Logger, worker *e return nil } +// ForceDelete simply returns nil in case of forceful deletion since cleaning up the machines would never succeed in this case. +// So we proceed to remove the finalizer without any action. +func (a *genericActuator) ForceDelete(_ context.Context, _ logr.Logger, _ *extensionsv1alpha1.Worker, _ *extensionscontroller.Cluster) error { + return nil +} + // Mark all existing machines to become forcefully deleted. func markAllMachinesForcefulDeletion(ctx context.Context, log logr.Logger, cl client.Client, namespace string) error { log.Info("Marking all machines for forceful deletion") @@ -166,106 +161,12 @@ func markMachineForcefulDeletion(ctx context.Context, cl client.Client, machine return cl.Update(ctx, machine) } -// waitUntilMachineResourcesDeleted waits for a maximum of 30 minutes until all machine resources have been properly -// deleted by the machine-controller-manager. It polls the status every 5 seconds. -// TODO: Parallelise this? -func (a *genericActuator) waitUntilMachineResourcesDeleted(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, workerDelegate WorkerDelegate) error { - var ( - countMachines = -1 - countMachineSets = -1 - countMachineDeployments = -1 - countMachineClasses = -1 - countMachineClassSecrets = -1 - ) - log.Info("Waiting until all machine resources have been deleted") - - return retryutils.UntilTimeout(ctx, 5*time.Second, 5*time.Minute, func(ctx context.Context) (bool, error) { - msg := "" - - // Check whether all machines have been deleted. - if countMachines != 0 { - existingMachines := &machinev1alpha1.MachineList{} - if err := a.reader.List(ctx, existingMachines, client.InNamespace(worker.Namespace)); err != nil { - return retryutils.SevereError(err) - } - countMachines = len(existingMachines.Items) - msg += fmt.Sprintf("%d machines, ", countMachines) - } - - // Check whether all machine sets have been deleted. - if countMachineSets != 0 { - existingMachineSets := &machinev1alpha1.MachineSetList{} - if err := a.reader.List(ctx, existingMachineSets, client.InNamespace(worker.Namespace)); err != nil { - return retryutils.SevereError(err) - } - countMachineSets = len(existingMachineSets.Items) - msg += fmt.Sprintf("%d machine sets, ", countMachineSets) - } - - // Check whether all machine deployments have been deleted. - if countMachineDeployments != 0 { - existingMachineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := a.reader.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { - return retryutils.SevereError(err) - } - countMachineDeployments = len(existingMachineDeployments.Items) - msg += fmt.Sprintf("%d machine deployments, ", countMachineDeployments) - - // Check whether an operation failed during the deletion process. - for _, existingMachineDeployment := range existingMachineDeployments.Items { - for _, failedMachine := range existingMachineDeployment.Status.FailedMachines { - return retryutils.SevereError(fmt.Errorf("machine %s failed: %s", failedMachine.Name, failedMachine.LastOperation.Description)) - } - } - } - - // Check whether all machine classes have been deleted. - if countMachineClasses != 0 { - machineClassList := workerDelegate.MachineClassList() - if err := a.reader.List(ctx, machineClassList, client.InNamespace(worker.Namespace)); err != nil { - return retryutils.SevereError(err) - } - machineClasses, err := meta.ExtractList(machineClassList) - if err != nil { - return retryutils.SevereError(err) - } - countMachineClasses = len(machineClasses) - msg += fmt.Sprintf("%d machine classes, ", countMachineClasses) - } - - // Check whether all machine class secrets have been deleted. - if countMachineClassSecrets != 0 { - count := 0 - existingMachineClassSecrets, err := a.listMachineClassSecrets(ctx, worker.Namespace) - if err != nil { - return retryutils.SevereError(err) - } - for _, machineClassSecret := range existingMachineClassSecrets.Items { - if len(machineClassSecret.Finalizers) != 0 { - count++ - } - } - countMachineClassSecrets = count - msg += fmt.Sprintf("%d machine class secrets, ", countMachineClassSecrets) - } - - if countMachines != 0 || countMachineSets != 0 || countMachineDeployments != 0 || countMachineClasses != 0 || countMachineClassSecrets != 0 { - log.Info("Waiting until machine resources have been deleted", - "machines", countMachines, "machineSets", countMachineSets, "machineDeployments", countMachineDeployments, - "machineClasses", countMachineClasses, "machineClassSecrets", countMachineClassSecrets) - return retryutils.MinorError(fmt.Errorf("waiting until the following machine resources have been deleted: %s", strings.TrimSuffix(msg, ", "))) - } - - return retryutils.Ok() - }) -} - -func (a *genericActuator) waitUntilCredentialsSecretAcquiredOrReleased(ctx context.Context, acquired bool, worker *extensionsv1alpha1.Worker, workerDelegate WorkerDelegate) error { +func (a *genericActuator) waitUntilCredentialsSecretAcquiredOrReleased(ctx context.Context, acquired bool, worker *extensionsv1alpha1.Worker) error { acquiredOrReleased := false return retryutils.UntilTimeout(ctx, 5*time.Second, 5*time.Minute, func(ctx context.Context) (bool, error) { // Check whether the finalizer of the machine class credentials secret has been added or removed. if !acquiredOrReleased { - secret, err := kubernetesutils.GetSecretByReference(ctx, a.client, &worker.Spec.SecretRef) + secret, err := kubernetesutils.GetSecretByReference(ctx, a.seedClient, &worker.Spec.SecretRef) if err != nil { return retryutils.SevereError(fmt.Errorf("could not get the secret referenced by worker: %+v", err)) } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_migrate.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_migrate.go index 45cc62b49..8eafb041d 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_migrate.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_migrate.go @@ -16,87 +16,17 @@ package genericactuator import ( "context" - "fmt" - machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/go-logr/logr" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gardener/gardener/extensions/pkg/controller" - extensionsworkercontroller "github.com/gardener/gardener/extensions/pkg/controller/worker" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" - "github.com/gardener/gardener/pkg/utils/managedresources" ) -// Migrate removes all machine related resources (e.g. MachineDeployments, MachineClasses, MachineClassSecrets, MachineSets and Machines) -// without waiting for machine-controller-manager to do that. Before removal it ensures that the MCM is deleted. -func (a *genericActuator) Migrate(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *controller.Cluster) error { +// Migrate ensures that the MCM is deleted in case it is managed. +func (a *genericActuator) Migrate(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, _ *controller.Cluster) error { log = log.WithValues("operation", "migrate") - workerDelegate, err := a.delegateFactory.WorkerDelegate(ctx, worker, cluster) - if err != nil { - return fmt.Errorf("could not instantiate actuator context: %w", err) - } - - // Keep objects for shoot managed resources so that they are not deleted from the shoot during the migration - if err := managedresources.SetKeepObjects(ctx, a.client, worker.Namespace, McmShootResourceName, true); err != nil { - return fmt.Errorf("could not keep objects of managed resource containing mcm chart for worker '%s': %w", kubernetesutils.ObjectName(worker), err) - } - - if a.mcmManaged { - // Make sure machine-controller-manager is deleted before deleting the machines. - if err := a.deleteMachineControllerManager(ctx, log, worker); err != nil { - return fmt.Errorf("failed deleting machine-controller-manager: %w", err) - } - - if err := a.waitUntilMachineControllerManagerIsDeleted(ctx, log, worker.Namespace); err != nil { - return fmt.Errorf("failed deleting machine-controller-manager: %w", err) - } - } - - // TODO(rfranzke): Instead of checking for machine objects, we could also only persist the state when it is nil. - // This is only to prevent that subsequent executions of Migrate don't overwrite/delete previously persisted state. - // We cannot do it this way yet since gardenlet does not persist the ShootState after all extension resources have - // been migrated. It is planned to do so after v1.79 has been released, hence we have to wait a bit longer. - machineObjectsExist, err := kubernetesutils.ResourcesExist(ctx, a.client, machinev1alpha1.SchemeGroupVersion.WithKind("MachineList"), client.InNamespace(worker.Namespace)) - if err != nil { - return fmt.Errorf("failed checking whether machine objects exist: %w", err) - } - if machineObjectsExist { - if err := extensionsworkercontroller.PersistState(ctx, log, a.client, worker); err != nil { - return fmt.Errorf("failed persisting worker state: %w", err) - } - } - - if err := a.shallowDeleteAllObjects(ctx, log, worker.Namespace, &machinev1alpha1.MachineList{}); err != nil { - return fmt.Errorf("shallow deletion of all machine failed: %w", err) - } - - if err := a.shallowDeleteAllObjects(ctx, log, worker.Namespace, &machinev1alpha1.MachineSetList{}); err != nil { - return fmt.Errorf("shallow deletion of all machineSets failed: %w", err) - } - - if err := a.shallowDeleteAllObjects(ctx, log, worker.Namespace, &machinev1alpha1.MachineDeploymentList{}); err != nil { - return fmt.Errorf("shallow deletion of all machineDeployments failed: %w", err) - } - - if err := a.shallowDeleteAllObjects(ctx, log, worker.Namespace, workerDelegate.MachineClassList()); err != nil { - return fmt.Errorf("cleaning up machine classes failed: %w", err) - } - - if err := a.shallowDeleteMachineClassSecrets(ctx, log, worker.Namespace, nil); err != nil { - return fmt.Errorf("cleaning up machine class secrets failed: %w", err) - } - - if err := a.removeFinalizerFromWorkerSecretRef(ctx, log, worker); err != nil { - return fmt.Errorf("unable to remove the finalizers from worker`s secret: %w", err) - } - - // Wait until all machine resources have been properly deleted. - if err := a.waitUntilMachineResourcesDeleted(ctx, log, worker, workerDelegate); err != nil { - return fmt.Errorf("failed while waiting for all machine resources to be deleted: %w", err) - } - - return nil + // Cleanup legacy machine-controller-manager resources. + return a.cleanupLegacyMachineControllerManagerResources(ctx, log, worker) } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_reconcile.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_reconcile.go index 414ecf65b..00330fc23 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_reconcile.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_reconcile.go @@ -23,18 +23,22 @@ import ( machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" extensionsworkercontroller "github.com/gardener/gardener/extensions/pkg/controller/worker" extensionsworkerhelper "github.com/gardener/gardener/extensions/pkg/controller/worker/helper" + v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" extensionsv1alpha1helper "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/helper" "github.com/gardener/gardener/pkg/controllerutils" + gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" "github.com/gardener/gardener/pkg/utils/kubernetes/health" retryutils "github.com/gardener/gardener/pkg/utils/retry" ) @@ -47,40 +51,19 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker return fmt.Errorf("could not instantiate actuator context: %w", err) } - // Call pre reconcilation hook to prepare Worker reconciliation. + // Call pre reconciliation hook to prepare Worker reconciliation. if err := workerDelegate.PreReconcileHook(ctx); err != nil { return fmt.Errorf("pre worker reconciliation hook failed: %w", err) } // Get the list of all existing machine deployments. existingMachineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := a.client.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { return err } - // mcmReplicaFunc returns the desired replicas for machine controller manager - var mcmReplicaFunc = func() int32 { - switch { - // if there are any existing machine deployments present with a positive replica count then MCM is needed. - case isExistingMachineDeploymentWithPositiveReplicaCountPresent(existingMachineDeployments): - return 1 - // If the cluster is hibernated then there is no further need of MCM and therefore its desired replicas is 0 - case extensionscontroller.IsHibernated(cluster): - return 0 - // If the cluster is created with hibernation enabled, then desired replicas for MCM is 0 - case extensionscontroller.IsHibernationEnabled(cluster) && extensionscontroller.IsCreationInProcess(cluster): - return 0 - // If shoot is either waking up or in the process of hibernation then, MCM is required and therefore its desired replicas is 1 - case extensionscontroller.IsHibernatingOrWakingUp(cluster): - return 1 - // If the shoot is awake then MCM should be available and therefore its desired replicas is 1 - default: - return 1 - } - } - - // Deploy the machine-controller-manager into the cluster. - if err := a.deployMachineControllerManager(ctx, log, worker, cluster, workerDelegate, mcmReplicaFunc); err != nil { + // Cleanup legacy machine-controller-manager resources. + if err := a.cleanupLegacyMachineControllerManagerResources(ctx, log, worker); err != nil { return err } @@ -97,7 +80,7 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker ) // Get list of existing machine class names - existingMachineClassNames, err := a.listMachineClassNames(ctx, worker.Namespace, workerDelegate.MachineClassList()) + existingMachineClassNames, err := a.listMachineClassNames(ctx, worker.Namespace) if err != nil { return err } @@ -119,7 +102,7 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker } // Generate machine deployment configuration based on previously computed list of deployments and deploy them. - if err := deployMachineDeployments(ctx, log, a.client, cluster, worker, existingMachineDeployments, wantedMachineDeployments, workerDelegate.MachineClassKind(), clusterAutoscalerUsed); err != nil { + if err := deployMachineDeployments(ctx, log, a.seedClient, cluster, worker, existingMachineDeployments, wantedMachineDeployments, clusterAutoscalerUsed); err != nil { return fmt.Errorf("failed to generate the machine deployment config: %w", err) } @@ -139,12 +122,12 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker if isStuck { podList := corev1.PodList{} - if err2 := a.client.List(ctx, &podList, client.InNamespace(worker.Namespace), client.MatchingLabels{"role": "machine-controller-manager"}); err2 != nil { + if err2 := a.seedClient.List(ctx, &podList, client.InNamespace(worker.Namespace), client.MatchingLabels{"role": "machine-controller-manager"}); err2 != nil { return fmt.Errorf("failed to list machine-controller-manager pods for worker (%s/%s): %w", worker.Namespace, worker.Name, err2) } for _, pod := range podList.Items { - if err2 := a.client.Delete(ctx, &pod); err2 != nil { + if err2 := a.seedClient.Delete(ctx, &pod); err2 != nil { return fmt.Errorf("failed to delete stuck machine-controller-manager pod for worker (%s/%s): %w", worker.Namespace, worker.Name, err2) } } @@ -164,7 +147,7 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker } // Delete all old machine classes (i.e. those which were not previously computed but exist in the cluster). - if err := a.cleanupMachineClasses(ctx, log, worker.Namespace, workerDelegate.MachineClassList(), wantedMachineDeployments); err != nil { + if err := a.cleanupMachineClasses(ctx, log, worker.Namespace, wantedMachineDeployments); err != nil { return fmt.Errorf("failed to cleanup the machine classes: %w", err) } @@ -173,8 +156,11 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker return fmt.Errorf("failed to cleanup the orphaned machine class secrets: %w", err) } - replicas := mcmReplicaFunc() - if replicas > 0 { + deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: v1beta1constants.DeploymentNameMachineControllerManager, Namespace: worker.Namespace}} + if err := a.seedClient.Get(ctx, client.ObjectKeyFromObject(deployment), deployment); client.IgnoreNotFound(err) != nil { + return fmt.Errorf("failed reading deployment %s: %w", client.ObjectKeyFromObject(deployment), err) + } + if pointer.Int32Deref(deployment.Spec.Replicas, 0) > 0 { // Wait until all unwanted machine deployments are deleted from the system. if err := a.waitUntilUnwantedMachineDeploymentsDeleted(ctx, log, worker, wantedMachineDeployments); err != nil { return fmt.Errorf("error while waiting for all undesired machine deployments to be deleted: %w", err) @@ -188,12 +174,12 @@ func (a *genericActuator) Reconcile(ctx context.Context, log logr.Logger, worker // Scale down machine-controller-manager if shoot is hibernated. if isHibernationEnabled { - if err := scaleMachineControllerManager(ctx, log, a.client, worker, 0); err != nil { + if err := scaleMachineControllerManager(ctx, log, a.seedClient, worker, 0); err != nil { return err } } - // Call post reconcilation hook after Worker reconciliation has happened. + // Call post reconciliation hook after Worker reconciliation has happened. if err := workerDelegate.PostReconcileHook(ctx); err != nil { return fmt.Errorf("post worker reconciliation hook failed: %w", err) } @@ -209,7 +195,6 @@ func deployMachineDeployments( worker *extensionsv1alpha1.Worker, existingMachineDeployments *machinev1alpha1.MachineDeploymentList, wantedMachineDeployments extensionsworkercontroller.MachineDeployments, - classKind string, clusterAutoscalerUsed bool, ) error { log.Info("Deploying machine deployments") @@ -291,7 +276,7 @@ func deployMachineDeployments( }, Spec: machinev1alpha1.MachineSpec{ Class: machinev1alpha1.ClassSpec{ - Kind: classKind, + Kind: "MachineClass", Name: deployment.ClassName, }, NodeTemplateSpec: machinev1alpha1.NodeTemplateSpec{ @@ -327,18 +312,18 @@ func (a *genericActuator) waitUntilWantedMachineDeploymentsAvailable(ctx context // Get the list of all machine deployments machineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := a.client.List(ctx, machineDeployments, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, machineDeployments, client.InNamespace(worker.Namespace)); err != nil { return retryutils.SevereError(err) } // Get the list of all machine sets machineSets := &machinev1alpha1.MachineSetList{} - if err := a.client.List(ctx, machineSets, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, machineSets, client.InNamespace(worker.Namespace)); err != nil { return retryutils.SevereError(err) } // map the owner reference to the machine sets - ownerReferenceToMachineSet := extensionsworkerhelper.BuildOwnerToMachineSetsMap(machineSets.Items) + ownerReferenceToMachineSet := gardenerutils.BuildOwnerToMachineSetsMap(machineSets.Items) // Collect the numbers of available and desired replicas. for _, deployment := range machineDeployments.Items { @@ -432,7 +417,7 @@ func (a *genericActuator) waitUntilUnwantedMachineDeploymentsDeleted(ctx context log.Info("Waiting until unwanted machine deployments are deleted") return retryutils.UntilTimeout(ctx, 5*time.Second, 5*time.Minute, func(ctx context.Context) (bool, error) { existingMachineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := a.client.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { + if err := a.seedClient.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { return retryutils.SevereError(err) } @@ -469,7 +454,7 @@ func (a *genericActuator) updateWorkerStatusMachineDeployments(ctx context.Conte patch := client.MergeFrom(worker.DeepCopy()) worker.Status.MachineDeployments = statusMachineDeployments worker.Status.MachineDeploymentsLastUpdateTime = &updateTime - return a.client.Status().Patch(ctx, worker, patch) + return a.seedClient.Status().Patch(ctx, worker, patch) } // Helper functions @@ -505,15 +490,6 @@ func getExistingMachineDeployment(existingMachineDeployments *machinev1alpha1.Ma return nil } -func isExistingMachineDeploymentWithPositiveReplicaCountPresent(existingMachineDeployments *machinev1alpha1.MachineDeploymentList) bool { - for _, machineDeployment := range existingMachineDeployments.Items { - if machineDeployment.Status.Replicas > 0 { - return true - } - } - return false -} - // ReadMachineConfiguration reads the configuration from worker-pool and returns the corresponding configuration of machine-deployment. func ReadMachineConfiguration(pool extensionsv1alpha1.WorkerPool) *machinev1alpha1.MachineConfiguration { machineConfiguration := &machinev1alpha1.MachineConfiguration{} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_restore.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_restore.go index d4a1d9259..c78a40f47 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_restore.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/actuator_restore.go @@ -22,12 +22,17 @@ import ( machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" "github.com/go-logr/logr" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" extensionsworkercontroller "github.com/gardener/gardener/extensions/pkg/controller/worker" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" + v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" + v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/client/kubernetes" + "github.com/gardener/gardener/pkg/utils/gardener/shootstate" kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" ) @@ -35,7 +40,8 @@ import ( func RestoreWithoutReconcile( ctx context.Context, log logr.Logger, - cl client.Client, + gardenReader client.Reader, + seedClient client.Client, delegateFactory DelegateFactory, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster, @@ -56,21 +62,21 @@ func RestoreWithoutReconcile( // Get the list of all existing machine deployments. existingMachineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := cl.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { + if err := seedClient.List(ctx, existingMachineDeployments, client.InNamespace(worker.Namespace)); err != nil { return err } // Parse the worker state to a separate machineDeployment states and attach them to // the corresponding machineDeployments which are to be deployed later - log.Info("Extracting state from worker status") - if err := addStateToMachineDeployment(worker, wantedMachineDeployments); err != nil { + log.Info("Extracting machine state") + if err := addStateToMachineDeployment(ctx, log, gardenReader, cluster.Shoot, worker, wantedMachineDeployments); err != nil { return err } wantedMachineDeployments = removeWantedDeploymentWithoutState(wantedMachineDeployments) // Scale the machine-controller-manager to 0. During restoration MCM must not be working - if err := scaleMachineControllerManager(ctx, log, cl, worker, 0); err != nil { + if err := scaleMachineControllerManager(ctx, log, seedClient, worker, 0); err != nil { return fmt.Errorf("failed to scale down machine-controller-manager: %w", err) } @@ -79,23 +85,23 @@ func RestoreWithoutReconcile( return fmt.Errorf("failed to deploy the machine classes: %w", err) } - if err := kubernetes.WaitUntilDeploymentScaledToDesiredReplicas(ctx, cl, kubernetesutils.Key(worker.Namespace, McmDeploymentName), 0); err != nil && !apierrors.IsNotFound(err) { + if err := kubernetes.WaitUntilDeploymentScaledToDesiredReplicas(ctx, seedClient, kubernetesutils.Key(worker.Namespace, v1beta1constants.DeploymentNameMachineControllerManager), 0); err != nil && !apierrors.IsNotFound(err) { return fmt.Errorf("deadline exceeded while scaling down machine-controller-manager: %w", err) } // Do the actual restoration - if err := restoreMachineSetsAndMachines(ctx, log, cl, wantedMachineDeployments); err != nil { + if err := restoreMachineSetsAndMachines(ctx, log, seedClient, wantedMachineDeployments); err != nil { return fmt.Errorf("failed restoration of the machineSet and the machines: %w", err) } // Generate machine deployment configuration based on previously computed list of deployments and deploy them. - if err := deployMachineDeployments(ctx, log, cl, cluster, worker, existingMachineDeployments, wantedMachineDeployments, workerDelegate.MachineClassKind(), true); err != nil { + if err := deployMachineDeployments(ctx, log, seedClient, cluster, worker, existingMachineDeployments, wantedMachineDeployments, true); err != nil { return fmt.Errorf("failed to restore the machine deployment config: %w", err) } // Scale the machine-controller-manager to 1 now that all resources have been restored. if !extensionscontroller.IsHibernated(cluster) { - if err := scaleMachineControllerManager(ctx, log, cl, worker, 1); err != nil { + if err := scaleMachineControllerManager(ctx, log, seedClient, worker, 1); err != nil { return fmt.Errorf("failed to scale up machine-controller-manager: %w", err) } } @@ -107,34 +113,61 @@ func RestoreWithoutReconcile( // If there is a record in the state corresponding to a wanted deployment then the Restore function // deploys that MachineDeployment with all related MachineSet and Machines. It finally calls the 'Reconcile' function. func (a *genericActuator) Restore(ctx context.Context, log logr.Logger, worker *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error { - if err := RestoreWithoutReconcile(ctx, log, a.client, a.delegateFactory, worker, cluster); err != nil { + if err := RestoreWithoutReconcile(ctx, log, a.gardenReader, a.seedClient, a.delegateFactory, worker, cluster); err != nil { return err } return a.Reconcile(ctx, log, worker, cluster) - // TODO(rfranzke): Uncomment these lines after the stateReconciler has been dropped (probably after v1.79 has been - // released). - // patch := client.MergeFromWithOptions(worker.DeepCopy(), client.MergeFromWithOptimisticLock{}) - // worker.Status.State = nil - // return a.client.Status().Patch(ctx, worker, patch) } -func addStateToMachineDeployment(worker *extensionsv1alpha1.Worker, wantedMachineDeployments extensionsworkercontroller.MachineDeployments) error { - if worker.Status.State == nil || len(worker.Status.State.Raw) <= 0 { - return nil +func addStateToMachineDeployment( + ctx context.Context, + log logr.Logger, + gardenReader client.Reader, + shoot *gardencorev1beta1.Shoot, + worker *extensionsv1alpha1.Worker, + wantedMachineDeployments extensionsworkercontroller.MachineDeployments, +) error { + var state []byte + + // We use the `gardenReader` here to prevent controller-runtime from trying to cache/list the ShootStates. + shootState := &gardencorev1beta1.ShootState{ObjectMeta: metav1.ObjectMeta{Name: shoot.Name, Namespace: shoot.Namespace}} + if err := gardenReader.Get(ctx, client.ObjectKeyFromObject(shootState), shootState); err != nil { + return err } - // Parse the worker state to MachineDeploymentStates - workerState := &extensionsworkercontroller.State{ - MachineDeployments: make(map[string]*extensionsworkercontroller.MachineDeploymentState), + gardenerData := v1beta1helper.GardenerResourceDataList(shootState.Spec.Gardener) + if machineState := gardenerData.Get(v1beta1constants.DataTypeMachineState); machineState != nil && machineState.Type == v1beta1constants.DataTypeMachineState { + log.Info("Fetching machine state from ShootState succeeded", "shootState", client.ObjectKeyFromObject(shootState)) + var err error + state, err = shootstate.DecompressMachineState(machineState.Data.Raw) + if err != nil { + return err + } + } else { + // TODO(rfranzke): Drop this code after Gardener v1.86 has been released. + log.Info("Fetching machine state from ShootState not possible since the machine state was not found, falling back to Worker's .status.state field", "shootState", client.ObjectKeyFromObject(shootState)) + if worker.Status.State == nil || len(worker.Status.State.Raw) <= 0 { + log.Info("Worker's .status.state field is empty, no state to add") + return nil + } + log.Info("Fetching machine state from Worker's .status.state field succeeded") + state = worker.Status.State.Raw } - if err := json.Unmarshal(worker.Status.State.Raw, &workerState); err != nil { + if len(state) == 0 { + log.Info("Machine state is empty, no state to add") + return nil + } + + // Parse the worker state to MachineDeploymentStates + machineState := &shootstate.MachineState{MachineDeployments: make(map[string]*shootstate.MachineDeploymentState)} + if err := json.Unmarshal(state, &machineState); err != nil { return err } // Attach the parsed MachineDeploymentStates to the wanted MachineDeployments for index, wantedMachineDeployment := range wantedMachineDeployments { - wantedMachineDeployments[index].State = workerState.MachineDeployments[wantedMachineDeployment.Name] + wantedMachineDeployments[index].State = machineState.MachineDeployments[wantedMachineDeployment.Name] } return nil diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/interface.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/interface.go index c4924c68d..804d9546a 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/interface.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/interface.go @@ -17,8 +17,6 @@ package genericactuator import ( "context" - "sigs.k8s.io/controller-runtime/pkg/client" - extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" "github.com/gardener/gardener/extensions/pkg/controller/worker" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" @@ -26,19 +24,6 @@ import ( // WorkerDelegate is used for the Worker reconciliation. type WorkerDelegate interface { - // GetMachineControllerManagerChartValues should return the chart and the values for the machine-controller-manager - // deployment. - GetMachineControllerManagerChartValues(context.Context) (map[string]interface{}, error) - // GetMachineControllerManagerShootChartValues should return the values to render the chart containing resources - // that are required by the machine-controller-manager inside the shoot cluster itself. - GetMachineControllerManagerShootChartValues(context.Context) (map[string]interface{}, error) - - // MachineClassKind yields the name of the provider specific machine class. - MachineClassKind() string - // MachineClass yields a newly initialized machine class object. - MachineClass() client.Object - // MachineClassList yields a newly initialized machine class list object. - MachineClassList() client.ObjectList // DeployMachineClasses generates and creates the provider specific machine classes. DeployMachineClasses(context.Context) error diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/machine_controller_manager.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/machine_controller_manager.go index a90d0a3d3..3d0ae6a1c 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/machine_controller_manager.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/genericactuator/machine_controller_manager.go @@ -16,151 +16,29 @@ package genericactuator import ( "context" - "fmt" - "time" "github.com/go-logr/logr" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" - extensionscontroller "github.com/gardener/gardener/extensions/pkg/controller" + v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/client/kubernetes" - gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" "github.com/gardener/gardener/pkg/utils/managedresources" ) -const ( - // McmShootResourceName is the name of the managed resource that contains the Machine Controller Manager - McmShootResourceName = "extension-worker-mcm-shoot" - - // McmDeploymentName is the name of the deployment that spawn machine-cotroll-manager pods - McmDeploymentName = "machine-controller-manager" -) - -// ReplicaCount determines the number of replicas. -type ReplicaCount func() int32 - -func (a *genericActuator) deployMachineControllerManager(ctx context.Context, logger logr.Logger, workerObj *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster, workerDelegate WorkerDelegate, replicas ReplicaCount) error { - if !a.mcmManaged { - logger.Info("Skip machine-controller-manager deployment since gardenlet manages it - deleting monitoring ConfigMap and extension-worker-mcm-shoot ManagedResource") - if err := a.client.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "machine-controller-manager-monitoring-config", Namespace: workerObj.Namespace}}); client.IgnoreNotFound(err) != nil { - return err - } - return managedresources.Delete(ctx, a.client, workerObj.Namespace, McmShootResourceName, false) - } - - logger.Info("Deploying the machine-controller-manager") - - mcmValues, err := workerDelegate.GetMachineControllerManagerChartValues(ctx) - if err != nil { - return err - } - - mcmValues["useTokenRequestor"] = true - mcmValues["useProjectedTokenMount"] = true - - if err := gardenerutils.NewShootAccessSecret(a.mcmName, workerObj.Namespace).Reconcile(ctx, a.client); err != nil { +// TODO(rfranzke): Remove this function after v1.85 has been released. +func (a *genericActuator) cleanupLegacyMachineControllerManagerResources(ctx context.Context, logger logr.Logger, workerObj *extensionsv1alpha1.Worker) error { + logger.Info("Skip machine-controller-manager deployment since gardenlet manages it - deleting monitoring ConfigMap and extension-worker-mcm-shoot ManagedResource") + if err := a.seedClient.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "machine-controller-manager-monitoring-config", Namespace: workerObj.Namespace}}); client.IgnoreNotFound(err) != nil { return err } - mcmValues["genericTokenKubeconfigSecretName"] = extensionscontroller.GenericTokenKubeconfigSecretNameFromCluster(cluster) - - replicaCount := replicas() - mcmValues["replicas"] = replicaCount - - if err := a.mcmSeedChart.Apply(ctx, a.chartApplier, workerObj.Namespace, - a.imageVector, a.gardenerClientset.Version(), cluster.Shoot.Spec.Kubernetes.Version, mcmValues); err != nil { - return fmt.Errorf("could not apply MCM chart in seed for worker '%s': %w", kubernetesutils.ObjectName(workerObj), err) - } - - if err := a.applyMachineControllerManagerShootChart(ctx, logger, workerDelegate, workerObj, cluster); err != nil { - return fmt.Errorf("could not apply machine-controller-manager shoot chart: %w", err) - } - - logger.Info("Waiting until rollout of machine-controller-manager Deployment is completed") - if err := kubernetes.WaitUntilDeploymentRolloutIsComplete(ctx, a.client, workerObj.Namespace, McmDeploymentName, 5*time.Second, 300*time.Second); err != nil { - return fmt.Errorf("waiting until deployment/%s is updated: %w", McmDeploymentName, err) - } - - return nil -} - -func (a *genericActuator) deleteMachineControllerManager(ctx context.Context, logger logr.Logger, workerObj *extensionsv1alpha1.Worker) error { - if !a.mcmManaged { - logger.Info("Skip machine-controller-manager deployment since gardenlet manages it - deleting monitoring ConfigMap and extension-worker-mcm-shoot ManagedResource") - if err := a.client.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "machine-controller-manager-monitoring-config", Namespace: workerObj.Namespace}}); client.IgnoreNotFound(err) != nil { - return err - } - return managedresources.Delete(ctx, a.client, workerObj.Namespace, McmShootResourceName, false) - } - - logger.Info("Deleting the machine-controller-manager") - if err := managedresources.Delete(ctx, a.client, workerObj.Namespace, McmShootResourceName, false); err != nil { - return fmt.Errorf("could not delete managed resource containing mcm chart for worker '%s': %w", kubernetesutils.ObjectName(workerObj), err) - } - - logger.Info("Waiting for machine-controller-manager ManagedResource to be deleted") - timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - if err := managedresources.WaitUntilDeleted(timeoutCtx, a.client, workerObj.Namespace, McmShootResourceName); err != nil { - return fmt.Errorf("error while waiting for managed resource containing mcm for '%s' to be deleted: %w", kubernetesutils.ObjectName(workerObj), err) - } - - if err := a.mcmSeedChart.Delete(ctx, a.client, workerObj.Namespace); err != nil { - return fmt.Errorf("cleaning up machine-controller-manager resources in seed failed: %w", err) - } - - return kubernetesutils.DeleteObject(ctx, a.client, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "shoot-access-" + a.mcmName, Namespace: workerObj.Namespace}}) -} - -func (a *genericActuator) waitUntilMachineControllerManagerIsDeleted(ctx context.Context, logger logr.Logger, namespace string) error { - logger.Info("Waiting until machine-controller-manager is deleted") - return wait.PollUntil(5*time.Second, func() (bool, error) { - machineControllerManagerDeployment := &appsv1.Deployment{} - if err := a.client.Get(ctx, client.ObjectKey{Namespace: namespace, Name: McmDeploymentName}, machineControllerManagerDeployment); err != nil { - if apierrors.IsNotFound(err) { - return true, nil - } - return false, err - } - - return false, nil - }, ctx.Done()) + return managedresources.Delete(ctx, a.seedClient, workerObj.Namespace, "extension-worker-mcm-shoot", false) } func scaleMachineControllerManager(ctx context.Context, logger logr.Logger, cl client.Client, worker *extensionsv1alpha1.Worker, replicas int32) error { logger.Info("Scaling machine-controller-manager", "replicas", replicas) - return client.IgnoreNotFound(kubernetes.ScaleDeployment(ctx, cl, kubernetesutils.Key(worker.Namespace, McmDeploymentName), replicas)) -} - -func (a *genericActuator) applyMachineControllerManagerShootChart(ctx context.Context, logger logr.Logger, workerDelegate WorkerDelegate, workerObj *extensionsv1alpha1.Worker, cluster *extensionscontroller.Cluster) error { - if !a.mcmManaged { - logger.Info("Skip machine-controller-manager shoot chart application since gardenlet manages it") - return nil - } - - // Create shoot chart renderer - chartRenderer, err := a.chartRendererFactory.NewChartRendererForShoot(cluster.Shoot.Spec.Kubernetes.Version) - if err != nil { - return fmt.Errorf("could not create chart renderer for shoot '%s': %w", workerObj.Namespace, err) - } - - // Get machine-controller-manager shoot chart values - values, err := workerDelegate.GetMachineControllerManagerShootChartValues(ctx) - if err != nil { - return err - } - - values["useTokenRequestor"] = true - - if err := managedresources.RenderChartAndCreate(ctx, workerObj.Namespace, McmShootResourceName, false, a.client, chartRenderer, a.mcmShootChart, values, a.imageVector, metav1.NamespaceSystem, cluster.Shoot.Spec.Kubernetes.Version, true, false); err != nil { - return fmt.Errorf("could not apply control plane shoot chart for worker '%s': %w", kubernetesutils.ObjectName(workerObj), err) - } - - return nil + return client.IgnoreNotFound(kubernetes.ScaleDeployment(ctx, cl, kubernetesutils.Key(worker.Namespace, v1beta1constants.DeploymentNameMachineControllerManager), replicas)) } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/helper/helper.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/helper/helper.go index 355ade13f..777abbcf5 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/helper/helper.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/helper/helper.go @@ -24,54 +24,6 @@ import ( errorsutils "github.com/gardener/gardener/pkg/utils/errors" ) -const ( - nameLabel = "name" - // MachineSetKind is the kind of the owner reference of a machine set - MachineSetKind = "MachineSet" - // MachineDeploymentKind is the kind of the owner reference of a machine deployment - MachineDeploymentKind = "MachineDeployment" -) - -// BuildOwnerToMachinesMap builds a map from a slice of machinev1alpha1.Machine, that maps the owner reference -// to a slice of machines with the same owner reference -func BuildOwnerToMachinesMap(machines []machinev1alpha1.Machine) map[string][]machinev1alpha1.Machine { - ownerToMachines := make(map[string][]machinev1alpha1.Machine) - for index, machine := range machines { - if len(machine.OwnerReferences) > 0 { - for _, reference := range machine.OwnerReferences { - if reference.Kind == MachineSetKind { - ownerToMachines[reference.Name] = append(ownerToMachines[reference.Name], machines[index]) - } - } - } else if len(machine.Labels) > 0 { - if machineDeploymentName, ok := machine.Labels[nameLabel]; ok { - ownerToMachines[machineDeploymentName] = append(ownerToMachines[machineDeploymentName], machines[index]) - } - } - } - return ownerToMachines -} - -// BuildOwnerToMachineSetsMap builds a map from a slice of machinev1alpha1.MachineSet, that maps the owner reference -// to a slice of MachineSets with the same owner reference -func BuildOwnerToMachineSetsMap(machineSets []machinev1alpha1.MachineSet) map[string][]machinev1alpha1.MachineSet { - ownerToMachineSets := make(map[string][]machinev1alpha1.MachineSet) - for index, machineSet := range machineSets { - if len(machineSet.OwnerReferences) > 0 { - for _, reference := range machineSet.OwnerReferences { - if reference.Kind == MachineDeploymentKind { - ownerToMachineSets[reference.Name] = append(ownerToMachineSets[reference.Name], machineSets[index]) - } - } - } else if len(machineSet.Labels) > 0 { - if machineDeploymentName, ok := machineSet.Labels[nameLabel]; ok { - ownerToMachineSets[machineDeploymentName] = append(ownerToMachineSets[machineDeploymentName], machineSets[index]) - } - } - } - return ownerToMachineSets -} - // GetMachineSetWithMachineClass checks if for the given , there exists a machine set in the with the machine class // returns the machine set or nil func GetMachineSetWithMachineClass(machineDeploymentName, machineClassName string, ownerReferenceToMachineSet map[string][]machinev1alpha1.MachineSet) *machinev1alpha1.MachineSet { diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/machines.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/machines.go index c9232cbc9..63c15f457 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/machines.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/machines.go @@ -30,6 +30,7 @@ import ( "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/utils" + "github.com/gardener/gardener/pkg/utils/gardener/shootstate" ) var diskSizeRegex = regexp.MustCompile(`^(\d+)`) @@ -47,26 +48,13 @@ type MachineDeployment struct { Labels map[string]string Annotations map[string]string Taints []corev1.Taint - State *MachineDeploymentState + State *shootstate.MachineDeploymentState MachineConfiguration *machinev1alpha1.MachineConfiguration } // MachineDeployments is a list of machine deployments. type MachineDeployments []MachineDeployment -// MachineDeploymentState stores the last versions of the machine sets and machine which -// the machine deployment corresponds -type MachineDeploymentState struct { - Replicas int32 `json:"replicas,omitempty"` - MachineSets []machinev1alpha1.MachineSet `json:"machineSets,omitempty"` - Machines []machinev1alpha1.Machine `json:"machines,omitempty"` -} - -// State represent the last known state of a Worker -type State struct { - MachineDeployments map[string]*MachineDeploymentState `json:"machineDeployments,omitempty"` -} - // HasDeployment checks whether the is part of the // list, i.e. whether there is an entry whose 'Name' attribute matches . It returns true or false. func (m MachineDeployments) HasDeployment(name string) bool { @@ -224,7 +212,7 @@ func DistributePositiveIntOrPercent(zoneIndex int32, intOrPercent intstr.IntOrSt if intOrPercent.Type == intstr.String { return intstr.FromString(DistributePercentOverZones(zoneIndex, intOrPercent.StrVal, zoneSize, total)) } - return intstr.FromInt(int(DistributeOverZones(zoneIndex, intOrPercent.IntVal, zoneSize))) + return intstr.FromInt32(DistributeOverZones(zoneIndex, intOrPercent.IntVal, zoneSize)) } // DiskSize extracts the numerical component of DiskSize strings, i.e. strings like "10Gi" and diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/mapper.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/mapper.go index fba76d6ed..e21da3e59 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/mapper.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/mapper.go @@ -15,19 +15,12 @@ package worker import ( - "context" - "time" - - machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" - "github.com/go-logr/logr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/controllerutils/mapper" - predicateutils "github.com/gardener/gardener/pkg/controllerutils/predicate" ) // ClusterToWorkerMapper returns a mapper that returns requests for Worker whose @@ -35,72 +28,3 @@ import ( func ClusterToWorkerMapper(mgr manager.Manager, predicates []predicate.Predicate) mapper.Mapper { return mapper.ClusterToObjectMapper(mgr, func() client.ObjectList { return &extensionsv1alpha1.WorkerList{} }, predicates) } - -// MachineSetToWorkerMapper returns a mapper that returns requests for Worker whose -// referenced MachineSets have been modified. -func MachineSetToWorkerMapper(predicates []predicate.Predicate) mapper.Mapper { - return newMachineSetToObjectMapper(func() client.ObjectList { return &extensionsv1alpha1.WorkerList{} }, predicates) -} - -// MachineToWorkerMapper returns a mapper that returns requests for Worker whose -// referenced Machines have been modified. -func MachineToWorkerMapper(predicates []predicate.Predicate) mapper.Mapper { - return newMachineToObjectMapper(func() client.ObjectList { return &extensionsv1alpha1.WorkerList{} }, predicates) -} - -type machineSetToObjectMapper struct { - newObjListFunc func() client.ObjectList - predicates []predicate.Predicate -} - -func (m *machineSetToObjectMapper) Map(ctx context.Context, _ logr.Logger, reader client.Reader, obj client.Object) []reconcile.Request { - machineSet, ok := obj.(*machinev1alpha1.MachineSet) - if !ok { - return nil - } - - objList := m.newObjListFunc() - if err := reader.List(ctx, objList, client.InNamespace(machineSet.Namespace)); err != nil { - return nil - } - - return mapper.ObjectListToRequests(objList, func(o client.Object) bool { - return predicateutils.EvalGeneric(o, m.predicates...) - }) -} - -// newMachineSetToObjectMapper returns a mapper that returns requests for objects whose -// referenced MachineSets have been modified. -func newMachineSetToObjectMapper(newObjListFunc func() client.ObjectList, predicates []predicate.Predicate) mapper.Mapper { - return &machineSetToObjectMapper{newObjListFunc: newObjListFunc, predicates: predicates} -} - -type machineToObjectMapper struct { - newObjListFunc func() client.ObjectList - predicates []predicate.Predicate -} - -func (m *machineToObjectMapper) Map(ctx context.Context, _ logr.Logger, reader client.Reader, obj client.Object) []reconcile.Request { - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - machine, ok := obj.(*machinev1alpha1.Machine) - if !ok { - return nil - } - - objList := m.newObjListFunc() - if err := reader.List(ctx, objList, client.InNamespace(machine.Namespace)); err != nil { - return nil - } - - return mapper.ObjectListToRequests(objList, func(o client.Object) bool { - return predicateutils.EvalGeneric(o, m.predicates...) - }) -} - -// newMachineToObjectMapper returns a mapper that returns requests for objects whose -// referenced Machines have been modified. -func newMachineToObjectMapper(newObjListFunc func() client.ObjectList, predicates []predicate.Predicate) mapper.Mapper { - return &machineToObjectMapper{newObjListFunc: newObjListFunc, predicates: predicates} -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/predicate.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/predicate.go index c560894cd..b7b10a6bf 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/predicate.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/predicate.go @@ -19,8 +19,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" - - "github.com/gardener/gardener/pkg/api/extensions" ) // MachineNodeInfoHasChanged is a predicate deciding whether the information about the backing node of a Machine has @@ -56,20 +54,3 @@ func MachineNodeInfoHasChanged() predicate.Predicate { }, } } - -// WorkerSkipStateUpdateAnnotation is a Worker annotation that instructs the worker-state controller to do not reconcile the corresponding Worker. -const WorkerSkipStateUpdateAnnotation = "worker.gardener.cloud/skip-state-update" - -// WorkerStateUpdateIsNotSkipped is a predicate deciding whether the Worker is not annotated to skip state updates. -func WorkerStateUpdateIsNotSkipped() predicate.Predicate { - return predicate.NewPredicateFuncs(func(obj client.Object) bool { - acc, err := extensions.Accessor(obj) - if err != nil { - // We assume by default that the Worker is not annotated to skip state updates. - return true - } - - _, found := acc.GetAnnotations()[WorkerSkipStateUpdateAnnotation] - return !found - }) -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/reconciler.go index 34377985f..7c2c14111 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/reconciler.go @@ -163,7 +163,13 @@ func (r *reconciler) delete( } log.Info("Starting the deletion of worker") - if err := r.actuator.Delete(ctx, log, worker, cluster); err != nil { + var err error + if cluster != nil && v1beta1helper.ShootNeedsForceDeletion(cluster.Shoot) { + err = r.actuator.ForceDelete(ctx, log, worker, cluster) + } else { + err = r.actuator.Delete(ctx, log, worker, cluster) + } + if err != nil { _ = r.statusUpdater.Error(ctx, log, worker, err, gardencorev1beta1.LastOperationTypeDelete, "Error deleting Worker") return reconcilerutils.ReconcileErr(err) } @@ -172,8 +178,7 @@ func (r *reconciler) delete( return reconcile.Result{}, err } - err := r.removeFinalizerFromWorker(ctx, log, worker) - return reconcile.Result{}, err + return reconcile.Result{}, r.removeFinalizerFromWorker(ctx, log, worker) } func (r *reconciler) reconcile( diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/state_reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/state_reconciler.go deleted file mode 100644 index 0d6f86ee2..000000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/controller/worker/state_reconciler.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package worker - -import ( - "bytes" - "cmp" - "context" - "encoding/json" - "fmt" - "slices" - - machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" - "github.com/go-logr/logr" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - extensionsworkerhelper "github.com/gardener/gardener/extensions/pkg/controller/worker/helper" - gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" - v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" - extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" -) - -// TODO(rfranzke): Drop this stateReconciler after a few releases as soon as the shoot migrate flow persists the Shoot -// state only after all extension resources have been migrated. - -type stateReconciler struct { - client client.Client -} - -// NewStateReconciler creates a new reconcile.Reconciler that reconciles -// Worker's State resources of Gardener's `extensions.gardener.cloud` API group. -func NewStateReconciler(mgr manager.Manager) reconcile.Reconciler { - return &stateReconciler{client: mgr.GetClient()} -} - -func (r *stateReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - log := logf.FromContext(ctx) - - worker := &extensionsv1alpha1.Worker{} - if err := r.client.Get(ctx, request.NamespacedName, worker); err != nil { - if apierrors.IsNotFound(err) { - log.V(1).Info("Object is gone, stop reconciling") - return reconcile.Result{}, nil - } - return reconcile.Result{}, fmt.Errorf("error retrieving object from store: %w", err) - } - - if worker.DeletionTimestamp != nil { - return reconcile.Result{}, nil - } - - if v1beta1helper.ComputeOperationType(worker.ObjectMeta, worker.Status.LastOperation) != gardencorev1beta1.LastOperationTypeReconcile { - return reconcile.Result{Requeue: true}, nil - } - - if isWorkerMigrated(worker) { - return reconcile.Result{}, nil - } - - return reconcile.Result{}, PersistState(ctx, log, r.client, worker) -} - -// PersistState persists the worker state into the .status.state field. -func PersistState(ctx context.Context, log logr.Logger, c client.Client, worker *extensionsv1alpha1.Worker) error { - state, err := computeState(ctx, c, worker.Namespace) - if err != nil { - return err - } - - rawState, err := json.Marshal(state) - if err != nil { - return err - } - - // If the state did not change, do not even try to send an empty PATCH request. - if worker.Status.State != nil && bytes.Equal(rawState, worker.Status.State.Raw) { - return nil - } - - patch := client.MergeFromWithOptions(worker.DeepCopy(), client.MergeFromWithOptimisticLock{}) - worker.Status.State = &runtime.RawExtension{Raw: rawState} - if err := c.Status().Patch(ctx, worker, patch); err != nil { - return fmt.Errorf("error updating Worker state: %w", err) - } - - log.Info("Successfully updated Worker state") - return nil -} - -func computeState(ctx context.Context, c client.Client, namespace string) (*State, error) { - existingMachineDeployments := &machinev1alpha1.MachineDeploymentList{} - if err := c.List(ctx, existingMachineDeployments, client.InNamespace(namespace)); err != nil { - return nil, err - } - - machineSets, err := getExistingMachineSetsMap(ctx, c, namespace) - if err != nil { - return nil, err - } - - machines, err := getExistingMachinesMap(ctx, c, namespace) - if err != nil { - return nil, err - } - - workerState := &State{MachineDeployments: make(map[string]*MachineDeploymentState)} - - for _, deployment := range existingMachineDeployments.Items { - machineDeploymentState := &MachineDeploymentState{} - machineDeploymentState.Replicas = deployment.Spec.Replicas - - machineDeploymentMachineSets, ok := machineSets[deployment.Name] - if !ok { - continue - } - - addMachineSetToMachineDeploymentState(machineDeploymentMachineSets, machineDeploymentState) - - for _, machineSet := range machineDeploymentMachineSets { - currentMachines := append(machines[machineSet.Name], machines[deployment.Name]...) - if len(currentMachines) <= 0 { - continue - } - - for index := range currentMachines { - addMachineToMachineDeploymentState(¤tMachines[index], machineDeploymentState) - } - } - - workerState.MachineDeployments[deployment.Name] = machineDeploymentState - } - - return workerState, nil -} - -// getExistingMachineSetsMap returns a map of existing MachineSets as values and their owners as keys -func getExistingMachineSetsMap(ctx context.Context, c client.Client, namespace string) (map[string][]machinev1alpha1.MachineSet, error) { - existingMachineSets := &machinev1alpha1.MachineSetList{} - if err := c.List(ctx, existingMachineSets, client.InNamespace(namespace)); err != nil { - return nil, err - } - - // When we read from the cache we get unsorted results, hence, we sort to prevent unnecessary state updates from happening. - slices.SortFunc(existingMachineSets.Items, func(a, b machinev1alpha1.MachineSet) int { - return cmp.Compare(a.Name, b.Name) - }) - - return extensionsworkerhelper.BuildOwnerToMachineSetsMap(existingMachineSets.Items), nil -} - -// getExistingMachinesMap returns a map of the existing Machines as values and the name of their owner -// no matter of being machineSet or MachineDeployment. If a Machine has a ownerReference the key(owner) -// will be the MachineSet if not the key will be the name of the MachineDeployment which is stored as -// a label. We assume that there is no MachineDeployment and MachineSet with the same names. -func getExistingMachinesMap(ctx context.Context, c client.Client, namespace string) (map[string][]machinev1alpha1.Machine, error) { - existingMachines := &machinev1alpha1.MachineList{} - if err := c.List(ctx, existingMachines, client.InNamespace(namespace)); err != nil { - return nil, err - } - - // We temporarily filter out machines without provider ID or node label (VMs which got created but not yet joined the cluster) - // to prevent unnecessarily persisting them in the Worker state. - // TODO: Remove this again once machine-controller-manager supports backing off creation/deletion of failed machines, see - // https://github.com/gardener/machine-controller-manager/issues/483. - var filteredMachines []machinev1alpha1.Machine - for _, machine := range existingMachines.Items { - if _, ok := machine.Labels["node"]; ok || machine.Spec.ProviderID != "" { - filteredMachines = append(filteredMachines, machine) - } - } - - // When we read from the cache we get unsorted results, hence, we sort to prevent unnecessary state updates from happening. - slices.SortFunc(filteredMachines, func(a, b machinev1alpha1.Machine) int { - return cmp.Compare(a.Name, b.Name) - }) - - return extensionsworkerhelper.BuildOwnerToMachinesMap(filteredMachines), nil -} - -func addMachineSetToMachineDeploymentState(machineSets []machinev1alpha1.MachineSet, machineDeploymentState *MachineDeploymentState) { - if len(machineSets) < 1 || machineDeploymentState == nil { - return - } - - // remove redundant data from the machine set - for index := range machineSets { - machineSet := &machineSets[index] - machineSet.ObjectMeta = metav1.ObjectMeta{ - Name: machineSet.Name, - Namespace: machineSet.Namespace, - Annotations: machineSet.Annotations, - Labels: machineSet.Labels, - } - machineSet.OwnerReferences = nil - machineSet.Status = machinev1alpha1.MachineSetStatus{} - } - - machineDeploymentState.MachineSets = machineSets -} - -func addMachineToMachineDeploymentState(machine *machinev1alpha1.Machine, machineDeploymentState *MachineDeploymentState) { - if machine == nil || machineDeploymentState == nil { - return - } - - // remove redundant data from the machine - machine.ObjectMeta = metav1.ObjectMeta{ - Name: machine.Name, - Namespace: machine.Namespace, - Annotations: machine.Annotations, - Labels: machine.Labels, - } - machine.OwnerReferences = nil - machine.Status = machinev1alpha1.MachineStatus{} - - machineDeploymentState.Machines = append(machineDeploymentState.Machines, *machine) -} - -func isWorkerMigrated(worker *extensionsv1alpha1.Worker) bool { - return worker.Status.LastOperation != nil && - worker.Status.LastOperation.Type == gardencorev1beta1.LastOperationTypeMigrate && - worker.Status.LastOperation.State == gardencorev1beta1.LastOperationStateSucceeded -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot.go b/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot.go index 25b787487..ee938be55 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot.go @@ -17,7 +17,7 @@ package util import ( "fmt" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "k8s.io/apimachinery/pkg/version" ) diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot_clients.go b/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot_clients.go index 9570a197b..cb3c8ebbe 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot_clients.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/util/shoot_clients.go @@ -111,7 +111,7 @@ func NewClientForShoot(ctx context.Context, c client.Client, namespace string, o // TODO(ary1992): The new rest mapper implementation doesn't return a NoKindMatchError but a ErrGroupDiscoveryFailed // when an API GroupVersion is not present in the cluster. Remove the old restmapper usage once the upstream issue // (https://github.com/kubernetes-sigs/controller-runtime/pull/2425) is fixed. - mapper, err := thirdpartyapiutil.NewDynamicRESTMapper(shootRESTConfig) + mapper, err := thirdpartyapiutil.NewDynamicRESTMapper(shootRESTConfig, thirdpartyapiutil.WithLazyDiscovery) if err != nil { return nil, nil, fmt.Errorf("failed to create new DynamicRESTMapper: %w", err) } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go index d5d2d1b55..a2b776ca7 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/certificates/reconciler.go @@ -23,6 +23,7 @@ import ( "github.com/go-logr/logr" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/util/workqueue" "k8s.io/utils/clock" "k8s.io/utils/pointer" @@ -79,7 +80,7 @@ type reconciler struct { // URL is the URL that is used to register the webhooks in Kubernetes. URL string - serverPort int + serverPort int32 client client.Client } @@ -92,10 +93,10 @@ func (r *reconciler) AddToManager(ctx context.Context, mgr manager.Manager) erro return fmt.Errorf("expected *webhook.DefaultServer, got %T", webhookServer) } - r.serverPort = defaultServer.Options.Port + r.serverPort = int32(defaultServer.Options.Port) r.client = mgr.GetClient() - present, err := isWebhookServerSecretPresent(ctx, mgr.GetAPIReader(), r.ServerSecretName, r.Namespace, r.Identity) + present, err := isWebhookServerSecretPresent(ctx, mgr.GetAPIReader(), mgr.GetScheme(), r.ServerSecretName, r.Namespace, r.Identity) if err != nil { return err } @@ -193,7 +194,7 @@ func (r *reconciler) Reconcile(ctx context.Context, _ reconcile.Request) (reconc r.AtomicShootWebhookConfig.Store(r.ShootWebhookConfig.DeepCopy()) // reconcile all shoot webhook configs with the freshly created CA bundle - if err := extensionsshootwebhook.ReconcileWebhooksForAllNamespaces(ctx, r.client, r.Namespace, r.ComponentName, r.ShootWebhookManagedResourceName, r.ShootNamespaceSelector, r.serverPort, r.ShootWebhookConfig); err != nil { + if err := extensionsshootwebhook.ReconcileWebhooksForAllNamespaces(ctx, r.client, r.Namespace, r.ComponentName, r.ShootWebhookManagedResourceName, r.ShootNamespaceSelector, r.ShootWebhookConfig); err != nil { return reconcile.Result{}, fmt.Errorf("error reconciling all shoot webhook configs: %w", err) } log.Info("Updated all shoot webhook configs with new CA bundle", "webhookConfig", r.ShootWebhookConfig) @@ -220,8 +221,8 @@ func (r *reconciler) reconcileSourceWebhookConfig(ctx context.Context, sourceWeb return r.client.Patch(ctx, config, patch) } -func isWebhookServerSecretPresent(ctx context.Context, c client.Reader, secretName, namespace, identity string) (bool, error) { - return kubernetesutils.ResourcesExist(ctx, c, corev1.SchemeGroupVersion.WithKind("SecretList"), client.InNamespace(namespace), client.MatchingLabels{ +func isWebhookServerSecretPresent(ctx context.Context, c client.Reader, scheme *runtime.Scheme, secretName, namespace, identity string) (bool, error) { + return kubernetesutils.ResourcesExist(ctx, c, &corev1.SecretList{}, scheme, client.InNamespace(namespace), client.MatchingLabels{ secretsmanager.LabelKeyName: secretName, secretsmanager.LabelKeyManagedBy: secretsmanager.LabelValueSecretsManager, secretsmanager.LabelKeyManagerIdentity: identity, diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/cmd/options.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/cmd/options.go index 175a2e0ae..972f94303 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/cmd/options.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/cmd/options.go @@ -363,13 +363,7 @@ func (c *AddToManagerConfig) reconcileShootWebhookConfigs(mgr manager.Manager, s return err } - webhookServer := mgr.GetWebhookServer() - defaultServer, ok := webhookServer.(*webhook.DefaultServer) - if !ok { - return fmt.Errorf("expected *webhook.DefaultServer, got %T", webhookServer) - } - - if err := extensionsshootwebhook.ReconcileWebhooksForAllNamespaces(ctx, mgr.GetClient(), c.Server.Namespace, c.extensionName, c.shootWebhookManagedResourceName, c.shootNamespaceSelector, defaultServer.Options.Port, shootWebhookConfig); err != nil { + if err := extensionsshootwebhook.ReconcileWebhooksForAllNamespaces(ctx, mgr.GetClient(), c.Server.Namespace, c.extensionName, c.shootWebhookManagedResourceName, c.shootNamespaceSelector, shootWebhookConfig); err != nil { return fmt.Errorf("error reconciling all shoot webhook configs: %w", err) } } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/mutator.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/mutator.go index b82e0561e..8f816a414 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/mutator.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/mutator.go @@ -19,7 +19,7 @@ import ( "errors" "fmt" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "github.com/coreos/go-systemd/v22/unit" druidv1alpha1 "github.com/gardener/etcd-druid/api/v1alpha1" "github.com/go-logr/logr" @@ -246,6 +246,12 @@ func findFileWithPath(osc *extensionsv1alpha1.OperatingSystemConfig, path string if f := extensionswebhook.FileWithPath(osc.Spec.Files, path); f != nil { return f.Content.Inline } + + for _, unit := range osc.Spec.Units { + if f := extensionswebhook.FileWithPath(unit.Files, path); f != nil { + return f.Content.Inline + } + } } return nil diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/noopensurer.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/noopensurer.go index b289dafa3..0f2da7ada 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/noopensurer.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/controlplane/genericmutator/noopensurer.go @@ -17,7 +17,7 @@ package genericmutator import ( "context" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "github.com/coreos/go-systemd/v22/unit" druidv1alpha1 "github.com/gardener/etcd-druid/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" @@ -35,81 +35,81 @@ type NoopEnsurer struct{} var _ Ensurer = &NoopEnsurer{} // EnsureKubeAPIServerService ensures that the kube-apiserver service conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeAPIServerService(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *corev1.Service) error { +func (e *NoopEnsurer) EnsureKubeAPIServerService(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *corev1.Service) error { return nil } // EnsureKubeAPIServerDeployment ensures that the kube-apiserver deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeAPIServerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureKubeAPIServerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureKubeControllerManagerDeployment ensures that the kube-controller-manager deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeControllerManagerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureKubeControllerManagerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureKubeSchedulerDeployment ensures that the kube-scheduler deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeSchedulerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureKubeSchedulerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureMachineControllerManagerDeployment ensures that the machine-controller-manager deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureMachineControllerManagerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureMachineControllerManagerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureMachineControllerManagerVPA ensures that the machine-controller-manager deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureMachineControllerManagerVPA(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *vpaautoscalingv1.VerticalPodAutoscaler) error { +func (e *NoopEnsurer) EnsureMachineControllerManagerVPA(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *vpaautoscalingv1.VerticalPodAutoscaler) error { return nil } // EnsureClusterAutoscalerDeployment ensures that the cluster-autoscaler deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureClusterAutoscalerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureClusterAutoscalerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureETCD ensures that the etcd stateful sets conform to the provider requirements. -func (e *NoopEnsurer) EnsureETCD(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *druidv1alpha1.Etcd) error { +func (e *NoopEnsurer) EnsureETCD(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *druidv1alpha1.Etcd) error { return nil } // EnsureVPNSeedServerDeployment ensures that the vpn-seed-server deployment conforms to the provider requirements. -func (e *NoopEnsurer) EnsureVPNSeedServerDeployment(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *appsv1.Deployment) error { +func (e *NoopEnsurer) EnsureVPNSeedServerDeployment(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *appsv1.Deployment) error { return nil } // EnsureKubeletServiceUnitOptions ensures that the kubelet.service unit options conform to the provider requirements. -func (e *NoopEnsurer) EnsureKubeletServiceUnitOptions(ctx context.Context, gctx extensionscontextwebhook.GardenContext, kubeletVersion *semver.Version, new, old []*unit.UnitOption) ([]*unit.UnitOption, error) { +func (e *NoopEnsurer) EnsureKubeletServiceUnitOptions(_ context.Context, _ extensionscontextwebhook.GardenContext, _ *semver.Version, new, _ []*unit.UnitOption) ([]*unit.UnitOption, error) { return new, nil } // EnsureKubeletConfiguration ensures that the kubelet configuration conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeletConfiguration(ctx context.Context, gctx extensionscontextwebhook.GardenContext, kubeletVersion *semver.Version, new, old *kubeletconfigv1beta1.KubeletConfiguration) error { +func (e *NoopEnsurer) EnsureKubeletConfiguration(_ context.Context, _ extensionscontextwebhook.GardenContext, _ *semver.Version, _, _ *kubeletconfigv1beta1.KubeletConfiguration) error { return nil } // ShouldProvisionKubeletCloudProviderConfig returns if the cloud provider config file should be added to the kubelet configuration. -func (e *NoopEnsurer) ShouldProvisionKubeletCloudProviderConfig(ctx context.Context, gctx extensionscontextwebhook.GardenContext, kubeletVersion *semver.Version) bool { +func (e *NoopEnsurer) ShouldProvisionKubeletCloudProviderConfig(_ context.Context, _ extensionscontextwebhook.GardenContext, _ *semver.Version) bool { return false } // EnsureKubeletCloudProviderConfig ensures that the cloud provider config file conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubeletCloudProviderConfig(ctx context.Context, gctx extensionscontextwebhook.GardenContext, kubeletVersion *semver.Version, configContent *string, namespace string) error { +func (e *NoopEnsurer) EnsureKubeletCloudProviderConfig(_ context.Context, _ extensionscontextwebhook.GardenContext, _ *semver.Version, _ *string, _ string) error { return nil } // EnsureKubernetesGeneralConfiguration ensures that the kubernetes general configuration conforms to the provider requirements. -func (e *NoopEnsurer) EnsureKubernetesGeneralConfiguration(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *string) error { +func (e *NoopEnsurer) EnsureKubernetesGeneralConfiguration(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *string) error { return nil } // EnsureAdditionalUnits ensures that additional required system units are added. -func (e *NoopEnsurer) EnsureAdditionalUnits(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *[]extensionsv1alpha1.Unit) error { +func (e *NoopEnsurer) EnsureAdditionalUnits(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *[]extensionsv1alpha1.Unit) error { return nil } // EnsureAdditionalFiles ensures that additional required system files are added. -func (e *NoopEnsurer) EnsureAdditionalFiles(ctx context.Context, gctx extensionscontextwebhook.GardenContext, new, old *[]extensionsv1alpha1.File) error { +func (e *NoopEnsurer) EnsureAdditionalFiles(_ context.Context, _ extensionscontextwebhook.GardenContext, _, _ *[]extensionsv1alpha1.File) error { return nil } diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go deleted file mode 100644 index 58997c0c0..000000000 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/networkpolicy.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shoot - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" - "github.com/gardener/gardener/pkg/controllerutils" - "github.com/gardener/gardener/pkg/utils" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" -) - -// GetNetworkPolicyMeta returns the network policy object with filled metadata. -func GetNetworkPolicyMeta(shootNamespace, extensionName string) *networkingv1.NetworkPolicy { - return &networkingv1.NetworkPolicy{ObjectMeta: kubernetesutils.ObjectMeta(shootNamespace, "gardener-extension-"+extensionName)} -} - -// EnsureEgressNetworkPolicy ensures that the required egress network policy is installed that allows the kube-apiserver -// running in the given shoot namespace to talk to the extension webhook. -// Deprecated: This function is deprecated and will be removed after Gardener v1.80 has been released. Extensions should -// make sure that they can be accessed via the 'all-webhook-targets' alias. -// TODO(rfranzke): Drop this after v1.80 has been released. -func EnsureEgressNetworkPolicy(ctx context.Context, c client.Client, shootNamespace, extensionNamespace, extensionName string, port int) error { - networkPolicy := GetNetworkPolicyMeta(shootNamespace, extensionName) - _, err := controllerutils.GetAndCreateOrMergePatch(ctx, c, networkPolicy, func() error { - networkPolicy.Spec = networkingv1.NetworkPolicySpec{ - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}, - Egress: []networkingv1.NetworkPolicyEgressRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Port: utils.IntStrPtrFromInt(port), - Protocol: utils.ProtocolPtr(corev1.ProtocolTCP), - }, - }, - To: []networkingv1.NetworkPolicyPeer{ - { - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - corev1.LabelMetadataName: extensionNamespace, - }, - }, - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": "gardener-extension-" + extensionName, - }, - }, - }, - }, - }, - }, - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.LabelApp: v1beta1constants.LabelKubernetes, - v1beta1constants.LabelRole: v1beta1constants.LabelAPIServer, - }, - }, - } - return nil - }) - return err -} - -// EnsureIngressNetworkPolicy ensures that the required ingress network policy is installed that allows the -// kube-apiservers of shoot namespaces to talk to the extension webhook. -// Deprecated: This function is deprecated and will be removed after Gardener v1.80 has been released. Extensions should -// make sure that they can be accessed via the 'all-webhook-targets' alias. -// TODO(rfranzke): Drop this after v1.80 has been released. -func EnsureIngressNetworkPolicy(ctx context.Context, c client.Client, extensionNamespace, extensionName string, port int) error { - networkPolicy := &networkingv1.NetworkPolicy{ObjectMeta: metav1.ObjectMeta{Namespace: extensionNamespace, Name: "ingress-from-all-shoots-kube-apiserver"}} - _, err := controllerutils.GetAndCreateOrMergePatch(ctx, c, networkPolicy, func() error { - networkPolicy.Spec = networkingv1.NetworkPolicySpec{ - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress}, - Ingress: []networkingv1.NetworkPolicyIngressRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Port: utils.IntStrPtrFromInt(port), - Protocol: utils.ProtocolPtr(corev1.ProtocolTCP), - }, - }, - From: []networkingv1.NetworkPolicyPeer{ - { - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.GardenRole: v1beta1constants.GardenRoleShoot, - }, - }, - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - v1beta1constants.LabelApp: v1beta1constants.LabelKubernetes, - v1beta1constants.LabelRole: v1beta1constants.LabelAPIServer, - }, - }, - }, - }, - }, - }, - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": "gardener-extension-" + extensionName, - }, - }, - } - return nil - }) - return err -} diff --git a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go index 6bfb81f2c..ad0b3b70d 100644 --- a/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go +++ b/vendor/github.com/gardener/gardener/extensions/pkg/webhook/shoot/webhook.go @@ -21,16 +21,17 @@ import ( admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gardener/gardener/extensions/pkg/controller" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" + resourcesv1alpha1 "github.com/gardener/gardener/pkg/apis/resources/v1alpha1" "github.com/gardener/gardener/pkg/client/kubernetes" "github.com/gardener/gardener/pkg/extensions" "github.com/gardener/gardener/pkg/utils" "github.com/gardener/gardener/pkg/utils/flow" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" "github.com/gardener/gardener/pkg/utils/managedresources" ) @@ -43,18 +44,23 @@ func ReconcileWebhookConfig( extensionNamespace string, extensionName string, managedResourceName string, - serverPort int, shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, cluster *controller.Cluster, ) error { - if err := EnsureEgressNetworkPolicy(ctx, c, shootNamespace, extensionNamespace, extensionName, serverPort); err != nil { - return fmt.Errorf("could not create or update network policy for shoot webhooks in namespace '%s': %w", shootNamespace, err) - } - if cluster.Shoot == nil { return fmt.Errorf("no shoot found in cluster resource") } + // TODO(rfranzke): Remove this after Gardener v1.86 has been released. + { + if err := c.Delete(ctx, &networkingv1.NetworkPolicy{ObjectMeta: metav1.ObjectMeta{Namespace: shootNamespace, Name: "gardener-extension-" + extensionName}}); client.IgnoreNotFound(err) != nil { + return fmt.Errorf("could not delete old egress network policy for shoot webhooks in namespace '%s': %w", shootNamespace, err) + } + if err := c.Delete(ctx, &networkingv1.NetworkPolicy{ObjectMeta: metav1.ObjectMeta{Namespace: extensionNamespace, Name: "ingress-from-all-shoots-kube-apiserver"}}); client.IgnoreNotFound(err) != nil { + return fmt.Errorf("could not delete old ingress network policy for shoot webhooks in namespace '%s': %w", extensionNamespace, err) + } + } + data, err := managedresources. NewRegistry(kubernetes.ShootScheme, kubernetes.ShootCodec, kubernetes.ShootSerializer). AddAllAndSerialize(shootWebhookConfig) @@ -79,7 +85,6 @@ func ReconcileWebhooksForAllNamespaces( extensionName string, managedResourceName string, shootNamespaceSelector map[string]string, - port int, shootWebhookConfig *admissionregistrationv1.MutatingWebhookConfiguration, ) error { namespaceList := &corev1.NamespaceList{} @@ -91,23 +96,17 @@ func ReconcileWebhooksForAllNamespaces( fns := make([]flow.TaskFn, 0, len(namespaceList.Items)+1) - fns = append(fns, func(ctx context.Context) error { - return EnsureIngressNetworkPolicy(ctx, c, extensionNamespace, extensionName, port) - }) - for _, namespace := range namespaceList.Items { - var ( - networkPolicy = GetNetworkPolicyMeta(namespace.Name, extensionName) - namespaceName = namespace.Name - networkPolicyName = networkPolicy.Name - ) + namespaceName := namespace.Name fns = append(fns, func(ctx context.Context) error { - if err := c.Get(ctx, kubernetesutils.Key(namespaceName, networkPolicyName), &networkingv1.NetworkPolicy{}); err != nil { - if !errors.IsNotFound(err) { - return err + managedResource := &metav1.PartialObjectMetadata{} + managedResource.SetGroupVersionKind(resourcesv1alpha1.SchemeGroupVersion.WithKind("ManagedResource")) + if err := c.Get(ctx, client.ObjectKey{Name: managedResourceName, Namespace: namespaceName}, managedResource); err != nil { + if apierrors.IsNotFound(err) { + return nil } - return nil + return err } cluster, err := extensions.GetCluster(ctx, c, namespaceName) @@ -115,7 +114,7 @@ func ReconcileWebhooksForAllNamespaces( return err } - return ReconcileWebhookConfig(ctx, c, namespaceName, extensionNamespace, extensionName, managedResourceName, port, shootWebhookConfig.DeepCopy(), cluster) + return ReconcileWebhookConfig(ctx, c, namespaceName, extensionNamespace, extensionName, managedResourceName, shootWebhookConfig.DeepCopy(), cluster) }) } diff --git a/vendor/github.com/gardener/gardener/hack/check-docforge.sh b/vendor/github.com/gardener/gardener/hack/check-docforge.sh deleted file mode 100755 index 8186f74a8..000000000 --- a/vendor/github.com/gardener/gardener/hack/check-docforge.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -docCommitHash="fa2e9f84851be81e85668986675db235bb43a6b5" - -echo "> Check Docforge Manifest" -repoPath=${1-"$(readlink -f "$(dirname "${0}")/..")"} -manifestPath=${2-"${repoPath}/.docforge/manifest.yaml"} -diffDirs=${3-".docforge/;docs/"} -repoName=${4-"gardener"} -useToken=${5-false} - -tmpDir=$(mktemp -d) -function cleanup { - rm -rf "$tmpDir" -} -trap cleanup EXIT ERR INT TERM - -curl https://raw.githubusercontent.com/gardener/documentation/${docCommitHash}/.ci/check-manifest --output "${tmpDir}/check-manifest-script.sh" && chmod +x "${tmpDir}/check-manifest-script.sh" -curl https://raw.githubusercontent.com/gardener/documentation/${docCommitHash}/.ci/check-manifest-config --output "${tmpDir}/manifest-config" -scriptPath="${tmpDir}/check-manifest-script.sh" -configPath="${tmpDir}/manifest-config" - -${scriptPath} --repo-path "${repoPath}" --repo-name "${repoName}" --use-token "${useToken}" --manifest-path "${manifestPath}" --diff-dirs "${diffDirs}" --config-path "${configPath}" diff --git a/vendor/github.com/gardener/gardener/hack/check-skaffold-deps-for-binary.sh b/vendor/github.com/gardener/gardener/hack/check-skaffold-deps-for-binary.sh new file mode 100755 index 000000000..5b24d93c0 --- /dev/null +++ b/vendor/github.com/gardener/gardener/hack/check-skaffold-deps-for-binary.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# +# Copyright 2023 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +skaffold_file="" +binary_name="" +skaffold_config_name="" + +parse_flags() { + while test $# -gt 0; do + case "$1" in + --skaffold-file) + shift; skaffold_file="$1" + ;; + --binary) + shift; binary_name="$1" + ;; + --skaffold-config) + shift; skaffold_config_name="$1" + ;; + *) + echo "Unknown argument: $1" + exit 1 + ;; + esac + shift + done +} + +parse_flags "$@" + +out_dir=$(mktemp -d) +function cleanup_output { + rm -rf "$out_dir" +} +trap cleanup_output EXIT + +repo_root="$(git rev-parse --show-toplevel)" +skaffold_yaml="$(cat "$repo_root/$skaffold_file")" + +path_current_skaffold_dependencies="${out_dir}/current-$skaffold_file-deps-$binary_name.txt" +path_actual_dependencies="${out_dir}/actual-$skaffold_file-deps-$binary_name.txt" + +echo "$skaffold_yaml" |\ + yq eval "select(.metadata.name == \"$skaffold_config_name\") | .build.artifacts[] | select(.ko.main == \"./cmd/$binary_name\") | .ko.dependencies.paths[]?" - |\ + sort |\ + uniq > "$path_current_skaffold_dependencies" + +module_name=$(go list -m) +module_prefix="$module_name/" +go list -f '{{ join .Deps "\n" }}' "./cmd/$binary_name" |\ + grep "$module_prefix" |\ + sed "s@$module_prefix@@g" |\ + sort |\ + uniq > "$path_actual_dependencies" + +# always add vendor directory and VERSION file +echo "vendor" >> "$path_actual_dependencies" +echo "VERSION" >> "$path_actual_dependencies" + +# sort dependencies +sort -o $path_current_skaffold_dependencies{,} +sort -o $path_actual_dependencies{,} + +echo -n ">> Checking defined dependencies in Skaffold config '$skaffold_config_name' for '$binary_name' in '$skaffold_file'..." +if ! diff="$(diff "$path_current_skaffold_dependencies" "$path_actual_dependencies")"; then + echo + echo ">>> The following actual dependencies are missing in $skaffold_file (need to be added):" + echo "$diff" | grep '>' | awk '{print $2}' + echo + echo ">>> The following dependencies defined in $skaffold_file are not needed actually (need to be removed):" + echo "$diff" | grep '<' | awk '{print $2}' + echo + + exit 1 +else + echo " success." +fi diff --git a/vendor/github.com/gardener/gardener/hack/check-skaffold-deps.sh b/vendor/github.com/gardener/gardener/hack/check-skaffold-deps.sh index ecdaf774a..03411ada4 100755 --- a/vendor/github.com/gardener/gardener/hack/check-skaffold-deps.sh +++ b/vendor/github.com/gardener/gardener/hack/check-skaffold-deps.sh @@ -19,55 +19,11 @@ set -e echo "> Check Skaffold Dependencies" check_successful=true - -out_dir=$(mktemp -d) -function cleanup_output { - rm -rf "$out_dir" -} -trap cleanup_output EXIT +repo_root="$(git rev-parse --show-toplevel)" function check() { - skaffold_file="$1" - binary_name="$2" - skaffold_config_name="$3" - - skaffold_yaml="$(cat "$(dirname "$0")/../$skaffold_file")" - - path_current_skaffold_dependencies="${out_dir}/current-$skaffold_file-deps-$binary_name.txt" - path_actual_dependencies="${out_dir}/actual-$skaffold_file-deps-$binary_name.txt" - - echo "$skaffold_yaml" |\ - yq eval "select(.metadata.name == \"$skaffold_config_name\") | .build.artifacts[] | select(.ko.main == \"./cmd/$binary_name\") | .ko.dependencies.paths[]?" - |\ - sort |\ - uniq > "$path_current_skaffold_dependencies" - - go list -f '{{ join .Deps "\n" }}' "./cmd/$binary_name" |\ - grep "github.com/gardener/gardener/" |\ - sed 's/github\.com\/gardener\/gardener\///g' |\ - sort |\ - uniq > "$path_actual_dependencies" - - # always add vendor directory and VERSION file - echo "vendor" >> "$path_actual_dependencies" - echo "VERSION" >> "$path_actual_dependencies" - - # sort dependencies - sort -o $path_current_skaffold_dependencies{,} - sort -o $path_actual_dependencies{,} - - echo -n ">> Checking defined dependencies in Skaffold config '$skaffold_config_name' for '$binary_name' in '$skaffold_file'..." - if ! diff="$(diff "$path_current_skaffold_dependencies" "$path_actual_dependencies")"; then + if ! $repo_root/hack/check-skaffold-deps-for-binary.sh --skaffold-file $1 --binary $2 --skaffold-config $3; then check_successful=false - - echo - echo ">>> The following actual dependencies are missing in $skaffold_file (need to be added):" - echo "$diff" | grep '>' | awk '{print $2}' - echo - echo ">>> The following dependencies defined in $skaffold_file are not needed actually (need to be removed):" - echo "$diff" | grep '<' | awk '{print $2}' - echo - else - echo " success." fi } diff --git a/vendor/github.com/gardener/gardener/hack/compare-k8s-admission-plugins.sh b/vendor/github.com/gardener/gardener/hack/compare-k8s-admission-plugins.sh index 93e39d7f8..f07380f1c 100755 --- a/vendor/github.com/gardener/gardener/hack/compare-k8s-admission-plugins.sh +++ b/vendor/github.com/gardener/gardener/hack/compare-k8s-admission-plugins.sh @@ -20,7 +20,7 @@ usage() { echo "Usage:" echo "> compare-k8s-admission-plugins.sh [ -h | ]" echo - echo ">> For example: compare-k8s-admission-plugins.sh 1.22 1.23" + echo ">> For example: compare-k8s-admission-plugins.sh 1.26 1.27" exit 0 } diff --git a/vendor/github.com/gardener/gardener/hack/compare-k8s-api-groups.sh b/vendor/github.com/gardener/gardener/hack/compare-k8s-api-groups.sh new file mode 100755 index 000000000..59b0818cf --- /dev/null +++ b/vendor/github.com/gardener/gardener/hack/compare-k8s-api-groups.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +# +# Copyright 2023 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +usage() { + echo "Usage:" + echo "> compare-k8s-apigroups.sh [ -h | ]" + echo + echo ">> For example: compare-k8s-apigroups.sh 1.26 1.27" + + exit 0 +} + +if [ "$1" == "-h" ] || [ "$#" -ne 2 ]; then + usage +fi + +versions=("$1" "$2") + +out_dir=$(mktemp -d) +function cleanup_output { + rm -rf "$out_dir" +} +trap cleanup_output EXIT + +base_dir="staging/src/k8s.io/client-go/informers" + +for version in "${versions[@]}"; do + rm -rf "${out_dir}/kubernetes-${version}" + rm -f "${out_dir}/k8s-apiGVRs-${version}.txt" + rm -f "${out_dir}/k8s-apiGVs-${version}.txt" + + git clone --depth 1 --filter=blob:none --sparse https://github.com/kubernetes/kubernetes -b "release-${version}" "${out_dir}/kubernetes-${version}" + pushd "${out_dir}/kubernetes-${version}" > /dev/null + git sparse-checkout set "$base_dir" + popd > /dev/null + + groupVersions=() + groupVersionResources=() + g="" + v="" + + while IFS= read -r line; do + if [[ $line =~ Group=([a-zA-Z0-9.-]+),[[:space:]]*Version=([a-zA-Z0-9.-]+) ]]; then + g="${BASH_REMATCH[1]}" + v="${BASH_REMATCH[2]}" + if [[ $g == "core" ]]; then + groupVersions+=("$v") + else + groupVersions+=("$g/$v") + fi + elif [[ $line =~ WithResource\(\"(.*)\"\) ]]; then + k="${BASH_REMATCH[1]}" + if [[ $g == "core" ]]; then + groupVersionResources+=("$v/$k") + else + groupVersionResources+=("$g/$v/$k") + fi + fi + done < "${out_dir}/kubernetes-${version}/${base_dir}/generic.go" + + echo "${groupVersions[@]}" | tr ' ' '\n' | sort | uniq > "${out_dir}/k8s-apiGVs-${version}.txt" + echo "${groupVersionResources[@]}" | tr ' ' '\n' | sort | uniq > "${out_dir}/k8s-apiGVRs-${version}.txt" +done + +echo +echo "Kubernetes API group versions added in $2 compared to $1:" +diff "${out_dir}/k8s-apiGVs-$1.txt" "${out_dir}/k8s-apiGVs-$2.txt" | grep '>' | awk '{print $2}' +echo +echo "Kubernetes API GVRs added in $2 compared to $1:" +diff "${out_dir}/k8s-apiGVRs-$1.txt" "${out_dir}/k8s-apiGVRs-$2.txt" | grep '>' | awk '{print $2}' +echo +echo "Kubernetes API group versions removed in $2 compared to $1:" +diff "${out_dir}/k8s-apiGVs-$1.txt" "${out_dir}/k8s-apiGVs-$2.txt" | grep '<' | awk '{print $2}' +echo +echo "Kubernetes API GVRs removed in $2 compared to $1:" \ No newline at end of file diff --git a/vendor/github.com/gardener/gardener/hack/compare-k8s-controllers.sh b/vendor/github.com/gardener/gardener/hack/compare-k8s-controllers.sh index 3378aade2..9f345e21a 100755 --- a/vendor/github.com/gardener/gardener/hack/compare-k8s-controllers.sh +++ b/vendor/github.com/gardener/gardener/hack/compare-k8s-controllers.sh @@ -20,7 +20,7 @@ usage() { echo "Usage:" echo "> compare-k8s-controllers.sh [ -h | ]" echo - echo ">> For example: compare-k8s-controllers.sh 1.22 1.23" + echo ">> For example: compare-k8s-controllers.sh 1.26 1.27" exit 0 } @@ -49,7 +49,7 @@ for version in "${versions[@]}"; do git sparse-checkout set "$kcm_dir" "$ccm_dir" popd > /dev/null - for dir in $kcm_dir $ccm_dir; do + for dir in $kcm_dir; do cat "${out_dir}/kubernetes-${version}/$dir/"*.go |\ sed -rn "s/.*[Client|Config]OrDie\(\"(.*)\"\).*/\1/p" |\ grep -vE "informers|discovery" |\ @@ -57,7 +57,6 @@ for version in "${versions[@]}"; do uniq >> "${out_dir}/k8s-controllers-${version}.txt" done - # Starting with release-v1.23 the names for the CCM controllers are maintained differently. cat "${out_dir}/kubernetes-${version}/$ccm_dir/controllermanager.go" |\ sed -rn "s/.*ClientName: \"(.*)\",.*/\1/p" |\ sort |\ diff --git a/vendor/github.com/gardener/gardener/hack/compare-k8s-feature-gates.sh b/vendor/github.com/gardener/gardener/hack/compare-k8s-feature-gates.sh index 1770ae507..fa4e957b1 100755 --- a/vendor/github.com/gardener/gardener/hack/compare-k8s-feature-gates.sh +++ b/vendor/github.com/gardener/gardener/hack/compare-k8s-feature-gates.sh @@ -20,7 +20,7 @@ usage() { echo "Usage:" echo "> compare-k8s-feature-gates.sh [ -h | ]" echo - echo ">> For example: compare-k8s-feature-gates.sh 1.22 1.23" + echo ">> For example: compare-k8s-feature-gates.sh 1.26 1.27" exit 0 } diff --git a/vendor/github.com/gardener/gardener/hack/gardener-extensions-down.sh b/vendor/github.com/gardener/gardener/hack/gardener-extensions-down.sh index d7b16579f..55e79052c 100755 --- a/vendor/github.com/gardener/gardener/hack/gardener-extensions-down.sh +++ b/vendor/github.com/gardener/gardener/hack/gardener-extensions-down.sh @@ -60,10 +60,11 @@ if [[ "$remaining_seeds" != "" ]]; then echo "No clean up of kind cluster because of remaining seeds: ${remaining_seeds//$'\n'/,}" else echo "Cleaning up admission controllers" - "$SCRIPT_DIR"/../example/provider-extensions/garden/configure-admission.sh "$PATH_GARDEN_KUBECONFIG" delete + "$SCRIPT_DIR"/../example/provider-extensions/garden/configure-admission.sh "$PATH_GARDEN_KUBECONFIG" delete --ignore-not-found echo "Cleaning up kind cluster" kubectl --kubeconfig="$PATH_GARDEN_KUBECONFIG" delete validatingwebhookconfiguration/gardener-admission-controller --ignore-not-found - kubectl --kubeconfig="$PATH_GARDEN_KUBECONFIG" annotate project local garden confirmation.gardener.cloud/deletion=true + kubectl --kubeconfig="$PATH_GARDEN_KUBECONFIG" annotate project garden confirmation.gardener.cloud/deletion=true + kubectl --kubeconfig="$PATH_GARDEN_KUBECONFIG" annotate -f "$SCRIPT_DIR"/../example/provider-extensions/garden/project/project.yaml confirmation.gardener.cloud/deletion=true skaffold --kubeconfig="$PATH_GARDEN_KUBECONFIG" delete -m extensions-env -p extensions skaffold --kubeconfig="$PATH_GARDEN_KUBECONFIG" delete -m etcd,controlplane -p extensions kubectl --kubeconfig="$PATH_GARDEN_KUBECONFIG" delete ns garden gardener-system-seed-lease --ignore-not-found diff --git a/vendor/github.com/gardener/gardener/hack/generate-crds.sh b/vendor/github.com/gardener/gardener/hack/generate-crds.sh index b119d9a4c..3b3f30b45 100755 --- a/vendor/github.com/gardener/gardener/hack/generate-crds.sh +++ b/vendor/github.com/gardener/gardener/hack/generate-crds.sh @@ -19,13 +19,16 @@ set -o nounset set -o pipefail # Usage: -# generate-crds.sh [ ...] +# generate-crds.sh [] [ ...] # Generate manifests for all CRDs to the current working directory. # Useful for development purposes. # -# File name prefix for manifest files (e.g. '10-crd-') -# -l (Optional) If -l argument is given then the generated CRDs will have label gardener.cloud/deletion-protected: "true" -# List of groups to generate (generate all if unset) +# -p File name prefix for manifest files (e.g. '10-crd-') +# -l (Optional) If this argument is given then the generated CRDs will have label gardener.cloud/deletion-protected: "true" +# -k (Optional) If this argument is given then the generated CRDs will have annotation resources.gardener.cloud/keep-object: "true" +# -r (Optional) If this argument is given then the generated CRDs will have annotation api-approved.kubernetes.io: "" +# --allow-dangerous-types (Optional) If this argument is given then the CRD generation will tolerate issues related to dangerous types. +# List of groups to generate (generate all if unset) if ! command -v controller-gen &> /dev/null ; then >&2 echo "controller-gen not available" @@ -33,8 +36,10 @@ if ! command -v controller-gen &> /dev/null ; then fi output_dir="$(pwd)" -file_name_prefix="$1" +output_dir_temp="$(mktemp -d)" add_deletion_protection_label=false +add_keep_object_annotation=false +k8s_io_api_approval_reason="unapproved, temporarily squatting" crd_options="" get_group_package () { @@ -51,12 +56,18 @@ get_group_package () { "druid.gardener.cloud") echo "github.com/gardener/etcd-druid/api/v1alpha1" ;; - "autoscaling.k8s.io") + "hvpaautoscaling.k8s.io") echo "github.com/gardener/hvpa-controller/api/v1alpha1" ;; "fluentbit.fluent.io") echo "github.com/fluent/fluent-operator/v2/apis/fluentbit/v1alpha2" ;; + "autoscaling.k8s.io") + echo "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/..." + ;; + "machine.sapcloud.io") + echo "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" + ;; *) >&2 echo "unknown group $1" return 1 @@ -68,8 +79,10 @@ generate_all_groups () { generate_group resources.gardener.cloud generate_group operator.gardener.cloud generate_group druid.gardener.cloud + generate_group hvpaautoscaling.k8s.io generate_group autoscaling.k8s.io generate_group fluentbit.fluent.io + generate_group machine.sapcloud.io } generate_group () { @@ -80,23 +93,36 @@ generate_group () { if [ -z "$package" ] ; then exit 1 fi - local package_path="$(go list -f '{{ .Dir }}' "$package")" + local package_path="$(go list -f '{{ .Dir }}' "$package" | tr '\n' ';')" if [ -z "$package_path" ] ; then exit 1 fi - # clean all generated files for this group to account for changed prefix or removed resources - if ls "$output_dir"/*${group}_*.yaml >/dev/null 2>&1; then - rm "$output_dir"/*${group}_*.yaml - fi + generate="controller-gen crd"$crd_options" paths="$package_path" output:crd:dir="$output_dir_temp" output:stdout" - controller-gen crd"$crd_options" paths="$package_path" output:crd:dir="$output_dir" output:stdout + if [[ "$group" == "druid.gardener.cloud" ]]; then + # /scale subresource is intentionally removed from this CRD, although it is specified in the original CRD from + # etcd-druid, due to adverse interaction with VPA. + # See https://github.com/gardener/gardener/pull/6850 and https://github.com/gardener/gardener/pull/8560#discussion_r1347470394 + # TODO(shreyas-s-rao): Remove this workaround as soon as the scale subresource is supported properly. + etcd_api_types_file="${package_path%;}/types_etcd.go" + sed -i '/\/\/ +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.labelSelector/d' "$etcd_api_types_file" + $generate + git checkout "$etcd_api_types_file" + elif [[ "$group" == "autoscaling.k8s.io" ]]; then + # See https://github.com/kubernetes/autoscaler/blame/master/vertical-pod-autoscaler/hack/generate-crd-yaml.sh#L43-L45 + generator_output="$(mktemp -d)/controller-gen.log" + $generate &> "$generator_output" ||: + grep -v -e 'map keys must be strings, not int' -e 'not all generators ran successfully' -e 'usage' "$generator_output" && { echo "Failed to generate CRD YAMLs."; exit 1; } + else + $generate + fi + local relevant_files=("$@") while IFS= read -r crd; do crd_out="$output_dir/$file_name_prefix$(basename $crd)" - if [ "$crd" != "$crd_out" ]; then - mv "$crd" "$crd_out" - fi + mv "$crd" "$crd_out" + relevant_files+=("$(basename "$crd_out")") if $add_deletion_protection_label; then if grep -q "clusters.extensions.gardener.cloud" "$crd_out"; then @@ -106,42 +132,79 @@ generate_group () { fi fi + if $add_keep_object_annotation; then + sed -i '/^ annotations:.*/a\ resources.gardener.cloud/keep-object: "true"' "$crd_out" + fi + # TODO(plkokanov): this is needed to add the `api-approved.kubernetes.io` annotaiton to resource from the *.k8s.io api group generated by controller-gen # Currently there is an issue open to do that automatically: https://github.com/kubernetes-sigs/controller-tools/issues/656 if [[ ${group} =~ .*\.k8s\.io ]]; then - sed -i '/^ annotations:.*/a\ api-approved.kubernetes.io: unapproved, temporarily squatting' "$crd_out" + sed -i "/^ annotations:.*/a\ api-approved.kubernetes.io: $k8s_io_api_approval_reason" "$crd_out" fi - done < <(ls "$output_dir/${group}"_*.yaml) -} + done < <(ls "$output_dir_temp/${group/hvpa/}"_*.yaml) -if [ -n "${2:-}" ]; then - if [ "${2}" == "-l" ]; then - add_deletion_protection_label=true - if [ -n "${3:-}" ]; then - while [ -n "${3:-}" ] ; do - generate_group "$3" - shift - done - else - generate_all_groups - fi - elif [ "${2}" == "-allow-dangerous-types" ]; then - crd_options=":allowDangerousTypes=true" - if [ -n "${3:-}" ]; then - while [ -n "${3:-}" ] ; do - generate_group "$3" - shift - done - else - generate_all_groups + # garbage collection - clean all generated files for this group to account for changed prefix or removed resources + local pattern=".*${group}_.*\.yaml" + if [[ "$group" == "autoscaling.k8s.io" ]]; then + pattern=".*${group}_v.*\.yaml" + fi + + while IFS= read -r file; do + file_name=$(basename "$file") + delete_no_longer_needed_file=true + + for relevant_file_name in "${relevant_files[@]}"; do + if [[ $file_name == "$relevant_file_name" ]] || [[ ! $file_name =~ $pattern ]]; then + delete_no_longer_needed_file=false + break + fi + done + + if $delete_no_longer_needed_file; then + rm "$file" fi - else - while [ -n "${2:-}" ] ; do - generate_group "$2" + done < <(ls "$output_dir") +} + +parse_flags() { + while test $# -gt 0; do + case "$1" in + -p) + file_name_prefix="$2" shift - done - fi + shift + ;; + -r) + k8s_io_api_approval_reason="$2" + shift + shift + ;; + -l) + add_deletion_protection_label=true + shift + ;; + -k) + add_keep_object_annotation=true + shift + ;; + --allow-dangerous-types) + crd_options=":allowDangerousTypes=true" + shift + ;; + *) + args+=("$1") + shift + ;; + esac + done +} + +parse_flags "$@" + +if [ -n "$args" ]; then + for group in "${args[@]}"; do + generate_group "$group" + done else generate_all_groups fi - diff --git a/vendor/github.com/gardener/gardener/hack/hook-me.sh b/vendor/github.com/gardener/gardener/hack/hook-me.sh index 0bc38f0a8..3d72c55a2 100755 --- a/vendor/github.com/gardener/gardener/hack/hook-me.sh +++ b/vendor/github.com/gardener/gardener/hack/hook-me.sh @@ -257,16 +257,16 @@ extendedKeyUsage = clientAuth EOF # Create a certificate authority - openssl genrsa -out ca.key 2048 + openssl genrsa -out ca.key 3072 openssl req -x509 -new -nodes -key ca.key -days 100000 -out ca.crt -subj "/CN=quic-tunnel-ca" # Create a server certiticate - openssl genrsa -out tls.key 2048 + openssl genrsa -out tls.key 3072 openssl req -new -key tls.key -out server.csr -subj "/CN=quic-tunnel-server" -config server.conf openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out tls.crt -days 100000 -extensions v3_req -extfile server.conf # Create a client certiticate - openssl genrsa -out client.key 2048 + openssl genrsa -out client.key 3072 openssl req -new -key client.key -out client.csr -subj "/CN=quic-tunnel-client" -config client.conf openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 100000 -extensions v3_req -extfile client.conf diff --git a/vendor/github.com/gardener/gardener/hack/kind-up.sh b/vendor/github.com/gardener/gardener/hack/kind-up.sh index e531e5f2b..fdc0fa0a1 100755 --- a/vendor/github.com/gardener/gardener/hack/kind-up.sh +++ b/vendor/github.com/gardener/gardener/hack/kind-up.sh @@ -18,6 +18,7 @@ set -o errexit set -o nounset set -o pipefail +REGISTRY_CACHE=${CI:-false} CLUSTER_NAME="" PATH_CLUSTER_VALUES="" PATH_KUBECONFIG="" @@ -149,6 +150,22 @@ server = "${UPSTREAM_SERVER}" EOF } +check_registry_cache_availability() { + local registry_cache_ip + local registry_cache_dns + if [[ "$REGISTRY_CACHE" != "true" ]]; then + return + fi + echo "Registry-cache enabled. Checking if registry-cache instances are deployed in prow cluster." + for registry_cache_dns in $(kubectl create -k "$(dirname "$0")/../example/gardener-local/registry-prow" --dry-run=client -o yaml | grep kube-system.svc.cluster.local | awk '{ print $2 }' | sed -e "s/^http:\/\///" -e "s/:5000$//"); do + registry_cache_ip=$(getent hosts "$registry_cache_dns" | awk '{ print $1 }') + if [[ "$registry_cache_ip" == "" ]]; then + echo "Unable to resolve IP of $registry_cache_dns in prow cluster. Disabling registry-cache." + REGISTRY_CACHE=false + fi + done +} + parse_flags "$@" mkdir -m 0755 -p \ @@ -171,15 +188,15 @@ fi kind create cluster \ --name "$CLUSTER_NAME" \ - --image "kindest/node:v1.27.3" \ + --image "kindest/node:v1.28.0" \ --config <(helm template $CHART --values "$PATH_CLUSTER_VALUES" $ADDITIONAL_ARGS --set "gardener.repositoryRoot"=$(dirname "$0")/..) # adjust Kind's CRI default OCI runtime spec for new containers to include the cgroup namespace # this is required for nesting kubelets on cgroupsv2, as the kindest-node entrypoint script assumes an existing cgroupns when the host kernel uses cgroupsv2 # See containerd CRI: https://github.com/containerd/containerd/commit/687469d3cee18bf0e12defa5c6d0c7b9139a2dbd -if [ -f "/sys/fs/cgroup/cgroup.controllers" ]; then +if [ -f "/sys/fs/cgroup/cgroup.controllers" ] || [ "$(uname -s)" == "Darwin" ]; then echo "Host uses cgroupsv2" - cat << 'EOF' > adjust_cri_base.sh + cat << 'EOF' > "$(dirname "$0")/../dev/adjust_cri_base.sh" #!/bin/bash if [ -f /etc/containerd/cri-base.json ]; then key=$(cat /etc/containerd/cri-base.json | jq '.linux.namespaces | map(select(.type == "cgroup"))[0]') @@ -201,7 +218,7 @@ EOF echo "Adjusting containerd config for kind node $node_name" # copy script to the kind's docker container and execute it - docker cp adjust_cri_base.sh "$node_name":/etc/containerd/adjust_cri_base.sh + docker cp "$(dirname "$0")/../dev/adjust_cri_base.sh" "$node_name":/etc/containerd/adjust_cri_base.sh docker exec "$node_name" bash -c "chmod +x /etc/containerd/adjust_cri_base.sh && /etc/containerd/adjust_cri_base.sh && systemctl restart containerd" done fi @@ -262,7 +279,14 @@ kubectl -n kube-system get configmap coredns -ojson | \ kubectl -n kube-system rollout restart deployment coredns if [[ "$DEPLOY_REGISTRY" == "true" ]]; then - kubectl apply -k "$(dirname "$0")/../example/gardener-local/registry" --server-side + check_registry_cache_availability + if [[ "$REGISTRY_CACHE" == "true" ]]; then + echo "Deploying local container registries in registry-cache configuration" + kubectl apply -k "$(dirname "$0")/../example/gardener-local/registry-prow" --server-side + else + echo "Deploying local container registries in default configuration" + kubectl apply -k "$(dirname "$0")/../example/gardener-local/registry" --server-side + fi kubectl wait --for=condition=available deployment -l app=registry -n registry --timeout 5m fi kubectl apply -k "$(dirname "$0")/../example/gardener-local/calico/$IPFAMILY" --server-side diff --git a/vendor/github.com/gardener/gardener/hack/prepare-envtest.sh b/vendor/github.com/gardener/gardener/hack/prepare-envtest.sh index 372df31b2..ae2716a38 100755 --- a/vendor/github.com/gardener/gardener/hack/prepare-envtest.sh +++ b/vendor/github.com/gardener/gardener/hack/prepare-envtest.sh @@ -18,7 +18,7 @@ set -o errexit set -o nounset set -o pipefail -ENVTEST_K8S_VERSION=${ENVTEST_K8S_VERSION:-"1.27"} +ENVTEST_K8S_VERSION=${ENVTEST_K8S_VERSION:-"1.28"} echo "> Installing envtest tools@${ENVTEST_K8S_VERSION} with setup-envtest if necessary" if ! command -v setup-envtest &> /dev/null ; then diff --git a/vendor/github.com/gardener/gardener/hack/test-e2e-local.sh b/vendor/github.com/gardener/gardener/hack/test-e2e-local.sh index beb066a07..2d7f6d687 100755 --- a/vendor/github.com/gardener/gardener/hack/test-e2e-local.sh +++ b/vendor/github.com/gardener/gardener/hack/test-e2e-local.sh @@ -29,6 +29,9 @@ ginkgo_flags= if [ -n "${CI:-}" -a -n "${ARTIFACTS:-}" ]; then mkdir -p "$ARTIFACTS" ginkgo_flags="--output-dir=$ARTIFACTS --junit-report=junit.xml" + if [ "${JOB_TYPE:-}" != "periodic" ]; then + ginkgo_flags+=" --fail-fast" + fi fi # If we are not running the gardener-operator tests then we have to make the shoot domains accessible. @@ -53,6 +56,8 @@ if [[ "$1" != "operator" ]]; then e2e-rotate-wl.local e2e-default.local e2e-default-wl.local + e2e-force-delete.local + e2e-fd-hib.local e2e-upd-node.local e2e-upd-node-wl.local e2e-upgrade.local diff --git a/vendor/github.com/gardener/gardener/hack/tools.mk b/vendor/github.com/gardener/gardener/hack/tools.mk index 166cd60cf..e896b4178 100755 --- a/vendor/github.com/gardener/gardener/hack/tools.mk +++ b/vendor/github.com/gardener/gardener/hack/tools.mk @@ -30,7 +30,6 @@ endif TOOLS_BIN_DIR := $(TOOLS_DIR)/bin CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen -DOCFORGE := $(TOOLS_BIN_DIR)/docforge GEN_CRD_API_REFERENCE_DOCS := $(TOOLS_BIN_DIR)/gen-crd-api-reference-docs GINKGO := $(TOOLS_BIN_DIR)/ginkgo GOIMPORTS := $(TOOLS_BIN_DIR)/goimports @@ -58,19 +57,18 @@ YAML2JSON := $(TOOLS_BIN_DIR)/yaml2json YQ := $(TOOLS_BIN_DIR)/yq # default tool versions -DOCFORGE_VERSION ?= v0.34.0 -GOLANGCI_LINT_VERSION ?= v1.54.2 +GOLANGCI_LINT_VERSION ?= v1.55.1 GO_APIDIFF_VERSION ?= v0.6.1 GO_ADD_LICENSE_VERSION ?= v1.1.1 -GOIMPORTSREVISER_VERSION ?= v3.4.5 +GOIMPORTSREVISER_VERSION ?= v3.5.6 GO_VULN_CHECK_VERSION ?= latest -HELM_VERSION ?= v3.12.3 +HELM_VERSION ?= v3.13.1 KIND_VERSION ?= v0.20.0 -KUBECTL_VERSION ?= v1.28.2 -PROMTOOL_VERSION ?= 2.34.0 -PROTOC_VERSION ?= 24.1 -SKAFFOLD_VERSION ?= v2.7.0 -YQ_VERSION ?= v4.35.1 +KUBECTL_VERSION ?= v1.28.3 +PROMTOOL_VERSION ?= 2.47.2 +PROTOC_VERSION ?= 24.4 +SKAFFOLD_VERSION ?= v2.8.0 +YQ_VERSION ?= v4.35.2 # tool versions from go.mod CONTROLLER_GEN_VERSION ?= $(call version_gomod,sigs.k8s.io/controller-tools) @@ -124,7 +122,7 @@ ifeq ($(shell if [ -d $(TOOLS_BIN_SOURCE_DIR) ]; then echo "found"; fi),found) endif .PHONY: create-tools-bin -create-tools-bin: $(CONTROLLER_GEN) $(DOCFORGE) $(GEN_CRD_API_REFERENCE_DOCS) $(GINKGO) $(GOIMPORTS) $(GOIMPORTSREVISER) $(GO_ADD_LICENSE) $(GO_APIDIFF) $(GO_VULN_CHECK) $(GO_TO_PROTOBUF) $(HELM) $(IMPORT_BOSS) $(KIND) $(KUBECTL) $(MOCKGEN) $(OPENAPI_GEN) $(PROMTOOL) $(PROTOC) $(PROTOC_GEN_GOGO) $(SETUP_ENVTEST) $(SKAFFOLD) $(YAML2JSON) $(YQ) +create-tools-bin: $(CONTROLLER_GEN) $(GEN_CRD_API_REFERENCE_DOCS) $(GINKGO) $(GOIMPORTS) $(GOIMPORTSREVISER) $(GO_ADD_LICENSE) $(GO_APIDIFF) $(GO_VULN_CHECK) $(GO_TO_PROTOBUF) $(HELM) $(IMPORT_BOSS) $(KIND) $(KUBECTL) $(MOCKGEN) $(OPENAPI_GEN) $(PROMTOOL) $(PROTOC) $(PROTOC_GEN_GOGO) $(SETUP_ENVTEST) $(SKAFFOLD) $(YAML2JSON) $(YQ) ######################################### # Tools # @@ -133,10 +131,6 @@ create-tools-bin: $(CONTROLLER_GEN) $(DOCFORGE) $(GEN_CRD_API_REFERENCE_DOCS) $( $(CONTROLLER_GEN): $(call tool_version_file,$(CONTROLLER_GEN),$(CONTROLLER_GEN_VERSION)) go build -o $(CONTROLLER_GEN) sigs.k8s.io/controller-tools/cmd/controller-gen -$(DOCFORGE): $(call tool_version_file,$(DOCFORGE),$(DOCFORGE_VERSION)) - curl -L -o $(DOCFORGE) https://github.com/gardener/docforge/releases/download/$(DOCFORGE_VERSION)/docforge-$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(shell uname -m | sed 's/x86_64/amd64/') - chmod +x $(DOCFORGE) - $(GEN_CRD_API_REFERENCE_DOCS): $(call tool_version_file,$(GEN_CRD_API_REFERENCE_DOCS),$(GEN_CRD_API_REFERENCE_DOCS_VERSION)) go build -o $(GEN_CRD_API_REFERENCE_DOCS) github.com/ahmetb/gen-crd-api-reference-docs diff --git a/vendor/github.com/gardener/gardener/hack/update-codegen.sh b/vendor/github.com/gardener/gardener/hack/update-codegen.sh index db592cb29..98d3ff314 100755 --- a/vendor/github.com/gardener/gardener/hack/update-codegen.sh +++ b/vendor/github.com/gardener/gardener/hack/update-codegen.sh @@ -39,6 +39,7 @@ AVAILABLE_CODEGEN_OPTIONS=( "shootdnsrewriting_groups" "provider_local_groups" "extensions_config_groups" + "nodeagent_groups" ) # Friendly reminder if workspace location is not in $GOPATH @@ -379,6 +380,30 @@ resourcemanager_groups() { } export -f resourcemanager_groups +# Componentconfig for node-agent + +nodeagent_groups() { + echo "Generating API groups for pkg/nodeagent/apis/config" + + bash "${PROJECT_ROOT}"/hack/generate-internal-groups.sh \ + deepcopy,defaulter \ + github.com/gardener/gardener/pkg/client/componentconfig \ + github.com/gardener/gardener/pkg/nodeagent/apis \ + github.com/gardener/gardener/pkg/nodeagent/apis \ + "config:v1alpha1" \ + -h "${PROJECT_ROOT}/hack/LICENSE_BOILERPLATE.txt" + + bash "${PROJECT_ROOT}"/hack/generate-internal-groups.sh \ + conversion \ + github.com/gardener/gardener/pkg/client/componentconfig \ + github.com/gardener/gardener/pkg/nodeagent/apis \ + github.com/gardener/gardener/pkg/nodeagent/apis \ + "config:v1alpha1" \ + --extra-peer-dirs=github.com/gardener/gardener/pkg/nodeagent/apis/config,github.com/gardener/gardener/pkg/nodeagent/apis/config/v1alpha1,k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/conversion,k8s.io/apimachinery/pkg/runtime,k8s.io/component-base/config,k8s.io/component-base/config/v1alpha1 \ + -h "${PROJECT_ROOT}/hack/LICENSE_BOILERPLATE.txt" +} +export -f nodeagent_groups + # Componentconfig for admission plugins shoottolerationrestriction_groups() { diff --git a/vendor/github.com/gardener/gardener/imagevector/images.yaml b/vendor/github.com/gardener/gardener/imagevector/images.yaml index 8d54396f8..b7437e00a 100644 --- a/vendor/github.com/gardener/gardener/imagevector/images.yaml +++ b/vendor/github.com/gardener/gardener/imagevector/images.yaml @@ -49,7 +49,7 @@ images: - name: etcd-druid sourceRepository: github.com/gardener/etcd-druid repository: eu.gcr.io/gardener-project/gardener/etcd-druid - tag: "v0.19.3" + tag: "v0.20.3" - name: dependency-watchdog sourceRepository: github.com/gardener/dependency-watchdog repository: eu.gcr.io/gardener-project/gardener/dependency-watchdog @@ -57,36 +57,7 @@ images: - name: nginx-ingress-controller sourceRepository: github.com/kubernetes/ingress-nginx repository: registry.k8s.io/ingress-nginx/controller-chroot - tag: "v1.4.0" - targetVersion: "1.22.x" - labels: - - name: 'gardener.cloud/cve-categorisation' - value: - network_exposure: 'public' - authentication_enforced: true - user_interaction: 'end-user' - confidentiality_requirement: 'low' - integrity_requirement: 'low' - availability_requirement: 'low' -- name: nginx-ingress-controller - sourceRepository: github.com/kubernetes/ingress-nginx - repository: registry.k8s.io/ingress-nginx/controller-chroot - tag: "v1.6.4" - targetVersion: "1.23.x" - labels: - - name: 'gardener.cloud/cve-categorisation' - value: - network_exposure: 'public' - authentication_enforced: true - user_interaction: 'end-user' - confidentiality_requirement: 'low' - integrity_requirement: 'low' - availability_requirement: 'low' -- name: nginx-ingress-controller - sourceRepository: github.com/kubernetes/ingress-nginx - repository: registry.k8s.io/ingress-nginx/controller-chroot - tag: "v1.8.1" - targetVersion: ">= 1.24" + tag: "v1.9.4" labels: - name: 'gardener.cloud/cve-categorisation' value: @@ -131,7 +102,7 @@ images: - name: machine-controller-manager sourceRepository: github.com/gardener/machine-controller-manager repository: eu.gcr.io/gardener-project/gardener/machine-controller-manager - tag: "v0.49.3" + tag: "v0.50.0" labels: - name: gardener.cloud/cve-categorisation value: @@ -144,7 +115,7 @@ images: - name: cluster-autoscaler sourceRepository: github.com/gardener/autoscaler repository: eu.gcr.io/gardener-project/gardener/autoscaler/cluster-autoscaler - tag: "v1.27.0" + tag: "v1.27.1" targetVersion: ">= 1.27" - name: cluster-autoscaler sourceRepository: github.com/gardener/autoscaler @@ -161,16 +132,6 @@ images: repository: eu.gcr.io/gardener-project/gardener/autoscaler/cluster-autoscaler tag: "v1.24.3" targetVersion: "1.24.x" -- name: cluster-autoscaler - sourceRepository: github.com/gardener/autoscaler - repository: eu.gcr.io/gardener-project/gardener/autoscaler/cluster-autoscaler - tag: "v1.23.4" - targetVersion: "1.23.x" -- name: cluster-autoscaler - sourceRepository: github.com/gardener/autoscaler - repository: eu.gcr.io/gardener-project/gardener/autoscaler/cluster-autoscaler - tag: "v1.22.6" - targetVersion: "1.22.x" - name: vpn-seed-server sourceRepository: github.com/gardener/vpn2 repository: eu.gcr.io/gardener-project/gardener/vpn-seed-server @@ -249,6 +210,8 @@ images: sourceRepository: github.com/gardener/gardener-metrics-exporter repository: eu.gcr.io/gardener-project/gardener/metrics-exporter tag: "0.27.0" + resourceId: + name: metrics-exporter - name: node-exporter sourceRepository: github.com/prometheus/node_exporter repository: quay.io/prometheus/node-exporter @@ -270,7 +233,7 @@ images: - name: plutono sourceRepository: github.com/credativ/plutono repository: ghcr.io/credativ/plutono - tag: "v7.5.24" + tag: "v7.5.25" labels: - name: gardener.cloud/cve-categorisation value: @@ -445,7 +408,7 @@ images: - name: vali sourceRepository: github.com/credativ/vali repository: ghcr.io/credativ/vali - tag: "v2.2.8" + tag: "v2.2.9" labels: - name: 'gardener.cloud/cve-categorisation' value: @@ -497,7 +460,7 @@ images: - name: valitail sourceRepository: github.com/credativ/vali repository: ghcr.io/credativ/valitail - tag: "v2.2.8" + tag: "v2.2.9" labels: - name: 'gardener.cloud/cve-categorisation' value: @@ -671,7 +634,7 @@ images: - name: ext-authz-server sourceRepository: github.com/gardener/ext-authz-server repository: eu.gcr.io/gardener-project/gardener/ext-authz-server - tag: "0.8.0" + tag: "0.9.0" # API Server SNI - name: apiserver-proxy @@ -696,4 +659,4 @@ images: name: apiserver-proxy sourceRepository: github.com/gardener/apiserver-proxy repository: eu.gcr.io/gardener-project/gardener/apiserver-proxy - tag: "v0.13.0" + tag: "v0.14.0" diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/types.go b/vendor/github.com/gardener/gardener/pkg/apis/core/types.go index ac7692b80..212ecdedf 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/types.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/types.go @@ -14,7 +14,9 @@ package core -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) const ( // GardenerSeedLeaseNamespace is the namespace in which Gardenlet will report Seeds' diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/types_cloudprofile.go b/vendor/github.com/gardener/gardener/pkg/apis/core/types_cloudprofile.go index b77e77eb3..3c582e078 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/types_cloudprofile.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/types_cloudprofile.go @@ -98,6 +98,11 @@ type MachineImage struct { Name string // Versions contains versions, expiration dates and container runtimes of the machine image Versions []MachineImageVersion + // UpdateStrategy is the update strategy to use for the machine image. Possible values are: + // - patch: update to the latest patch version of the current minor version. + // - minor: update to the latest minor and patch version. + // - major: always update to the overall latest version (default). + UpdateStrategy *MachineImageUpdateStrategy } // MachineImageVersion is an expirable version with list of supported container runtimes and interfaces @@ -212,3 +217,17 @@ const ( // and will eventually expire. ClassificationDeprecated VersionClassification = "deprecated" ) + +// MachineImageUpdateStrategy is the update strategy to use for a machine image +type MachineImageUpdateStrategy string + +const ( + // UpdateStrategyPatch indicates that auto-updates are performed to the latest patch version of the current minor version. + // When using an expired version during the maintenance window, force updates to the latest patch of the next (not necessarily consecutive) minor when using an expired version. + UpdateStrategyPatch MachineImageUpdateStrategy = "patch" + // UpdateStrategyMinor indicates that auto-updates are performed to the latest patch and minor version of the current major version. + // When using an expired version during the maintenance window, force updates to the latest minor and patch of the next (not necessarily consecutive) major version. + UpdateStrategyMinor MachineImageUpdateStrategy = "minor" + // UpdateStrategyMajor indicates that auto-updates are performed always to the overall latest version. + UpdateStrategyMajor MachineImageUpdateStrategy = "major" +) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/types_controllerregistration.go b/vendor/github.com/gardener/gardener/pkg/apis/core/types_controllerregistration.go index 6192201fb..0cce61bd9 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/types_controllerregistration.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/types_controllerregistration.go @@ -94,7 +94,7 @@ type ControllerRegistrationDeployment struct { // considered for a deployment. // An empty list means that all seeds are selected. SeedSelector *metav1.LabelSelector - // DeploymentRefs holds references to `ControllerDeployments`. Only one element is support now. + // DeploymentRefs holds references to `ControllerDeployments`. Only one element is supported currently. DeploymentRefs []DeploymentRef } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/types_shoot.go b/vendor/github.com/gardener/gardener/pkg/apis/core/types_shoot.go index 880d215d0..d7d922162 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/types_shoot.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/types_shoot.go @@ -479,6 +479,10 @@ type ClusterAutoscaler struct { MaxGracefulTerminationSeconds *int32 // IgnoreTaints specifies a list of taint keys to ignore in node templates when considering to scale a node group. IgnoreTaints []string + // NewPodScaleUpDelay specifies how long CA should ignore newly created pods before they have to be considered for scale-up. + NewPodScaleUpDelay *metav1.Duration + // MaxEmptyBulkDelete specifies the maximum number of empty nodes that can be deleted at the same time (default: 10). + MaxEmptyBulkDelete *int32 } // ExpanderMode is type used for Expander values @@ -616,7 +620,6 @@ type ServiceAccountConfig struct { // AcceptedIssuers is an additional set of issuers that are used to determine which service account tokens are accepted. // These values are not used to generate new service account tokens. Only useful when service account tokens are also // issued by another external system or a change of the current issuer that is used for generating tokens is being performed. - // This field is only available for Kubernetes v1.22 or later. AcceptedIssuers []string } @@ -1056,7 +1059,7 @@ type Worker struct { // CABundle is a certificate bundle which will be installed onto every machine of this worker pool. CABundle *string // CRI contains configurations of CRI support of every machine in the worker pool. - // Defaults to a CRI with name `containerd` when the Kubernetes version of the `Shoot` is >= 1.22. + // Defaults to a CRI with name `containerd`. CRI *CRI // Kubernetes contains configuration for Kubernetes components related to this worker pool. Kubernetes *WorkerKubernetes @@ -1206,9 +1209,9 @@ type ContainerRuntime struct { var ( // DefaultWorkerMaxSurge is the default value for Worker MaxSurge. - DefaultWorkerMaxSurge = intstr.FromInt(1) + DefaultWorkerMaxSurge = intstr.FromInt32(1) // DefaultWorkerMaxUnavailable is the default value for Worker MaxUnavailable. - DefaultWorkerMaxUnavailable = intstr.FromInt(0) + DefaultWorkerMaxUnavailable = intstr.FromInt32(0) ) // WorkersSettings contains settings for all workers. diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/constants/types_constants.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/constants/types_constants.go index f75b6baf1..52884c2cc 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/constants/types_constants.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/constants/types_constants.go @@ -312,12 +312,6 @@ const ( // ShootNoCleanup is a constant for a label on a resource indicating that the Gardener cleaner should not delete this // resource when cleaning a shoot during the deletion flow. ShootNoCleanup = "shoot.gardener.cloud/no-cleanup" - // ShootAlphaScalingAPIServerClass is a constant for an annotation on the shoot stating the initial API server class. - // It influences the size of the initial resource requests/limits. - // Possible values are [small, medium, large, xlarge, 2xlarge]. - // Note that this annotation is alpha and can be removed anytime without further notice. Only use it if you know - // what you do. - ShootAlphaScalingAPIServerClass = "alpha.kube-apiserver.scaling.shoot.gardener.cloud/class" // ShootAlphaControlPlaneScaleDownDisabled is a constant for an annotation on the Shoot resource stating that the // automatic scale-down shall be disabled for the etcd, kube-apiserver, kube-controller-manager. @@ -536,16 +530,6 @@ const ( // LabelExtensionProjectRole is a constant for a label value for extension project roles LabelExtensionProjectRole = "extension-project-role" - // LabelAPIServerExposure is a constant for label key which gardener can add to various objects related - // to kube-apiserver exposure. - // Deprecated: This label key is deprecated and will be removed after Gardener v1.80 has been released. - // TODO(rfranzke): Drop this after v1.80 has been released. - LabelAPIServerExposure = "core.gardener.cloud/apiserver-exposure" - // LabelAPIServerExposureGardenerManaged is a constant for label value which gardener sets on the label key - // "core.gardener.cloud/apiserver-exposure" to indicate that it's responsible for apiserver exposure (via SNI). - // Deprecated: This label key is deprecated and will be removed after Gardener v1.80 has been released. - // TODO(rfranzke): Drop this after v1.80 has been released. - LabelAPIServerExposureGardenerManaged = "gardener-managed" // LabelExposureClassHandlerName is the label key for exposure class handler names. LabelExposureClassHandlerName = "handler.exposureclass.gardener.cloud/name" @@ -569,6 +553,13 @@ const ( // DefaultIngressGatewayAppLabelValue is the ingress gateway value for the app label. DefaultIngressGatewayAppLabelValue = "istio-ingressgateway" + // DataTypeSecret is a constant for a value of the 'Type' field in 'GardenerResourceData' structs describing that + // the data is a secret. + DataTypeSecret = "secret" + // DataTypeMachineState is a constant for a value of the 'Type' field in 'GardenerResourceData' structs describing + // that the data is machine state. + DataTypeMachineState = "machine-state" + // DefaultSchedulerName is the name of the default scheduler. DefaultSchedulerName = "default-scheduler" // SchedulingPurpose is a constant for the key in a label describing the purpose of the scheduler related object. @@ -579,6 +570,9 @@ const ( // the linked cloudprofiles containing the region distances. AnnotationSchedulingCloudProfiles = "scheduling.gardener.cloud/cloudprofiles" + // AnnotationConfirmationForceDeletion is a constant for an annotation on a Shoot resource whose value must be set to "true" in order to + // trigger force-deletion of the cluster. It can only be set if the Shoot has a deletion timestamp and contains an ErrorCode in the Shoot Status. + AnnotationConfirmationForceDeletion = "confirmation.gardener.cloud/force-deletion" // AnnotationManagedSeedAPIServer is a constant for an annotation on a Shoot resource containing the API server settings for a managed seed. AnnotationManagedSeedAPIServer = "shoot.gardener.cloud/managed-seed-api-server" // AnnotationShootIgnoreAlerts is the key for an annotation of a Shoot cluster whose value indicates @@ -666,10 +660,6 @@ const ( LabelPodMaintenanceRestart = "maintenance.gardener.cloud/restart" // LabelWorkerPool is a constant for a label that indicates the worker pool the node belongs to LabelWorkerPool = "worker.gardener.cloud/pool" - // LabelWorkerPoolImageName is a label that indicates the name of the OS image for that worker pool - LabelWorkerPoolImageName = "worker.gardener.cloud/image-name" - // LabelWorkerPoolImageVersion is a label that indicates the version of the OS image for that worker pool - LabelWorkerPoolImageVersion = "worker.gardener.cloud/image-version" // LabelWorkerKubernetesVersion is a constant for a label that indicates the Kubernetes version used for the worker pool nodes. LabelWorkerKubernetesVersion = "worker.gardener.cloud/kubernetes-version" // LabelWorkerPoolDeprecated is a deprecated constant for a label that indicates the worker pool the node belongs to @@ -852,7 +842,10 @@ const ( TaintNodeCriticalComponentsNotReady = "node.gardener.cloud/critical-components-not-ready" // LabelNodeCriticalComponent is the label key for marking node-critical component pods. LabelNodeCriticalComponent = "node.gardener.cloud/critical-component" - // AnnotationWaitForCSINode is the annotation key for csi-driver-node pods, - // indicating they use the driver specified in the value. + // AnnotationPrefixWaitForCSINode is the annotation key for csi-driver-node pods, indicating they use the driver + // specified in the value. AnnotationPrefixWaitForCSINode = "node.gardener.cloud/wait-for-csi-node-" + + // GardenPurposeMachineClass is a constant for the 'machineclass' value in a label. + GardenPurposeMachineClass = "machineclass" ) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults.go index ff9788a5d..009b717bf 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults.go @@ -91,7 +91,7 @@ func SetDefaults_SeedNetworks(obj *SeedNetworks) { } // SetDefaults_SeedSettingDependencyWatchdog sets defaults for SeedSettingDependencyWatchdog objects. -func SetDefaults_SeedSettingDependencyWatchdog(obj *SeedSettingDependencyWatchdog) { +func SetDefaults_SeedSettingDependencyWatchdog(_ *SeedSettingDependencyWatchdog) { } // SetDefaults_Shoot sets default values for Shoot objects. diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults_cloudprofile.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults_cloudprofile.go index 5b9bd84a2..a744a7db6 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults_cloudprofile.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/defaults_cloudprofile.go @@ -20,6 +20,14 @@ import ( v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" ) +// SetDefaults_MachineImage sets default values for MachineImage objects. +func SetDefaults_MachineImage(obj *MachineImage) { + if obj.UpdateStrategy == nil { + updateStrategyMajor := UpdateStrategyMajor + obj.UpdateStrategy = &updateStrategyMajor + } +} + // SetDefaults_MachineImageVersion sets default values for MachineImageVersion objects. func SetDefaults_MachineImageVersion(obj *MachineImageVersion) { if len(obj.CRI) == 0 { diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.pb.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.pb.go index 7b21ca40d..c490e4e4f 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.pb.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.pb.go @@ -5012,754 +5012,761 @@ func init() { } var fileDescriptor_ca37af0df9a5bbd2 = []byte{ - // 11952 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x7d, 0x6c, 0x24, 0xc9, - 0x75, 0x18, 0xae, 0x1e, 0x7e, 0x0d, 0x1f, 0x3f, 0x96, 0x5b, 0xfb, 0x71, 0x5c, 0xee, 0xdd, 0xce, - 0xaa, 0xef, 0xa4, 0xdf, 0x9d, 0x4f, 0xe6, 0xfa, 0xce, 0x92, 0x4e, 0xb7, 0xd2, 0xe9, 0x44, 0xce, - 0x70, 0x77, 0x47, 0x4b, 0x72, 0x79, 0x35, 0xdc, 0xbb, 0xd3, 0xc9, 0xbf, 0xb3, 0x9a, 0xd3, 0xc5, - 0x61, 0x1f, 0x7b, 0xba, 0xe7, 0xba, 0x7b, 0xb8, 0x9c, 0x3b, 0x29, 0xb2, 0x64, 0x4b, 0xb1, 0xce, - 0x56, 0x60, 0x08, 0x70, 0x14, 0x49, 0x0e, 0x2c, 0xc3, 0x70, 0x9c, 0xc4, 0x81, 0x63, 0x38, 0x70, - 0x00, 0xdb, 0x08, 0x60, 0x08, 0x48, 0x2c, 0x19, 0x96, 0x21, 0x48, 0x09, 0x22, 0x21, 0x31, 0x1d, - 0x31, 0x8a, 0x1c, 0x20, 0x81, 0x11, 0xc0, 0x08, 0x82, 0x6c, 0x0c, 0x27, 0xa8, 0xaf, 0xee, 0xea, - 0xaf, 0x21, 0xd9, 0x43, 0x52, 0x3a, 0xd8, 0x7f, 0x91, 0x53, 0x1f, 0xef, 0x55, 0x55, 0x57, 0xbd, - 0x7a, 0xef, 0xd5, 0xfb, 0x80, 0xc5, 0x96, 0x15, 0x6c, 0x75, 0x37, 0xe6, 0x9b, 0x6e, 0xfb, 0x5a, - 0xcb, 0xf0, 0x4c, 0xe2, 0x10, 0x2f, 0xfa, 0xa7, 0xb3, 0xdd, 0xba, 0x66, 0x74, 0x2c, 0xff, 0x5a, - 0xd3, 0xf5, 0xc8, 0xb5, 0x9d, 0x27, 0x36, 0x48, 0x60, 0x3c, 0x71, 0xad, 0x45, 0xeb, 0x8c, 0x80, - 0x98, 0xf3, 0x1d, 0xcf, 0x0d, 0x5c, 0xf4, 0x64, 0x04, 0x63, 0x5e, 0x76, 0x8d, 0xfe, 0xe9, 0x6c, - 0xb7, 0xe6, 0x29, 0x8c, 0x79, 0x0a, 0x63, 0x5e, 0xc0, 0x98, 0xfb, 0x51, 0x15, 0xaf, 0xdb, 0x72, - 0xaf, 0x31, 0x50, 0x1b, 0xdd, 0x4d, 0xf6, 0x8b, 0xfd, 0x60, 0xff, 0x71, 0x14, 0x73, 0x8f, 0x6d, - 0xbf, 0xc7, 0x9f, 0xb7, 0x5c, 0x3a, 0x98, 0x6b, 0x46, 0x37, 0x70, 0xfd, 0xa6, 0x61, 0x5b, 0x4e, - 0xeb, 0xda, 0x4e, 0x6a, 0x34, 0x73, 0xba, 0xd2, 0x54, 0x0c, 0xbb, 0x6f, 0x1b, 0x6f, 0xc3, 0x68, - 0x66, 0xb5, 0x79, 0x67, 0xd4, 0xa6, 0x6d, 0x34, 0xb7, 0x2c, 0x87, 0x78, 0x3d, 0xb9, 0x20, 0xd7, - 0x3c, 0xe2, 0xbb, 0x5d, 0xaf, 0x49, 0x8e, 0xd4, 0xcb, 0xbf, 0xd6, 0x26, 0x81, 0x91, 0x85, 0xeb, - 0x5a, 0x5e, 0x2f, 0xaf, 0xeb, 0x04, 0x56, 0x3b, 0x8d, 0xe6, 0xdd, 0x07, 0x75, 0xf0, 0x9b, 0x5b, - 0xa4, 0x6d, 0xa4, 0xfa, 0xfd, 0x78, 0x5e, 0xbf, 0x6e, 0x60, 0xd9, 0xd7, 0x2c, 0x27, 0xf0, 0x03, - 0x2f, 0xd9, 0x49, 0x7f, 0x43, 0x83, 0x99, 0x85, 0xb5, 0x7a, 0x83, 0x78, 0x3b, 0xc4, 0x5b, 0x76, - 0x5b, 0x2d, 0xcb, 0x69, 0xa1, 0xc7, 0x61, 0x7c, 0x87, 0x78, 0x1b, 0xae, 0x6f, 0x05, 0xbd, 0x59, - 0xed, 0xaa, 0xf6, 0xe8, 0xc8, 0xe2, 0xd4, 0xfe, 0x5e, 0x65, 0xfc, 0x79, 0x59, 0x88, 0xa3, 0x7a, - 0x54, 0x87, 0x73, 0x5b, 0x41, 0xd0, 0x59, 0x68, 0x36, 0x89, 0xef, 0x87, 0x2d, 0x66, 0x4b, 0xac, - 0xdb, 0x03, 0xfb, 0x7b, 0x95, 0x73, 0xb7, 0xd6, 0xd7, 0xd7, 0x12, 0xd5, 0x38, 0xab, 0x8f, 0xfe, - 0xdb, 0x1a, 0x9c, 0x0d, 0x07, 0x83, 0xc9, 0xab, 0x5d, 0xe2, 0x07, 0x3e, 0xc2, 0x70, 0xb1, 0x6d, - 0xec, 0xae, 0xba, 0xce, 0x4a, 0x37, 0x30, 0x02, 0xcb, 0x69, 0xd5, 0x9d, 0x4d, 0xdb, 0x6a, 0x6d, - 0x05, 0x62, 0x68, 0x73, 0xfb, 0x7b, 0x95, 0x8b, 0x2b, 0x99, 0x2d, 0x70, 0x4e, 0x4f, 0x3a, 0xe8, - 0xb6, 0xb1, 0x9b, 0x02, 0xa8, 0x0c, 0x7a, 0x25, 0x5d, 0x8d, 0xb3, 0xfa, 0xe8, 0x4f, 0xc2, 0xc8, - 0x82, 0x69, 0xba, 0x0e, 0x7a, 0x0c, 0xc6, 0x88, 0x63, 0x6c, 0xd8, 0xc4, 0x64, 0x03, 0x2b, 0x2f, - 0x9e, 0xf9, 0xea, 0x5e, 0xe5, 0x2d, 0xfb, 0x7b, 0x95, 0xb1, 0x25, 0x5e, 0x8c, 0x65, 0xbd, 0xfe, - 0x8b, 0x25, 0x18, 0x65, 0x9d, 0x7c, 0xf4, 0x39, 0x0d, 0xce, 0x6d, 0x77, 0x37, 0x88, 0xe7, 0x90, - 0x80, 0xf8, 0x35, 0xc3, 0xdf, 0xda, 0x70, 0x0d, 0x8f, 0x83, 0x98, 0x78, 0xf2, 0xe6, 0xfc, 0xd1, - 0xcf, 0xdf, 0xfc, 0xed, 0x34, 0x38, 0x3e, 0xa7, 0x8c, 0x0a, 0x9c, 0x85, 0x1c, 0xed, 0xc0, 0xa4, - 0xd3, 0xb2, 0x9c, 0xdd, 0xba, 0xd3, 0xf2, 0x88, 0xef, 0xb3, 0x75, 0x99, 0x78, 0xf2, 0x03, 0x45, - 0x06, 0xb3, 0xaa, 0xc0, 0x59, 0x9c, 0xd9, 0xdf, 0xab, 0x4c, 0xaa, 0x25, 0x38, 0x86, 0x47, 0xff, - 0x6b, 0x0d, 0xce, 0x2c, 0x98, 0x6d, 0xcb, 0xf7, 0x2d, 0xd7, 0x59, 0xb3, 0xbb, 0x2d, 0xcb, 0x41, - 0x57, 0x61, 0xd8, 0x31, 0xda, 0x84, 0x2d, 0xc8, 0xf8, 0xe2, 0xa4, 0x58, 0xd3, 0xe1, 0x55, 0xa3, - 0x4d, 0x30, 0xab, 0x41, 0xcf, 0xc1, 0x68, 0xd3, 0x75, 0x36, 0xad, 0x96, 0x18, 0xe7, 0x8f, 0xce, - 0xf3, 0x93, 0x30, 0xaf, 0x9e, 0x04, 0x36, 0x3c, 0x71, 0x82, 0xe6, 0xb1, 0x71, 0x6f, 0x69, 0x37, - 0x20, 0x0e, 0x45, 0xb3, 0x08, 0xfb, 0x7b, 0x95, 0xd1, 0x2a, 0x03, 0x80, 0x05, 0x20, 0xf4, 0x28, - 0x94, 0x4d, 0xcb, 0xe7, 0x1f, 0x73, 0x88, 0x7d, 0xcc, 0xc9, 0xfd, 0xbd, 0x4a, 0xb9, 0x26, 0xca, - 0x70, 0x58, 0x8b, 0x96, 0xe1, 0x3c, 0x5d, 0x41, 0xde, 0xaf, 0x41, 0x9a, 0x1e, 0x09, 0xe8, 0xd0, - 0x66, 0x87, 0xd9, 0x70, 0x67, 0xf7, 0xf7, 0x2a, 0xe7, 0x6f, 0x67, 0xd4, 0xe3, 0xcc, 0x5e, 0xfa, - 0x0d, 0x28, 0x2f, 0xd8, 0xc4, 0xa3, 0x1b, 0x0c, 0x5d, 0x87, 0x69, 0xd2, 0x36, 0x2c, 0x1b, 0x93, - 0x26, 0xb1, 0x76, 0x88, 0xe7, 0xcf, 0x6a, 0x57, 0x87, 0x1e, 0x1d, 0x5f, 0x44, 0xfb, 0x7b, 0x95, - 0xe9, 0xa5, 0x58, 0x0d, 0x4e, 0xb4, 0xd4, 0x3f, 0xa1, 0xc1, 0xc4, 0x42, 0xd7, 0xb4, 0x02, 0x3e, - 0x2f, 0xe4, 0xc1, 0x84, 0x41, 0x7f, 0xae, 0xb9, 0xb6, 0xd5, 0xec, 0x89, 0xcd, 0xf5, 0x6c, 0x91, - 0xef, 0xb9, 0x10, 0x81, 0x59, 0x3c, 0xb3, 0xbf, 0x57, 0x99, 0x50, 0x0a, 0xb0, 0x8a, 0x44, 0xdf, - 0x02, 0xb5, 0x0e, 0x7d, 0x08, 0x26, 0xf9, 0x74, 0x57, 0x8c, 0x0e, 0x26, 0x9b, 0x62, 0x0c, 0x0f, - 0x2b, 0xdf, 0x4a, 0x22, 0x9a, 0xbf, 0xb3, 0xf1, 0x0a, 0x69, 0x06, 0x98, 0x6c, 0x12, 0x8f, 0x38, - 0x4d, 0xc2, 0xb7, 0x4d, 0x55, 0xe9, 0x8c, 0x63, 0xa0, 0xf4, 0x3f, 0xa3, 0x44, 0x6c, 0xc7, 0xb0, - 0x6c, 0x63, 0xc3, 0xb2, 0xad, 0xa0, 0xf7, 0x92, 0xeb, 0x90, 0x43, 0xec, 0x9b, 0xbb, 0xf0, 0x40, - 0xd7, 0x31, 0x78, 0x3f, 0x9b, 0xac, 0xf0, 0x9d, 0xb2, 0xde, 0xeb, 0x10, 0xba, 0xe1, 0xe9, 0x4a, - 0x5f, 0xde, 0xdf, 0xab, 0x3c, 0x70, 0x37, 0xbb, 0x09, 0xce, 0xeb, 0x4b, 0xe9, 0x95, 0x52, 0xf5, - 0xbc, 0x6b, 0x77, 0xdb, 0x02, 0xea, 0x10, 0x83, 0xca, 0xe8, 0xd5, 0xdd, 0xcc, 0x16, 0x38, 0xa7, - 0xa7, 0xfe, 0xd5, 0x12, 0x4c, 0x2e, 0x1a, 0xcd, 0xed, 0x6e, 0x67, 0xb1, 0xdb, 0xdc, 0x26, 0x01, - 0xfa, 0x08, 0x94, 0xe9, 0x85, 0x63, 0x1a, 0x81, 0x21, 0x56, 0xf2, 0xc7, 0x72, 0x77, 0x3d, 0xfb, - 0x88, 0xb4, 0x75, 0xb4, 0xb6, 0x2b, 0x24, 0x30, 0x16, 0x91, 0x58, 0x13, 0x88, 0xca, 0x70, 0x08, - 0x15, 0x6d, 0xc2, 0xb0, 0xdf, 0x21, 0x4d, 0x71, 0xa6, 0x6a, 0x45, 0xf6, 0x8a, 0x3a, 0xe2, 0x46, - 0x87, 0x34, 0xa3, 0xaf, 0x40, 0x7f, 0x61, 0x06, 0x1f, 0x39, 0x30, 0xea, 0x07, 0x46, 0xd0, 0xf5, - 0xd9, 0x41, 0x9b, 0x78, 0xf2, 0xc6, 0xc0, 0x98, 0x18, 0xb4, 0xc5, 0x69, 0x81, 0x6b, 0x94, 0xff, - 0xc6, 0x02, 0x8b, 0xfe, 0xef, 0x35, 0x98, 0x51, 0x9b, 0x2f, 0x5b, 0x7e, 0x80, 0x7e, 0x22, 0xb5, - 0x9c, 0xf3, 0x87, 0x5b, 0x4e, 0xda, 0x9b, 0x2d, 0xe6, 0x8c, 0x40, 0x57, 0x96, 0x25, 0xca, 0x52, - 0x12, 0x18, 0xb1, 0x02, 0xd2, 0xe6, 0xdb, 0xaa, 0x20, 0x1d, 0x55, 0x87, 0xbc, 0x38, 0x25, 0x90, - 0x8d, 0xd4, 0x29, 0x58, 0xcc, 0xa1, 0xeb, 0x1f, 0x81, 0xf3, 0x6a, 0xab, 0x35, 0xcf, 0xdd, 0xb1, - 0x4c, 0xe2, 0xd1, 0x93, 0x10, 0xf4, 0x3a, 0xa9, 0x93, 0x40, 0x77, 0x16, 0x66, 0x35, 0xe8, 0xed, - 0x30, 0xea, 0x91, 0x96, 0xe5, 0x3a, 0xec, 0x6b, 0x8f, 0x47, 0x6b, 0x87, 0x59, 0x29, 0x16, 0xb5, - 0xfa, 0xff, 0x2c, 0xc5, 0xd7, 0x8e, 0x7e, 0x46, 0xb4, 0x03, 0xe5, 0x8e, 0x40, 0x25, 0xd6, 0xee, - 0xd6, 0xa0, 0x13, 0x94, 0x43, 0x8f, 0x56, 0x55, 0x96, 0xe0, 0x10, 0x17, 0xb2, 0x60, 0x5a, 0xfe, - 0x5f, 0x1d, 0x80, 0xfc, 0x33, 0x72, 0xba, 0x16, 0x03, 0x84, 0x13, 0x80, 0xd1, 0x3a, 0x8c, 0xfb, - 0x8c, 0x48, 0x53, 0xc2, 0x35, 0x94, 0x4f, 0xb8, 0x1a, 0xb2, 0x91, 0x20, 0x5c, 0x67, 0xc5, 0xf0, - 0xc7, 0xc3, 0x0a, 0x1c, 0x01, 0xa2, 0x97, 0x8c, 0x4f, 0x88, 0xa9, 0x5c, 0x17, 0xec, 0x92, 0x69, - 0x88, 0x32, 0x1c, 0xd6, 0xea, 0x5f, 0x1e, 0x06, 0x94, 0xde, 0xe2, 0xea, 0x0a, 0xf0, 0x12, 0xb1, - 0xfe, 0x83, 0xac, 0x80, 0x38, 0x2d, 0x09, 0xc0, 0xe8, 0x35, 0x98, 0xb2, 0x0d, 0x3f, 0xb8, 0xd3, - 0xa1, 0xdc, 0xa3, 0xdc, 0x28, 0x13, 0x4f, 0x2e, 0x14, 0xf9, 0xd2, 0xcb, 0x2a, 0xa0, 0xc5, 0xb3, - 0xfb, 0x7b, 0x95, 0xa9, 0x58, 0x11, 0x8e, 0xa3, 0x42, 0xaf, 0xc0, 0x38, 0x2d, 0x58, 0xf2, 0x3c, - 0xd7, 0x13, 0xab, 0xff, 0x4c, 0x51, 0xbc, 0x0c, 0x08, 0xe7, 0x66, 0xc3, 0x9f, 0x38, 0x02, 0x8f, - 0x3e, 0x08, 0xc8, 0xdd, 0xf0, 0x29, 0x03, 0x6a, 0xde, 0xe4, 0xac, 0x32, 0x9d, 0x2c, 0xfd, 0x3a, - 0x43, 0x8b, 0x73, 0xe2, 0x6b, 0xa2, 0x3b, 0xa9, 0x16, 0x38, 0xa3, 0x17, 0xda, 0x06, 0x14, 0xb2, - 0xdb, 0xe1, 0x06, 0x98, 0x1d, 0x39, 0xfc, 0xf6, 0xb9, 0x48, 0x91, 0xdd, 0x4c, 0x81, 0xc0, 0x19, - 0x60, 0xf5, 0x7f, 0x5d, 0x82, 0x09, 0xbe, 0x45, 0x96, 0x9c, 0xc0, 0xeb, 0x9d, 0xc2, 0x05, 0x41, - 0x62, 0x17, 0x44, 0xb5, 0xf8, 0x99, 0x67, 0x03, 0xce, 0xbd, 0x1f, 0xda, 0x89, 0xfb, 0x61, 0x69, - 0x50, 0x44, 0xfd, 0xaf, 0x87, 0x7f, 0xa7, 0xc1, 0x19, 0xa5, 0xf5, 0x29, 0xdc, 0x0e, 0x66, 0xfc, - 0x76, 0x78, 0x76, 0xc0, 0xf9, 0xe5, 0x5c, 0x0e, 0x6e, 0x6c, 0x5a, 0x8c, 0x70, 0x3f, 0x09, 0xb0, - 0xc1, 0xc8, 0xc9, 0x6a, 0xc4, 0x27, 0x85, 0x9f, 0x7c, 0x31, 0xac, 0xc1, 0x4a, 0xab, 0x18, 0xcd, - 0x2a, 0xf5, 0xa5, 0x59, 0xff, 0x65, 0x08, 0xce, 0xa6, 0x96, 0x3d, 0x4d, 0x47, 0xb4, 0x1f, 0x10, - 0x1d, 0x29, 0xfd, 0x20, 0xe8, 0xc8, 0x50, 0x21, 0x3a, 0x72, 0xe8, 0x7b, 0x02, 0x79, 0x80, 0xda, - 0x56, 0x8b, 0x77, 0x6b, 0x04, 0x86, 0x17, 0xac, 0x5b, 0x6d, 0x22, 0x28, 0xce, 0x8f, 0x1c, 0x6e, - 0xcb, 0xd2, 0x1e, 0x9c, 0xf0, 0xac, 0xa4, 0x20, 0xe1, 0x0c, 0xe8, 0xfa, 0x37, 0x87, 0x01, 0xaa, - 0x0b, 0xd8, 0x0d, 0xf8, 0x60, 0x9f, 0x85, 0x91, 0xce, 0x96, 0xe1, 0xcb, 0xfd, 0xf4, 0x98, 0xdc, - 0x8c, 0x6b, 0xb4, 0xf0, 0xfe, 0x5e, 0x65, 0xb6, 0xea, 0x11, 0x93, 0x38, 0x81, 0x65, 0xd8, 0xbe, - 0xec, 0xc4, 0xea, 0x30, 0xef, 0x47, 0xe7, 0x40, 0x97, 0xb1, 0xea, 0xb6, 0x3b, 0x36, 0xa1, 0xb5, - 0x6c, 0x0e, 0xa5, 0x62, 0x73, 0x58, 0x4e, 0x41, 0xc2, 0x19, 0xd0, 0x25, 0xce, 0xba, 0x63, 0x05, - 0x96, 0x11, 0xe2, 0x1c, 0x2a, 0x8e, 0x33, 0x0e, 0x09, 0x67, 0x40, 0x47, 0x6f, 0x68, 0x30, 0x17, - 0x2f, 0xbe, 0x61, 0x39, 0x96, 0xbf, 0x45, 0x4c, 0x86, 0x7c, 0xf8, 0xc8, 0xc8, 0xaf, 0xec, 0xef, - 0x55, 0xe6, 0x96, 0x73, 0x21, 0xe2, 0x3e, 0xd8, 0xd0, 0x67, 0x35, 0xb8, 0x9c, 0x58, 0x17, 0xcf, - 0x6a, 0xb5, 0x88, 0x27, 0x46, 0x73, 0xf4, 0x2d, 0x54, 0xd9, 0xdf, 0xab, 0x5c, 0x5e, 0xce, 0x07, - 0x89, 0xfb, 0xe1, 0xd3, 0xbf, 0xa2, 0xc1, 0x50, 0x15, 0xd7, 0xd1, 0xe3, 0x31, 0x21, 0xee, 0x01, - 0x55, 0x88, 0xbb, 0xbf, 0x57, 0x19, 0xab, 0xe2, 0xba, 0x22, 0xcf, 0x7d, 0x56, 0x83, 0xb3, 0x4d, - 0xd7, 0x09, 0x0c, 0x3a, 0x2e, 0xcc, 0x39, 0x1d, 0x49, 0x55, 0x0b, 0xc9, 0x2f, 0xd5, 0x04, 0xb0, - 0xc5, 0x4b, 0x62, 0x00, 0x67, 0x93, 0x35, 0x3e, 0x4e, 0x63, 0xd6, 0xbf, 0xad, 0xc1, 0x64, 0xd5, - 0x76, 0xbb, 0xe6, 0x9a, 0xe7, 0x6e, 0x5a, 0x36, 0x79, 0x73, 0x08, 0x6d, 0xea, 0x88, 0xf3, 0x2e, - 0x65, 0x26, 0x44, 0xa9, 0x0d, 0xdf, 0x24, 0x42, 0x94, 0x3a, 0xe4, 0x9c, 0x7b, 0xf2, 0x17, 0xc7, - 0xe2, 0x33, 0x63, 0x37, 0xe5, 0xa3, 0x50, 0x6e, 0x1a, 0x8b, 0x5d, 0xc7, 0xb4, 0x43, 0x29, 0x8a, - 0x8e, 0xb2, 0xba, 0xc0, 0xcb, 0x70, 0x58, 0x8b, 0x5e, 0x03, 0x88, 0x14, 0x6a, 0xe2, 0x33, 0xdc, - 0x18, 0x4c, 0x89, 0xd7, 0x20, 0x41, 0x60, 0x39, 0x2d, 0x3f, 0xfa, 0xf4, 0x51, 0x1d, 0x56, 0xb0, - 0xa1, 0x8f, 0xc1, 0x94, 0x58, 0xe4, 0x7a, 0xdb, 0x68, 0x09, 0x7d, 0x43, 0xc1, 0x95, 0x5a, 0x51, - 0x00, 0x2d, 0x5e, 0x10, 0x88, 0xa7, 0xd4, 0x52, 0x1f, 0xc7, 0xb1, 0xa1, 0x1e, 0x4c, 0xb6, 0x55, - 0x1d, 0xca, 0x70, 0x71, 0x76, 0x46, 0xd1, 0xa7, 0x2c, 0x9e, 0x17, 0xc8, 0x27, 0x63, 0xda, 0x97, - 0x18, 0xaa, 0x0c, 0x51, 0x70, 0xe4, 0xa4, 0x44, 0x41, 0x02, 0x63, 0x5c, 0x18, 0xf6, 0x67, 0x47, - 0xd9, 0x04, 0xaf, 0x17, 0x99, 0x20, 0x97, 0xab, 0x23, 0x0d, 0x31, 0xff, 0xed, 0x63, 0x09, 0x1b, - 0xed, 0xc0, 0x24, 0xbd, 0xd5, 0x1b, 0xc4, 0x26, 0xcd, 0xc0, 0xf5, 0x66, 0xc7, 0x8a, 0x6b, 0x60, - 0x1b, 0x0a, 0x1c, 0xae, 0x4a, 0x53, 0x4b, 0x70, 0x0c, 0x4f, 0xa8, 0x2b, 0x28, 0xe7, 0xea, 0x0a, - 0xba, 0x30, 0xb1, 0xa3, 0xe8, 0xb4, 0xc6, 0xd9, 0x22, 0xbc, 0xbf, 0xc8, 0xc0, 0x22, 0x05, 0xd7, - 0xe2, 0x39, 0x81, 0x68, 0x42, 0x55, 0x86, 0xa9, 0x78, 0xf4, 0xbd, 0x32, 0x9c, 0xad, 0xda, 0x5d, - 0x3f, 0x20, 0xde, 0x82, 0x78, 0x24, 0x22, 0x1e, 0xfa, 0xa4, 0x06, 0x17, 0xd9, 0xbf, 0x35, 0xf7, - 0x9e, 0x53, 0x23, 0xb6, 0xd1, 0x5b, 0xd8, 0xa4, 0x2d, 0x4c, 0xf3, 0x68, 0x14, 0xa8, 0xd6, 0x15, - 0x5c, 0x24, 0x53, 0xce, 0x35, 0x32, 0x21, 0xe2, 0x1c, 0x4c, 0xe8, 0xe7, 0x34, 0xb8, 0x94, 0x51, - 0x55, 0x23, 0x36, 0x09, 0x24, 0xe7, 0x72, 0xd4, 0x71, 0x3c, 0xb4, 0xbf, 0x57, 0xb9, 0xd4, 0xc8, - 0x03, 0x8a, 0xf3, 0xf1, 0xa1, 0xbf, 0xa7, 0xc1, 0x5c, 0x46, 0xed, 0x0d, 0xc3, 0xb2, 0xbb, 0x9e, - 0x64, 0x6a, 0x8e, 0x3a, 0x1c, 0xc6, 0x5b, 0x34, 0x72, 0xa1, 0xe2, 0x3e, 0x18, 0xd1, 0xc7, 0xe1, - 0x42, 0x58, 0x7b, 0xd7, 0x71, 0x08, 0x31, 0x63, 0x2c, 0xce, 0x51, 0x87, 0x72, 0x69, 0x7f, 0xaf, - 0x72, 0xa1, 0x91, 0x05, 0x10, 0x67, 0xe3, 0x41, 0x2d, 0x78, 0x28, 0xaa, 0x08, 0x2c, 0xdb, 0x7a, - 0x8d, 0x73, 0x61, 0x5b, 0x1e, 0xf1, 0xb7, 0x5c, 0xdb, 0x64, 0xc4, 0x42, 0x5b, 0x7c, 0xeb, 0xfe, - 0x5e, 0xe5, 0xa1, 0x46, 0xbf, 0x86, 0xb8, 0x3f, 0x1c, 0x64, 0xc2, 0xa4, 0xdf, 0x34, 0x9c, 0xba, - 0x13, 0x10, 0x6f, 0xc7, 0xb0, 0x67, 0x47, 0x0b, 0x4d, 0x90, 0x1f, 0x51, 0x05, 0x0e, 0x8e, 0x41, - 0x45, 0xef, 0x81, 0x32, 0xd9, 0xed, 0x18, 0x8e, 0x49, 0x38, 0x59, 0x18, 0x5f, 0x7c, 0x90, 0x5e, - 0x46, 0x4b, 0xa2, 0xec, 0xfe, 0x5e, 0x65, 0x52, 0xfe, 0xbf, 0xe2, 0x9a, 0x04, 0x87, 0xad, 0xd1, - 0x47, 0xe1, 0x3c, 0x7b, 0x0f, 0x33, 0x09, 0x23, 0x72, 0xbe, 0x64, 0x74, 0xcb, 0x85, 0xc6, 0xc9, - 0xde, 0x36, 0x56, 0x32, 0xe0, 0xe1, 0x4c, 0x2c, 0xf4, 0x33, 0xb4, 0x8d, 0xdd, 0x9b, 0x9e, 0xd1, - 0x24, 0x9b, 0x5d, 0x7b, 0x9d, 0x78, 0x6d, 0xcb, 0xe1, 0xb2, 0x04, 0x69, 0xba, 0x8e, 0x49, 0x49, - 0x89, 0xf6, 0xe8, 0x08, 0xff, 0x0c, 0x2b, 0xfd, 0x1a, 0xe2, 0xfe, 0x70, 0xd0, 0x3b, 0x61, 0xd2, - 0x6a, 0x39, 0xae, 0x47, 0xd6, 0x0d, 0xcb, 0x09, 0xfc, 0x59, 0x60, 0x6a, 0x77, 0xb6, 0xac, 0x75, - 0xa5, 0x1c, 0xc7, 0x5a, 0xe9, 0x7b, 0x43, 0x30, 0x5e, 0x75, 0x1d, 0xd3, 0x62, 0x62, 0xcc, 0x13, - 0x31, 0x9d, 0xe9, 0x43, 0x2a, 0x1d, 0xbc, 0xbf, 0x57, 0x99, 0x0a, 0x1b, 0x2a, 0x84, 0xf1, 0xe9, - 0x50, 0x51, 0xc1, 0x05, 0xe3, 0xb7, 0xc6, 0x35, 0x0c, 0xf7, 0xf7, 0x2a, 0x67, 0xc2, 0x6e, 0x71, - 0xa5, 0x03, 0xda, 0xe1, 0xf2, 0xc7, 0xba, 0x67, 0x38, 0xbe, 0x35, 0x80, 0xfc, 0x11, 0x4a, 0x96, - 0xcb, 0x29, 0x68, 0x38, 0x03, 0x03, 0x7a, 0x05, 0xa6, 0x69, 0xe9, 0xdd, 0x8e, 0x69, 0x04, 0xa4, - 0xa0, 0xd8, 0x71, 0x51, 0xe0, 0x9c, 0x5e, 0x8e, 0x41, 0xc2, 0x09, 0xc8, 0x5c, 0xc7, 0x6c, 0xf8, - 0xae, 0xc3, 0x8e, 0x5b, 0x4c, 0xc7, 0x4c, 0x4b, 0xb1, 0xa8, 0x45, 0x8f, 0xc1, 0x58, 0x9b, 0xf8, - 0xbe, 0xd1, 0x22, 0xec, 0xfc, 0x8c, 0x47, 0x97, 0xe4, 0x0a, 0x2f, 0xc6, 0xb2, 0x1e, 0xbd, 0x03, - 0x46, 0x9a, 0xae, 0x49, 0xfc, 0xd9, 0x31, 0xf6, 0x85, 0xa9, 0xf4, 0x35, 0x52, 0xa5, 0x05, 0xf7, - 0xf7, 0x2a, 0xe3, 0x4c, 0x0e, 0xa7, 0xbf, 0x30, 0x6f, 0xa4, 0xff, 0x32, 0xe5, 0x59, 0x13, 0x4c, - 0xfa, 0x21, 0x74, 0xe3, 0xa7, 0xa7, 0x66, 0xd6, 0x3f, 0x4f, 0x05, 0x06, 0xd7, 0x09, 0x3c, 0xd7, - 0x5e, 0xb3, 0x0d, 0x87, 0xa0, 0x4f, 0x6b, 0x30, 0xb3, 0x65, 0xb5, 0xb6, 0xd4, 0xc7, 0x2d, 0x71, - 0xb1, 0x15, 0xe2, 0xed, 0x6f, 0x25, 0x60, 0x2d, 0x9e, 0xdf, 0xdf, 0xab, 0xcc, 0x24, 0x4b, 0x71, - 0x0a, 0xa7, 0xfe, 0x99, 0x12, 0x9c, 0x17, 0x23, 0xb3, 0xe9, 0x4d, 0xd3, 0xb1, 0xdd, 0x5e, 0x9b, - 0x38, 0xa7, 0xf1, 0x0e, 0x25, 0xbf, 0x50, 0x29, 0xf7, 0x0b, 0xb5, 0x53, 0x5f, 0x68, 0xa8, 0xc8, - 0x17, 0x0a, 0x37, 0xf2, 0x01, 0x5f, 0xe9, 0xcf, 0x35, 0x98, 0xcd, 0x5a, 0x8b, 0x53, 0x90, 0x81, - 0xda, 0x71, 0x19, 0xe8, 0x56, 0x51, 0xa1, 0x36, 0x39, 0xf4, 0x1c, 0x59, 0xe8, 0xfb, 0x25, 0xb8, - 0x18, 0x35, 0xaf, 0x3b, 0x7e, 0x60, 0xd8, 0x36, 0x57, 0xf3, 0x9c, 0xfc, 0x77, 0xef, 0xc4, 0x44, - 0xd9, 0xd5, 0xc1, 0xa6, 0xaa, 0x8e, 0x3d, 0x57, 0xd3, 0xbc, 0x9b, 0xd0, 0x34, 0xaf, 0x1d, 0x23, - 0xce, 0xfe, 0x4a, 0xe7, 0xff, 0xa6, 0xc1, 0x5c, 0x76, 0xc7, 0x53, 0xd8, 0x54, 0x6e, 0x7c, 0x53, - 0x7d, 0xf0, 0xf8, 0x66, 0x9d, 0xb3, 0xad, 0x7e, 0xbb, 0x94, 0x37, 0x5b, 0x26, 0x6c, 0x6f, 0xc2, - 0x19, 0x2a, 0x05, 0xf9, 0x81, 0x50, 0x89, 0x1e, 0xcd, 0x56, 0x40, 0xea, 0x88, 0xce, 0xe0, 0x38, - 0x0c, 0x9c, 0x04, 0x8a, 0x56, 0x61, 0x8c, 0x8a, 0x3e, 0x14, 0x7e, 0xe9, 0xf0, 0xf0, 0xc3, 0xdb, - 0xa8, 0xc1, 0xfb, 0x62, 0x09, 0x04, 0xfd, 0x04, 0x4c, 0x99, 0xe1, 0x89, 0x3a, 0xe0, 0xa1, 0x30, - 0x09, 0x95, 0x29, 0xaf, 0x6b, 0x6a, 0x6f, 0x1c, 0x07, 0xa6, 0xff, 0x95, 0x06, 0x0f, 0xf6, 0xdb, - 0x5b, 0xe8, 0x55, 0x80, 0xa6, 0x64, 0x2f, 0xb8, 0xa9, 0x48, 0x41, 0xf5, 0x76, 0xc8, 0xa4, 0x44, - 0x07, 0x34, 0x2c, 0xf2, 0xb1, 0x82, 0x24, 0xe3, 0xfd, 0xb1, 0x74, 0x42, 0xef, 0x8f, 0xfa, 0x7f, - 0xd7, 0x54, 0x52, 0xa4, 0x7e, 0xdb, 0x37, 0x1b, 0x29, 0x52, 0xc7, 0x9e, 0xab, 0x5f, 0xfb, 0x56, - 0x09, 0xae, 0x66, 0x77, 0x51, 0xee, 0xde, 0x0f, 0xc0, 0x68, 0x87, 0xdb, 0xf3, 0x0c, 0xb1, 0xbb, - 0xf1, 0x51, 0x4a, 0x59, 0xb8, 0xb5, 0xcd, 0xfd, 0xbd, 0xca, 0x5c, 0x16, 0xa1, 0x17, 0x76, 0x3a, - 0xa2, 0x1f, 0xb2, 0x12, 0x5a, 0x06, 0xce, 0xfd, 0xfd, 0xf8, 0x21, 0x89, 0x8b, 0xb1, 0x41, 0xec, - 0x43, 0x2b, 0x16, 0x3e, 0xa1, 0xc1, 0x74, 0x6c, 0x47, 0xfb, 0xb3, 0x23, 0x6c, 0x8f, 0x16, 0x7a, - 0xfa, 0x89, 0x1d, 0x95, 0xe8, 0xe6, 0x8e, 0x15, 0xfb, 0x38, 0x81, 0x30, 0x41, 0x66, 0xd5, 0x55, - 0x7d, 0xd3, 0x91, 0x59, 0x75, 0xf0, 0x39, 0x64, 0xf6, 0x97, 0x4a, 0x79, 0xb3, 0x65, 0x64, 0xf6, - 0x1e, 0x8c, 0x4b, 0x4b, 0x57, 0x49, 0x2e, 0x6e, 0x0c, 0x3a, 0x26, 0x0e, 0x2e, 0x32, 0x7b, 0x90, - 0x25, 0x3e, 0x8e, 0x70, 0xa1, 0x9f, 0xd1, 0x00, 0xa2, 0x0f, 0x23, 0x0e, 0xd5, 0xfa, 0xf1, 0x2d, - 0x87, 0xc2, 0xd6, 0x4c, 0xd3, 0x23, 0xad, 0x6c, 0x0a, 0x05, 0xaf, 0xfe, 0xbf, 0x87, 0x00, 0xa5, - 0xc7, 0x4e, 0xd9, 0xcd, 0x6d, 0xcb, 0x31, 0x93, 0x02, 0xc1, 0x6d, 0xcb, 0x31, 0x31, 0xab, 0x39, - 0x04, 0x43, 0xfa, 0x0c, 0x9c, 0x69, 0xd9, 0xee, 0x86, 0x61, 0xdb, 0x3d, 0x61, 0xfa, 0x29, 0x8c, - 0x08, 0xcf, 0xd1, 0x8b, 0xe9, 0x66, 0xbc, 0x0a, 0x27, 0xdb, 0xa2, 0x0e, 0xcc, 0x78, 0x54, 0x94, - 0x6d, 0x5a, 0x36, 0x13, 0x9d, 0xdc, 0x6e, 0x50, 0x50, 0x57, 0xc2, 0xd8, 0x7b, 0x9c, 0x80, 0x85, - 0x53, 0xd0, 0xd1, 0xdb, 0x60, 0xac, 0xe3, 0x59, 0x6d, 0xc3, 0xeb, 0x31, 0xe1, 0xac, 0xbc, 0x38, - 0x41, 0x6f, 0xb8, 0x35, 0x5e, 0x84, 0x65, 0x1d, 0xfa, 0x28, 0x8c, 0xdb, 0xd6, 0x26, 0x69, 0xf6, - 0x9a, 0x36, 0x11, 0xca, 0x8d, 0x3b, 0xc7, 0xb3, 0x65, 0x96, 0x25, 0x58, 0xf1, 0xa4, 0x2a, 0x7f, - 0xe2, 0x08, 0x21, 0xaa, 0xc3, 0xb9, 0x7b, 0xae, 0xb7, 0x4d, 0x3c, 0x9b, 0xf8, 0x7e, 0xa3, 0xdb, - 0xe9, 0xb8, 0x5e, 0x40, 0x4c, 0xa6, 0x02, 0x29, 0x73, 0xfb, 0xd6, 0x17, 0xd2, 0xd5, 0x38, 0xab, - 0x8f, 0xfe, 0x46, 0x09, 0x2e, 0xf7, 0x19, 0x04, 0xc2, 0xf4, 0x6c, 0x88, 0x35, 0x12, 0x3b, 0xe1, - 0x9d, 0x7c, 0x3f, 0x8b, 0xc2, 0xfb, 0x7b, 0x95, 0x87, 0xfb, 0x00, 0x68, 0xd0, 0xad, 0x48, 0x5a, - 0x3d, 0x1c, 0x81, 0x41, 0x75, 0x18, 0x35, 0x23, 0x8d, 0xe0, 0xf8, 0xe2, 0x13, 0x94, 0x5a, 0x73, - 0x9d, 0xdd, 0x61, 0xa1, 0x09, 0x00, 0x68, 0x19, 0xc6, 0xf8, 0x43, 0x2c, 0x11, 0x94, 0xff, 0x49, - 0x26, 0x1e, 0xf3, 0xa2, 0xc3, 0x02, 0x93, 0x20, 0xf4, 0xff, 0xa5, 0xc1, 0x58, 0xd5, 0xf5, 0x48, - 0x6d, 0xb5, 0x81, 0x7a, 0x30, 0xa1, 0x98, 0xe0, 0x0b, 0x2a, 0x58, 0x90, 0x2c, 0x30, 0x88, 0x0b, - 0x11, 0x34, 0x69, 0x2e, 0x1a, 0x16, 0x60, 0x15, 0x17, 0x7a, 0x95, 0xae, 0xf9, 0x3d, 0xcf, 0x0a, - 0x28, 0xe2, 0x41, 0xde, 0xaf, 0x38, 0x62, 0x2c, 0x61, 0xf1, 0x1d, 0x15, 0xfe, 0xc4, 0x11, 0x16, - 0x7d, 0x8d, 0x52, 0x80, 0xe4, 0x30, 0xd1, 0x75, 0x18, 0x6e, 0xbb, 0xa6, 0xfc, 0xee, 0x6f, 0x97, - 0xe7, 0x7b, 0xc5, 0x35, 0xe9, 0xda, 0x5e, 0x4c, 0xf7, 0x60, 0x5a, 0x36, 0xd6, 0x47, 0x5f, 0x85, - 0x99, 0x24, 0x7e, 0x74, 0x1d, 0xa6, 0x9b, 0x6e, 0xbb, 0xed, 0x3a, 0x8d, 0xee, 0xe6, 0xa6, 0xb5, - 0x4b, 0x62, 0x76, 0xbc, 0xd5, 0x58, 0x0d, 0x4e, 0xb4, 0xd4, 0xbf, 0xa4, 0xc1, 0x10, 0xfd, 0x2e, - 0x3a, 0x8c, 0x9a, 0x6e, 0xdb, 0xb0, 0x1c, 0x31, 0x2a, 0x66, 0xb3, 0x5c, 0x63, 0x25, 0x58, 0xd4, - 0xa0, 0x0e, 0x8c, 0x4b, 0xa6, 0x69, 0x20, 0x5b, 0x92, 0xda, 0x6a, 0x23, 0xb4, 0xbf, 0x0b, 0x29, - 0xb9, 0x2c, 0xf1, 0x71, 0x84, 0x44, 0x37, 0xe0, 0x6c, 0x6d, 0xb5, 0x51, 0x77, 0x9a, 0x76, 0xd7, - 0x24, 0x4b, 0xbb, 0xec, 0x0f, 0xa5, 0x25, 0x16, 0x2f, 0x11, 0xf3, 0x64, 0xb4, 0x44, 0x34, 0xc2, - 0xb2, 0x8e, 0x36, 0x23, 0xbc, 0x87, 0x30, 0xb6, 0x65, 0xcd, 0x04, 0x10, 0x2c, 0xeb, 0xf4, 0x6f, - 0x97, 0x60, 0x42, 0x19, 0x10, 0xb2, 0x61, 0x8c, 0x4f, 0x57, 0xda, 0xba, 0x2d, 0x15, 0x9c, 0x62, - 0x7c, 0xd4, 0x1c, 0x3b, 0x5f, 0x50, 0x1f, 0x4b, 0x14, 0x2a, 0x5d, 0x2c, 0xf5, 0xa1, 0x8b, 0xf3, - 0x00, 0x7e, 0x64, 0xf9, 0xcd, 0x8f, 0x24, 0xbb, 0x7a, 0x14, 0x7b, 0x6f, 0xa5, 0x05, 0x7a, 0x50, - 0xdc, 0x20, 0xdc, 0x98, 0xa3, 0x9c, 0xb8, 0x3d, 0x36, 0x61, 0xe4, 0x35, 0xd7, 0x21, 0xbe, 0x78, - 0xc3, 0x3a, 0xa6, 0x09, 0x8e, 0x53, 0xfe, 0xe0, 0x25, 0x0a, 0x17, 0x73, 0xf0, 0xfa, 0xaf, 0x68, - 0x00, 0x35, 0x23, 0x30, 0xf8, 0x93, 0xcb, 0x21, 0xec, 0xa5, 0x1f, 0x8c, 0x5d, 0x7c, 0xe5, 0x94, - 0x0d, 0xe9, 0xb0, 0x6f, 0xbd, 0x26, 0xa7, 0x1f, 0x32, 0xd4, 0x1c, 0x7a, 0xc3, 0x7a, 0x8d, 0x60, - 0x56, 0x8f, 0x1e, 0x87, 0x71, 0xe2, 0x34, 0xbd, 0x5e, 0x87, 0x12, 0xef, 0x61, 0xb6, 0xaa, 0xec, - 0x84, 0x2e, 0xc9, 0x42, 0x1c, 0xd5, 0xeb, 0x4f, 0x40, 0x5c, 0x2a, 0x3a, 0x78, 0x94, 0xfa, 0x77, - 0x87, 0xe1, 0xd2, 0xd2, 0x7a, 0xb5, 0x26, 0xe0, 0x59, 0xae, 0x73, 0x9b, 0xf4, 0xfe, 0xd6, 0x3c, - 0xe5, 0x6f, 0xcd, 0x53, 0x8e, 0xd1, 0x3c, 0xe5, 0xbe, 0x06, 0x33, 0x4b, 0xbb, 0x1d, 0xcb, 0x63, - 0x76, 0xfa, 0xc4, 0xa3, 0x62, 0x2c, 0x7a, 0x0c, 0xc6, 0x76, 0xf8, 0xbf, 0x62, 0x73, 0x85, 0xaa, - 0x02, 0xd1, 0x02, 0xcb, 0x7a, 0xb4, 0x09, 0xd3, 0x84, 0x75, 0x67, 0xfc, 0xaa, 0x11, 0x14, 0xd9, - 0x40, 0xdc, 0x0d, 0x24, 0x06, 0x05, 0x27, 0xa0, 0xa2, 0x06, 0x4c, 0x37, 0x6d, 0xc3, 0xf7, 0xad, - 0x4d, 0xab, 0x19, 0x59, 0xa0, 0x8d, 0x2f, 0x3e, 0xce, 0xae, 0x9e, 0x58, 0xcd, 0xfd, 0xbd, 0xca, - 0x05, 0x31, 0xce, 0x78, 0x05, 0x4e, 0x80, 0xd0, 0xbf, 0x50, 0x82, 0xa9, 0xa5, 0xdd, 0x8e, 0xeb, - 0x77, 0x3d, 0xc2, 0x9a, 0x9e, 0x82, 0x04, 0xfe, 0x18, 0x8c, 0x6d, 0x19, 0x8e, 0x69, 0x13, 0x4f, - 0x50, 0x9f, 0x70, 0x6d, 0x6f, 0xf1, 0x62, 0x2c, 0xeb, 0xd1, 0xeb, 0x00, 0x7e, 0x73, 0x8b, 0x98, - 0x5d, 0xc6, 0xc1, 0xf0, 0x43, 0x72, 0xbb, 0x08, 0x0d, 0x8d, 0xcd, 0xb1, 0x11, 0x82, 0x14, 0x94, - 0x3d, 0xfc, 0x8d, 0x15, 0x74, 0xfa, 0x77, 0x34, 0x38, 0x1b, 0xeb, 0x77, 0x0a, 0x82, 0xe5, 0x66, - 0x5c, 0xb0, 0x5c, 0x18, 0x78, 0xae, 0x39, 0xf2, 0xe4, 0xcf, 0x96, 0xe0, 0x81, 0x9c, 0x35, 0x49, - 0x99, 0x2b, 0x68, 0xa7, 0x64, 0xae, 0xd0, 0x85, 0x89, 0xc0, 0xb5, 0x85, 0xa1, 0xa4, 0x5c, 0x81, - 0x42, 0xc6, 0x08, 0xeb, 0x21, 0x98, 0xc8, 0x18, 0x21, 0x2a, 0xf3, 0xb1, 0x8a, 0x47, 0xff, 0x8a, - 0x06, 0xe3, 0xa1, 0xfe, 0xea, 0x87, 0xea, 0x0d, 0xe9, 0xf0, 0x9e, 0x6b, 0xfa, 0x1f, 0x97, 0xe0, - 0x62, 0x08, 0x5b, 0xca, 0x09, 0x8d, 0x80, 0xd2, 0x8d, 0x83, 0x85, 0xe0, 0x07, 0xc5, 0x3d, 0xac, - 0xf0, 0x02, 0x0a, 0xa7, 0x40, 0xf9, 0xa6, 0xae, 0xd7, 0x71, 0x7d, 0xc9, 0x0e, 0x70, 0xbe, 0x89, - 0x17, 0x61, 0x59, 0x87, 0x56, 0x61, 0xc4, 0xa7, 0xf8, 0xc4, 0x6d, 0x72, 0xc4, 0xd5, 0x60, 0x1c, - 0x0d, 0x1b, 0x2f, 0xe6, 0x60, 0xd0, 0xeb, 0xaa, 0x4a, 0x63, 0xa4, 0xb8, 0x9a, 0x85, 0xce, 0xc4, - 0x94, 0x2b, 0x92, 0xe1, 0xcd, 0x91, 0xa5, 0xd6, 0xd0, 0x97, 0x61, 0x46, 0x58, 0x3c, 0xf0, 0x6d, - 0xe3, 0x34, 0x09, 0x7a, 0x4f, 0x6c, 0x67, 0x3c, 0x92, 0x78, 0x45, 0x3e, 0x9f, 0x6c, 0x1f, 0xed, - 0x18, 0xdd, 0x87, 0xf2, 0x4d, 0x31, 0x48, 0x34, 0x07, 0x25, 0x4b, 0x7e, 0x0b, 0x10, 0x30, 0x4a, - 0xf5, 0x1a, 0x2e, 0x59, 0x66, 0xc8, 0x0f, 0x95, 0x72, 0xb9, 0x36, 0xe5, 0x5a, 0x1a, 0xea, 0x7f, - 0x2d, 0xe9, 0xdf, 0x2b, 0xc1, 0x79, 0x89, 0x55, 0xce, 0xb1, 0x26, 0xde, 0xe0, 0x0e, 0xe0, 0x0d, - 0x0f, 0x56, 0x8a, 0xdc, 0x81, 0x61, 0x46, 0x00, 0x0b, 0xbd, 0xcd, 0x85, 0x00, 0xe9, 0x70, 0x30, - 0x03, 0x84, 0x3e, 0x0a, 0xa3, 0xb6, 0xb1, 0x41, 0x6c, 0x69, 0x69, 0x56, 0x48, 0x85, 0x94, 0x35, - 0x5d, 0xae, 0xd9, 0xf4, 0xb9, 0x35, 0x7d, 0xf8, 0x64, 0xc3, 0x0b, 0xb1, 0xc0, 0x39, 0xf7, 0x34, - 0x4c, 0x28, 0xcd, 0xd0, 0x0c, 0x0c, 0x6d, 0x13, 0xfe, 0x36, 0x3b, 0x8e, 0xe9, 0xbf, 0xe8, 0x3c, - 0x8c, 0xec, 0x18, 0x76, 0x57, 0x2c, 0x09, 0xe6, 0x3f, 0xae, 0x97, 0xde, 0xa3, 0xe9, 0xbf, 0xa9, - 0xc1, 0xc4, 0x2d, 0x6b, 0x83, 0x78, 0xdc, 0x6c, 0x81, 0x89, 0x42, 0x31, 0xc7, 0xe1, 0x89, 0x2c, - 0xa7, 0x61, 0xb4, 0x0b, 0xe3, 0xe2, 0xa6, 0x09, 0xad, 0x5a, 0x6f, 0x16, 0x7b, 0x04, 0x0e, 0x51, - 0x0b, 0x0a, 0xae, 0x3a, 0x2a, 0x49, 0x0c, 0x38, 0x42, 0xa6, 0xbf, 0x0e, 0xe7, 0x32, 0x3a, 0xa1, - 0x0a, 0x3b, 0xbe, 0x5e, 0x20, 0xb6, 0x85, 0x3c, 0x8f, 0x5e, 0x80, 0x79, 0x39, 0xba, 0x04, 0x43, - 0xc4, 0x31, 0xc5, 0x9e, 0x18, 0xdb, 0xdf, 0xab, 0x0c, 0x2d, 0x39, 0x26, 0xa6, 0x65, 0x94, 0x4c, - 0xd9, 0x6e, 0x8c, 0x27, 0x61, 0x64, 0x6a, 0x59, 0x94, 0xe1, 0xb0, 0x96, 0x3d, 0xdb, 0x27, 0x5f, - 0xa8, 0x29, 0x77, 0x3a, 0xb3, 0x99, 0x38, 0x3d, 0x83, 0x3c, 0x8c, 0x27, 0x4f, 0xe2, 0xe2, 0xac, - 0x58, 0x90, 0xd4, 0x99, 0xc6, 0x29, 0xbc, 0xfa, 0xef, 0x0d, 0xc3, 0x43, 0xb7, 0x5c, 0xcf, 0x7a, - 0xcd, 0x75, 0x02, 0xc3, 0x5e, 0x73, 0xcd, 0xc8, 0x40, 0x4d, 0x10, 0xe5, 0x4f, 0x69, 0xf0, 0x40, - 0xb3, 0xd3, 0xe5, 0xdc, 0xad, 0xb4, 0x1b, 0x5a, 0x23, 0x9e, 0xe5, 0x16, 0xb5, 0x53, 0x63, 0xae, - 0xa9, 0xd5, 0xb5, 0xbb, 0x59, 0x20, 0x71, 0x1e, 0x2e, 0x66, 0x2e, 0x67, 0xba, 0xf7, 0x1c, 0x36, - 0xb8, 0x46, 0xc0, 0x56, 0xf3, 0xb5, 0xe8, 0x23, 0x14, 0x34, 0x97, 0xab, 0x65, 0x42, 0xc4, 0x39, - 0x98, 0xd0, 0xc7, 0xe1, 0x82, 0xc5, 0x07, 0x87, 0x89, 0x61, 0x5a, 0x0e, 0xf1, 0x7d, 0x66, 0x34, - 0x36, 0x88, 0x3d, 0x58, 0x3d, 0x0b, 0x20, 0xce, 0xc6, 0x83, 0x5e, 0x06, 0xf0, 0x7b, 0x4e, 0x53, - 0xac, 0xff, 0x48, 0x21, 0xac, 0x9c, 0x09, 0x0c, 0xa1, 0x60, 0x05, 0x22, 0x95, 0x70, 0x83, 0x70, - 0x53, 0x8e, 0x32, 0xdb, 0x32, 0x26, 0xe1, 0x46, 0x7b, 0x28, 0xaa, 0xd7, 0xff, 0x99, 0x06, 0x63, - 0xc2, 0xfd, 0x1d, 0xbd, 0x3d, 0xa1, 0xe5, 0x09, 0x69, 0x4f, 0x42, 0xd3, 0xd3, 0x63, 0x4f, 0x7d, - 0x42, 0xc3, 0x27, 0x58, 0x89, 0x42, 0x6a, 0x02, 0x81, 0x38, 0x52, 0x17, 0xc6, 0x9e, 0xfc, 0xa4, - 0x0a, 0x51, 0x41, 0xa6, 0x7f, 0x59, 0x83, 0xb3, 0xa9, 0x5e, 0x87, 0xe0, 0x17, 0x4e, 0xd1, 0x8a, - 0xe6, 0x5b, 0xc3, 0x30, 0xcd, 0x8c, 0xe5, 0x1c, 0xc3, 0xe6, 0x0a, 0x98, 0x53, 0x10, 0x50, 0x1e, - 0x87, 0x71, 0xab, 0xdd, 0xee, 0x06, 0x94, 0x54, 0x0b, 0x1d, 0x3a, 0xfb, 0xe6, 0x75, 0x59, 0x88, - 0xa3, 0x7a, 0xe4, 0x88, 0xab, 0x90, 0x13, 0xf1, 0xe5, 0x62, 0x5f, 0x4e, 0x9d, 0xe0, 0x3c, 0xbd, - 0xb6, 0xf8, 0x7d, 0x95, 0x75, 0x53, 0x7e, 0x5a, 0x03, 0xf0, 0x03, 0xcf, 0x72, 0x5a, 0xb4, 0x50, - 0x5c, 0x97, 0xf8, 0x18, 0xd0, 0x36, 0x42, 0xa0, 0x1c, 0x79, 0xb8, 0x46, 0x51, 0x05, 0x56, 0x30, - 0xa3, 0x05, 0xc1, 0x25, 0x70, 0x8a, 0xff, 0xa3, 0x09, 0x7e, 0xe8, 0xa1, 0x74, 0x74, 0x17, 0xe1, - 0x12, 0x19, 0xb1, 0x11, 0x73, 0x4f, 0xc1, 0x78, 0x88, 0xef, 0xa0, 0x5b, 0x77, 0x52, 0xb9, 0x75, - 0xe7, 0x9e, 0x81, 0x33, 0x89, 0xe1, 0x1e, 0xe9, 0xd2, 0xfe, 0x0f, 0x1a, 0xa0, 0xf8, 0xec, 0x4f, - 0x41, 0xb4, 0x6b, 0xc5, 0x45, 0xbb, 0xc5, 0xc1, 0x3f, 0x59, 0x8e, 0x6c, 0xf7, 0x8d, 0x29, 0x60, - 0xd1, 0x41, 0xc2, 0xe8, 0x2b, 0xe2, 0xe2, 0xa2, 0xf7, 0x6c, 0xe4, 0x61, 0x20, 0x4e, 0xee, 0x00, - 0xf7, 0xec, 0xed, 0x04, 0xac, 0xe8, 0x9e, 0x4d, 0xd6, 0xe0, 0x14, 0x5e, 0xf4, 0x19, 0x0d, 0x66, - 0x8c, 0x78, 0x74, 0x10, 0xb9, 0x32, 0x85, 0xbc, 0x4f, 0x13, 0x91, 0x46, 0xa2, 0xb1, 0x24, 0x2a, - 0x7c, 0x9c, 0x42, 0x8b, 0xde, 0x09, 0x93, 0x46, 0xc7, 0x5a, 0xe8, 0x9a, 0x16, 0x15, 0x0d, 0x64, - 0x68, 0x07, 0x26, 0xae, 0x2e, 0xac, 0xd5, 0xc3, 0x72, 0x1c, 0x6b, 0x15, 0x86, 0xe1, 0x10, 0x0b, - 0x39, 0x3c, 0x60, 0x18, 0x0e, 0xb1, 0x86, 0x51, 0x18, 0x0e, 0xb1, 0x74, 0x2a, 0x12, 0xe4, 0x00, - 0xb8, 0x96, 0xd9, 0x14, 0x28, 0xf9, 0xab, 0x5d, 0x21, 0x09, 0xf9, 0x4e, 0xbd, 0x56, 0x15, 0x18, - 0xd9, 0xed, 0x17, 0xfd, 0xc6, 0x0a, 0x06, 0xf4, 0x79, 0x0d, 0xa6, 0x04, 0xed, 0x16, 0x38, 0xc7, - 0xd8, 0x27, 0x7a, 0xa9, 0xe8, 0x7e, 0x49, 0xec, 0xc9, 0x79, 0xac, 0x02, 0xe7, 0x74, 0x27, 0x74, - 0x50, 0x89, 0xd5, 0xe1, 0xf8, 0x38, 0xd0, 0xdf, 0xd7, 0xe0, 0xbc, 0x4f, 0xbc, 0x1d, 0xab, 0x49, - 0x16, 0x9a, 0x4d, 0xb7, 0xeb, 0xc8, 0xef, 0x50, 0x2e, 0x1e, 0xb5, 0xa0, 0x91, 0x01, 0x8f, 0x5b, - 0x46, 0x67, 0xd5, 0xe0, 0x4c, 0xfc, 0x94, 0x2d, 0x3b, 0x73, 0xcf, 0x08, 0x9a, 0x5b, 0x55, 0xa3, - 0xb9, 0xc5, 0x74, 0xe5, 0xdc, 0x18, 0xba, 0xe0, 0xbe, 0x7e, 0x21, 0x0e, 0x8a, 0xbf, 0x3a, 0x27, - 0x0a, 0x71, 0x12, 0x21, 0x72, 0xa1, 0xec, 0x89, 0x90, 0x4b, 0xb3, 0x50, 0x9c, 0xa5, 0x48, 0xc5, - 0x6f, 0xe2, 0x8c, 0xbd, 0xfc, 0x85, 0x43, 0x24, 0xa8, 0x05, 0x0f, 0x71, 0xd1, 0x66, 0xc1, 0x71, - 0x9d, 0x5e, 0xdb, 0xed, 0xfa, 0x0b, 0xdd, 0x60, 0x8b, 0x38, 0x81, 0xd4, 0x55, 0x4e, 0xb0, 0x6b, - 0x94, 0xd9, 0x83, 0x2f, 0xf5, 0x6b, 0x88, 0xfb, 0xc3, 0x41, 0x2f, 0x42, 0x99, 0xec, 0x10, 0x27, - 0x58, 0x5f, 0x5f, 0x9e, 0x9d, 0x2c, 0xc4, 0xed, 0xb1, 0x29, 0x2c, 0x09, 0x18, 0x38, 0x84, 0x86, - 0xb6, 0x61, 0xcc, 0xe6, 0x31, 0xb3, 0x66, 0xa7, 0x8a, 0x13, 0xc5, 0x64, 0xfc, 0x2d, 0x2e, 0xff, - 0x89, 0x1f, 0x58, 0x62, 0x40, 0x1d, 0xb8, 0x6a, 0x92, 0x4d, 0xa3, 0x6b, 0x07, 0xab, 0x6e, 0x40, - 0x59, 0xda, 0x5e, 0xa4, 0x9f, 0x92, 0x26, 0xf4, 0xd3, 0xcc, 0xc1, 0xf8, 0x91, 0xfd, 0xbd, 0xca, - 0xd5, 0xda, 0x01, 0x6d, 0xf1, 0x81, 0xd0, 0x50, 0x0f, 0x1e, 0x16, 0x6d, 0xee, 0x3a, 0x1e, 0x31, - 0x9a, 0x5b, 0x74, 0x95, 0xd3, 0x48, 0xcf, 0x30, 0xa4, 0xff, 0xdf, 0xfe, 0x5e, 0xe5, 0xe1, 0xda, - 0xc1, 0xcd, 0xf1, 0x61, 0x60, 0xce, 0x7d, 0x00, 0x50, 0xfa, 0x9c, 0x1f, 0x74, 0x61, 0x97, 0xd5, - 0x0b, 0xfb, 0x8b, 0x23, 0x70, 0x99, 0x92, 0x8f, 0x88, 0x4d, 0x5d, 0x31, 0x1c, 0xa3, 0xf5, 0xc3, - 0x79, 0xb5, 0xfd, 0xa6, 0x06, 0x0f, 0x6c, 0x65, 0x8b, 0x90, 0x82, 0x51, 0x7e, 0xae, 0x90, 0xa8, - 0xdf, 0x4f, 0x2a, 0xe5, 0x27, 0xab, 0x6f, 0x13, 0x9c, 0x37, 0x28, 0xf4, 0x01, 0x98, 0x71, 0x5c, - 0x93, 0x54, 0xeb, 0x35, 0xbc, 0x62, 0xf8, 0xdb, 0x0d, 0xf9, 0xf2, 0x37, 0xc2, 0x6d, 0x4e, 0x56, - 0x13, 0x75, 0x38, 0xd5, 0x1a, 0xed, 0x00, 0xea, 0xb8, 0xe6, 0xd2, 0x8e, 0xd5, 0x94, 0x6f, 0x4e, - 0xc5, 0xed, 0x5c, 0xd8, 0xc3, 0xd6, 0x5a, 0x0a, 0x1a, 0xce, 0xc0, 0xc0, 0x64, 0x60, 0x3a, 0x98, - 0x15, 0xd7, 0xb1, 0x02, 0xd7, 0x63, 0x7e, 0x24, 0x03, 0x89, 0x82, 0x4c, 0x06, 0x5e, 0xcd, 0x84, - 0x88, 0x73, 0x30, 0xe9, 0xff, 0x43, 0x83, 0x33, 0x74, 0x5b, 0xac, 0x79, 0xee, 0x6e, 0xef, 0x87, - 0x71, 0x43, 0x3e, 0x26, 0x8c, 0x20, 0xb8, 0xee, 0xe6, 0x82, 0x62, 0x00, 0x31, 0xce, 0xc6, 0x1c, - 0xd9, 0x3c, 0xa8, 0xea, 0xab, 0xa1, 0x7c, 0xf5, 0x95, 0xfe, 0xf9, 0x12, 0x67, 0x31, 0xa5, 0xfa, - 0xe8, 0x87, 0xf2, 0x1c, 0x3e, 0x05, 0x53, 0xb4, 0x6c, 0xc5, 0xd8, 0x5d, 0xab, 0x3d, 0xef, 0xda, - 0xd2, 0x95, 0x87, 0x99, 0xe7, 0xde, 0x56, 0x2b, 0x70, 0xbc, 0x1d, 0xba, 0x0e, 0x63, 0x1d, 0xee, - 0x30, 0x2c, 0x84, 0x9b, 0xab, 0xdc, 0x52, 0x80, 0x15, 0xdd, 0xdf, 0xab, 0x9c, 0x8d, 0x1e, 0x4b, - 0x44, 0x21, 0x96, 0x1d, 0xf4, 0xcf, 0x5e, 0x00, 0x06, 0xdc, 0x26, 0xc1, 0x0f, 0xe3, 0x9a, 0x3c, - 0x01, 0x13, 0xcd, 0x4e, 0xb7, 0x7a, 0xa3, 0xf1, 0x5c, 0xd7, 0x65, 0x42, 0x2b, 0x8b, 0x6d, 0x48, - 0x79, 0xce, 0xea, 0xda, 0x5d, 0x59, 0x8c, 0xd5, 0x36, 0x94, 0x3a, 0x34, 0x3b, 0x5d, 0x41, 0x6f, - 0xd7, 0x54, 0x1b, 0x55, 0x46, 0x1d, 0xaa, 0x6b, 0x77, 0x63, 0x75, 0x38, 0xd5, 0x1a, 0x7d, 0x1c, - 0x26, 0x89, 0x38, 0xb8, 0xb7, 0x0c, 0xcf, 0x14, 0x74, 0xa1, 0x5e, 0x74, 0xf2, 0xe1, 0xd2, 0x4a, - 0x6a, 0xc0, 0x59, 0xf5, 0x25, 0x05, 0x05, 0x8e, 0x21, 0x44, 0x1f, 0x86, 0x4b, 0xf2, 0x37, 0xfd, - 0xca, 0xae, 0x99, 0x24, 0x14, 0x23, 0xdc, 0x47, 0x73, 0x29, 0xaf, 0x11, 0xce, 0xef, 0x8f, 0x7e, - 0x43, 0x83, 0x8b, 0x61, 0xad, 0xe5, 0x58, 0xed, 0x6e, 0x1b, 0x93, 0xa6, 0x6d, 0x58, 0x6d, 0xc1, - 0xa0, 0xbf, 0x70, 0x6c, 0x13, 0x8d, 0x83, 0xe7, 0xc4, 0x2a, 0xbb, 0x0e, 0xe7, 0x0c, 0x09, 0x7d, - 0x59, 0x83, 0xab, 0xb2, 0x6a, 0xcd, 0x23, 0xbe, 0xdf, 0xf5, 0x48, 0xe4, 0x48, 0x26, 0x96, 0x64, - 0xac, 0x10, 0xed, 0x64, 0x9c, 0xca, 0xd2, 0x01, 0xb0, 0xf1, 0x81, 0xd8, 0xd5, 0xed, 0xd2, 0x70, - 0x37, 0x03, 0xc1, 0xd1, 0x9f, 0xd4, 0x76, 0xa1, 0x28, 0x70, 0x0c, 0x21, 0xfa, 0xe7, 0x1a, 0x3c, - 0xa0, 0x16, 0xa8, 0xbb, 0x85, 0xb3, 0xf2, 0x2f, 0x1e, 0xdb, 0x60, 0x12, 0xf0, 0xb9, 0x2e, 0x38, - 0xa7, 0x12, 0xe7, 0x8d, 0x8a, 0x92, 0xed, 0x36, 0xdb, 0x98, 0x9c, 0xdd, 0x1f, 0xe1, 0x64, 0x9b, - 0xef, 0x55, 0x1f, 0xcb, 0x3a, 0x2a, 0xe8, 0x76, 0x5c, 0x73, 0xcd, 0x32, 0xfd, 0x65, 0xab, 0x6d, - 0x05, 0x8c, 0x29, 0x1f, 0xe2, 0xcb, 0xb1, 0xe6, 0x9a, 0x6b, 0xf5, 0x1a, 0x2f, 0xc7, 0xb1, 0x56, - 0xcc, 0x25, 0xda, 0x6a, 0x1b, 0x2d, 0xb2, 0xd6, 0xb5, 0xed, 0x35, 0xcf, 0x65, 0x0a, 0xc3, 0x1a, - 0x31, 0x4c, 0xdb, 0x72, 0x48, 0x41, 0x26, 0x9c, 0x1d, 0xb7, 0x7a, 0x1e, 0x50, 0x9c, 0x8f, 0x0f, - 0xcd, 0x03, 0x6c, 0x1a, 0x96, 0xdd, 0xb8, 0x67, 0x74, 0xee, 0x38, 0x8c, 0x53, 0x2f, 0x73, 0x11, - 0xf6, 0x46, 0x58, 0x8a, 0x95, 0x16, 0x74, 0x37, 0x51, 0x2a, 0x88, 0x09, 0x0f, 0xc5, 0xc3, 0xb8, - 0xea, 0xe3, 0xd8, 0x4d, 0x12, 0x20, 0x5f, 0xbe, 0xdb, 0x0a, 0x0a, 0x1c, 0x43, 0x88, 0x3e, 0xa5, - 0xc1, 0xb4, 0xdf, 0xf3, 0x03, 0xd2, 0x0e, 0xc7, 0x70, 0xe6, 0xb8, 0xc7, 0xc0, 0x54, 0xa9, 0x8d, - 0x18, 0x12, 0x9c, 0x40, 0x8a, 0x0c, 0xb8, 0xcc, 0x56, 0xf5, 0x66, 0xf5, 0x96, 0xd5, 0xda, 0x0a, - 0x1d, 0x9d, 0xd7, 0x88, 0xd7, 0x24, 0x4e, 0x30, 0x3b, 0xc3, 0xf6, 0x0d, 0x33, 0xa5, 0xa9, 0xe7, - 0x37, 0xc3, 0xfd, 0x60, 0xa0, 0x97, 0x61, 0x4e, 0x54, 0x2f, 0xbb, 0xf7, 0x52, 0x18, 0xce, 0x32, - 0x0c, 0xcc, 0x74, 0xa8, 0x9e, 0xdb, 0x0a, 0xf7, 0x81, 0x80, 0xea, 0x70, 0xce, 0x27, 0x1e, 0x7b, - 0x09, 0x21, 0xe1, 0xe6, 0xf1, 0x67, 0x51, 0x64, 0x35, 0xdc, 0x48, 0x57, 0xe3, 0xac, 0x3e, 0xe8, - 0x99, 0xd0, 0x31, 0xa9, 0x47, 0x0b, 0x9e, 0x5b, 0x6b, 0xcc, 0x9e, 0x63, 0xe3, 0x3b, 0xa7, 0xf8, - 0x1b, 0xc9, 0x2a, 0x9c, 0x6c, 0x4b, 0x79, 0x0b, 0x59, 0xb4, 0xd8, 0xf5, 0xfc, 0x60, 0xf6, 0x3c, - 0xeb, 0xcc, 0x78, 0x0b, 0xac, 0x56, 0xe0, 0x78, 0x3b, 0x74, 0x1d, 0xa6, 0x7d, 0xd2, 0x6c, 0xba, - 0xed, 0x8e, 0x10, 0xaf, 0x66, 0x2f, 0xb0, 0xd1, 0xf3, 0x2f, 0x18, 0xab, 0xc1, 0x89, 0x96, 0xa8, - 0x07, 0xe7, 0xc2, 0xc0, 0x34, 0xcb, 0x6e, 0x6b, 0xc5, 0xd8, 0x65, 0xac, 0xfa, 0xc5, 0x83, 0x4f, - 0xe0, 0xbc, 0x7c, 0xda, 0x9e, 0x7f, 0xae, 0x6b, 0x38, 0x81, 0x15, 0xf4, 0xf8, 0x72, 0x55, 0xd3, - 0xe0, 0x70, 0x16, 0x0e, 0xb4, 0x0c, 0xe7, 0x13, 0xc5, 0x37, 0x2c, 0x9b, 0xf8, 0xb3, 0x0f, 0xb0, - 0x69, 0x33, 0x1d, 0x49, 0x35, 0xa3, 0x1e, 0x67, 0xf6, 0x42, 0x77, 0xe0, 0x42, 0xc7, 0x73, 0x03, - 0xd2, 0x0c, 0x6e, 0x53, 0xf6, 0xc4, 0x16, 0x13, 0xf4, 0x67, 0x67, 0xd9, 0x5a, 0xb0, 0x57, 0xa0, - 0xb5, 0xac, 0x06, 0x38, 0xbb, 0x1f, 0xfa, 0xa2, 0x06, 0x57, 0xfc, 0xc0, 0x23, 0x46, 0xdb, 0x72, - 0x5a, 0x55, 0xd7, 0x71, 0x08, 0x23, 0x93, 0x75, 0x33, 0x32, 0xba, 0xbf, 0x54, 0x88, 0x4e, 0xe9, - 0xfb, 0x7b, 0x95, 0x2b, 0x8d, 0xbe, 0x90, 0xf1, 0x01, 0x98, 0xd1, 0xeb, 0x00, 0x6d, 0xd2, 0x76, - 0xbd, 0x1e, 0xa5, 0x48, 0xb3, 0x73, 0xc5, 0x8d, 0x98, 0x56, 0x42, 0x28, 0xfc, 0xf8, 0xc7, 0xde, - 0xaf, 0xa2, 0x4a, 0xac, 0xa0, 0xd3, 0xf7, 0x4a, 0x70, 0x21, 0xf3, 0xe2, 0xa1, 0x27, 0x80, 0xb7, - 0x5b, 0x90, 0x41, 0x6a, 0xc5, 0x93, 0x0f, 0x3b, 0x01, 0x2b, 0xf1, 0x2a, 0x9c, 0x6c, 0x4b, 0xd9, - 0x42, 0x76, 0x52, 0x6f, 0x34, 0xa2, 0xfe, 0xa5, 0x88, 0x2d, 0xac, 0x27, 0xea, 0x70, 0xaa, 0x35, - 0xaa, 0xc2, 0x59, 0x51, 0x56, 0xa7, 0x92, 0x95, 0x7f, 0xc3, 0x23, 0x92, 0xe1, 0xa6, 0x32, 0xca, - 0xd9, 0x7a, 0xb2, 0x12, 0xa7, 0xdb, 0xd3, 0x59, 0xd0, 0x1f, 0xea, 0x28, 0x86, 0xa3, 0x59, 0xac, - 0xc6, 0xab, 0x70, 0xb2, 0xad, 0x14, 0x7d, 0x63, 0x43, 0x18, 0x89, 0x66, 0xb1, 0x9a, 0xa8, 0xc3, - 0xa9, 0xd6, 0xfa, 0x7f, 0x1c, 0x86, 0x87, 0x0f, 0xc1, 0xac, 0xa1, 0x76, 0xf6, 0x72, 0x1f, 0xfd, - 0xe0, 0x1e, 0xee, 0xf3, 0x74, 0x72, 0x3e, 0xcf, 0xd1, 0xf1, 0x1d, 0xf6, 0x73, 0xfa, 0x79, 0x9f, - 0xf3, 0xe8, 0x28, 0x0f, 0xff, 0xf9, 0xdb, 0xd9, 0x9f, 0xbf, 0xe0, 0xaa, 0x1e, 0xb8, 0x5d, 0x3a, - 0x39, 0xdb, 0xa5, 0xe0, 0xaa, 0x1e, 0x62, 0x7b, 0xfd, 0xe9, 0x30, 0x3c, 0x72, 0x18, 0xc6, 0xb1, - 0xe0, 0xfe, 0xca, 0x20, 0x79, 0x27, 0xba, 0xbf, 0xf2, 0xfc, 0x9a, 0x4e, 0x70, 0x7f, 0x65, 0xa0, - 0x3c, 0xe9, 0xfd, 0x95, 0xb7, 0xaa, 0x27, 0xb5, 0xbf, 0xf2, 0x56, 0xf5, 0x10, 0xfb, 0xeb, 0x2f, - 0x93, 0xf7, 0x43, 0xc8, 0x2f, 0xd6, 0x61, 0xa8, 0xd9, 0xe9, 0x16, 0x24, 0x52, 0xcc, 0x40, 0xa8, - 0xba, 0x76, 0x17, 0x53, 0x18, 0x08, 0xc3, 0x28, 0xdf, 0x3f, 0x05, 0x49, 0x10, 0xf3, 0x90, 0xe1, - 0x5b, 0x12, 0x0b, 0x48, 0x74, 0xa9, 0x48, 0x67, 0x8b, 0xb4, 0x89, 0x67, 0xd8, 0x8d, 0xc0, 0xf5, - 0x8c, 0x56, 0x51, 0x6a, 0xc3, 0x96, 0x6a, 0x29, 0x01, 0x0b, 0xa7, 0xa0, 0xd3, 0x05, 0xe9, 0x58, - 0x66, 0x41, 0xfa, 0xc2, 0x16, 0x64, 0xad, 0x5e, 0xc3, 0x14, 0x86, 0xfe, 0x8f, 0xc6, 0x41, 0x09, - 0xfc, 0x86, 0x3e, 0x0c, 0x97, 0x0c, 0xdb, 0x76, 0xef, 0xad, 0x79, 0xd6, 0x8e, 0x65, 0x93, 0x16, - 0x31, 0x43, 0x66, 0xca, 0x17, 0x66, 0x64, 0x4c, 0x60, 0x5a, 0xc8, 0x6b, 0x84, 0xf3, 0xfb, 0xa3, - 0x37, 0x34, 0x38, 0xdb, 0x4c, 0x06, 0xdb, 0x1a, 0xc4, 0xd0, 0x24, 0x15, 0xb9, 0x8b, 0x9f, 0xa7, - 0x54, 0x31, 0x4e, 0xa3, 0x45, 0x3f, 0xa5, 0x71, 0xa5, 0x5c, 0xf8, 0x4c, 0x22, 0xbe, 0xd9, 0xcd, - 0x63, 0x7a, 0x50, 0x8c, 0xb4, 0x7b, 0xd1, 0xdb, 0x55, 0x1c, 0x21, 0xfa, 0xb2, 0x06, 0x17, 0xb6, - 0xb3, 0xde, 0x12, 0xc4, 0x97, 0xbd, 0x53, 0x74, 0x28, 0x39, 0x8f, 0x13, 0x9c, 0x9d, 0xcd, 0x6c, - 0x80, 0xb3, 0x07, 0x12, 0xae, 0x52, 0xa8, 0x5e, 0x15, 0x44, 0xa0, 0xf0, 0x2a, 0x25, 0xf4, 0xb4, - 0xd1, 0x2a, 0x85, 0x15, 0x38, 0x8e, 0x10, 0x75, 0x60, 0x7c, 0x5b, 0xea, 0xb4, 0x85, 0x1e, 0xab, - 0x5a, 0x14, 0xbb, 0xa2, 0x18, 0xe7, 0x86, 0x34, 0x61, 0x21, 0x8e, 0x90, 0xa0, 0x2d, 0x18, 0xdb, - 0xe6, 0x84, 0x48, 0xe8, 0x9f, 0x16, 0x06, 0x96, 0x8f, 0xb9, 0x1a, 0x44, 0x14, 0x61, 0x09, 0x5e, - 0xb5, 0xa2, 0x2d, 0x1f, 0xe0, 0xdc, 0xf1, 0x45, 0x0d, 0x2e, 0xec, 0x10, 0x2f, 0xb0, 0x9a, 0xc9, - 0x97, 0x9c, 0xf1, 0xe2, 0x32, 0xfc, 0xf3, 0x59, 0x00, 0xf9, 0x36, 0xc9, 0xac, 0xc2, 0xd9, 0x43, - 0xa0, 0x12, 0x3d, 0x57, 0xc8, 0x37, 0x02, 0x23, 0xb0, 0x9a, 0xeb, 0xee, 0x36, 0x71, 0xa2, 0xfc, - 0x24, 0x4c, 0x13, 0x54, 0xe6, 0x12, 0xfd, 0x52, 0x7e, 0x33, 0xdc, 0x0f, 0x86, 0xfe, 0x7d, 0x0d, - 0x52, 0x6a, 0x65, 0xf4, 0x0b, 0x1a, 0x4c, 0x6e, 0x12, 0x23, 0xe8, 0x7a, 0xe4, 0xa6, 0x11, 0x84, - 0x1e, 0xe7, 0xcf, 0x1f, 0x87, 0x36, 0x7b, 0xfe, 0x86, 0x02, 0x98, 0x1b, 0x04, 0x84, 0x41, 0x23, - 0xd5, 0x2a, 0x1c, 0x1b, 0xc1, 0xdc, 0xb3, 0x70, 0x36, 0xd5, 0xf1, 0x48, 0x2f, 0x8c, 0xff, 0x4a, - 0x83, 0xac, 0x94, 0x3a, 0xe8, 0x65, 0x18, 0x31, 0x4c, 0x33, 0x8c, 0x91, 0xff, 0x74, 0x31, 0xdb, - 0x14, 0x53, 0x75, 0xec, 0x67, 0x3f, 0x31, 0x07, 0x8b, 0x6e, 0x00, 0x32, 0x62, 0x2f, 0xdc, 0x2b, - 0x91, 0xbb, 0x2a, 0x7b, 0x09, 0x5b, 0x48, 0xd5, 0xe2, 0x8c, 0x1e, 0xfa, 0xcf, 0x6a, 0x80, 0xd2, - 0x61, 0x46, 0x91, 0x07, 0x65, 0xb1, 0x95, 0xe5, 0x57, 0xaa, 0x15, 0x74, 0x29, 0x89, 0xf9, 0x47, - 0x45, 0x86, 0x4e, 0xa2, 0xc0, 0xc7, 0x21, 0x1e, 0xfd, 0xaf, 0x34, 0x88, 0xe2, 0x68, 0xa3, 0x77, - 0xc1, 0x84, 0x49, 0xfc, 0xa6, 0x67, 0x75, 0x82, 0xc8, 0x9b, 0x2a, 0xf4, 0xca, 0xa8, 0x45, 0x55, - 0x58, 0x6d, 0x87, 0x74, 0x18, 0x0d, 0x0c, 0x7f, 0xbb, 0x5e, 0x13, 0x42, 0x25, 0x63, 0x01, 0xd6, - 0x59, 0x09, 0x16, 0x35, 0x51, 0xc8, 0xb0, 0xa1, 0x43, 0x84, 0x0c, 0x43, 0x9b, 0xc7, 0x10, 0x1f, - 0x0d, 0x1d, 0x1c, 0x1b, 0x4d, 0xff, 0xb5, 0x12, 0x9c, 0xa1, 0x4d, 0x56, 0x0c, 0xcb, 0x09, 0x88, - 0xc3, 0x7c, 0x07, 0x0a, 0x2e, 0x42, 0x0b, 0xa6, 0x82, 0x98, 0x6f, 0xdc, 0xd1, 0x3d, 0xcb, 0x42, - 0x6b, 0x9a, 0xb8, 0x47, 0x5c, 0x1c, 0x2e, 0x7a, 0x5a, 0x3a, 0x6f, 0x70, 0xf1, 0xfb, 0x61, 0xb9, - 0x55, 0x99, 0x47, 0xc6, 0x7d, 0xe1, 0x68, 0x18, 0x06, 0x5f, 0x8f, 0xf9, 0x69, 0x3c, 0x05, 0x53, - 0xc2, 0x88, 0x9a, 0xc7, 0x7e, 0x13, 0xe2, 0x37, 0xbb, 0x61, 0x6e, 0xa8, 0x15, 0x38, 0xde, 0x4e, - 0xff, 0x66, 0x09, 0xe2, 0x21, 0xde, 0x8b, 0xae, 0x52, 0x3a, 0xf0, 0x5d, 0xe9, 0xc4, 0x02, 0xdf, - 0xbd, 0x83, 0xe5, 0x47, 0xe1, 0x89, 0xb4, 0xf8, 0x13, 0xb9, 0x9a, 0xd5, 0x84, 0xa7, 0xc1, 0x0a, - 0x5b, 0x44, 0xcb, 0x3a, 0x7c, 0xe4, 0x65, 0x7d, 0x97, 0xb0, 0xae, 0x1c, 0x89, 0x85, 0x1f, 0x94, - 0xd6, 0x95, 0x67, 0x63, 0x1d, 0x15, 0x57, 0x93, 0xaf, 0x69, 0x30, 0x26, 0x62, 0xeb, 0x1e, 0xc2, - 0x95, 0x69, 0x13, 0x46, 0x98, 0xc8, 0x33, 0x08, 0x37, 0xd8, 0xd8, 0x72, 0xdd, 0x20, 0x16, 0x61, - 0x98, 0xf9, 0x0e, 0xb0, 0x7f, 0x31, 0x07, 0xcf, 0x0c, 0xec, 0xbc, 0xe6, 0x96, 0x15, 0x90, 0x66, - 0x20, 0xe3, 0x96, 0x4a, 0x03, 0x3b, 0xa5, 0x1c, 0xc7, 0x5a, 0xe9, 0x5f, 0x1a, 0x86, 0xab, 0x02, - 0x70, 0x8a, 0x45, 0x0a, 0x09, 0x5c, 0x0f, 0xce, 0x89, 0x6f, 0x5b, 0xf3, 0x0c, 0x2b, 0x34, 0x3d, - 0x28, 0x26, 0xfa, 0x8a, 0x64, 0x71, 0x29, 0x70, 0x38, 0x0b, 0x07, 0x8f, 0xc0, 0xc9, 0x8a, 0x6f, - 0x11, 0xc3, 0x0e, 0xb6, 0x24, 0xee, 0xd2, 0x20, 0x11, 0x38, 0xd3, 0xf0, 0x70, 0x26, 0x16, 0x66, - 0xfa, 0x20, 0x2a, 0xaa, 0x1e, 0x31, 0x54, 0xbb, 0x8b, 0x01, 0xcc, 0xff, 0x57, 0x32, 0x21, 0xe2, - 0x1c, 0x4c, 0x4c, 0x87, 0x68, 0xec, 0x32, 0x95, 0x04, 0x26, 0x81, 0x67, 0xb1, 0x48, 0xd1, 0xa1, - 0x16, 0x7d, 0x25, 0x5e, 0x85, 0x93, 0x6d, 0xd1, 0x75, 0x98, 0x66, 0xa6, 0x24, 0x51, 0xa8, 0xab, - 0x91, 0x28, 0x9a, 0xc2, 0x6a, 0xac, 0x06, 0x27, 0x5a, 0xea, 0xbf, 0xae, 0xc1, 0xa4, 0xba, 0xed, - 0x0e, 0xe1, 0xd7, 0xd4, 0x55, 0x2e, 0xc3, 0x01, 0x7c, 0x6e, 0x54, 0xac, 0x87, 0xb9, 0x0f, 0x3f, - 0x3b, 0x04, 0xe7, 0x32, 0xfa, 0x30, 0xc3, 0x00, 0x92, 0xb8, 0x58, 0x07, 0x31, 0x0c, 0x48, 0x5d, - 0xd2, 0xa1, 0x61, 0x40, 0xb2, 0x06, 0xa7, 0xf0, 0xa2, 0xe7, 0x61, 0xa8, 0xe9, 0x59, 0x62, 0x59, - 0x9e, 0x2a, 0x24, 0x16, 0xe2, 0xfa, 0xe2, 0x84, 0xc0, 0x38, 0x54, 0xc5, 0x75, 0x4c, 0x01, 0xd2, - 0xeb, 0x41, 0x3d, 0xd4, 0xf2, 0xae, 0x66, 0xd7, 0x83, 0x7a, 0xf6, 0x7d, 0x1c, 0x6f, 0x87, 0x5e, - 0x84, 0x59, 0xc1, 0xaf, 0x4b, 0x4f, 0x66, 0xd7, 0xf1, 0x03, 0x7a, 0xfe, 0x02, 0x41, 0x4e, 0x1f, - 0xdc, 0xdf, 0xab, 0xcc, 0xde, 0xce, 0x69, 0x83, 0x73, 0x7b, 0xeb, 0x7f, 0x31, 0x04, 0x13, 0x4a, - 0xfc, 0x71, 0xb4, 0x32, 0x88, 0xa2, 0x23, 0x9a, 0xb1, 0x54, 0x76, 0xac, 0xc0, 0x50, 0xab, 0xd3, - 0x2d, 0xa8, 0xe9, 0x08, 0xc1, 0xdd, 0xa4, 0xe0, 0x5a, 0x9d, 0x2e, 0x7a, 0x3e, 0xd4, 0x9d, 0x14, - 0xd3, 0x6e, 0x84, 0x7e, 0x27, 0x09, 0xfd, 0x89, 0x3c, 0x2e, 0xc3, 0xb9, 0xc7, 0xa5, 0x0d, 0x63, - 0xbe, 0x50, 0xac, 0x8c, 0x14, 0x8f, 0x1d, 0xa3, 0xac, 0xb4, 0x50, 0xa4, 0x70, 0xa9, 0x4c, 0xea, - 0x59, 0x24, 0x0e, 0xca, 0xf1, 0x75, 0x99, 0x37, 0x2b, 0x13, 0x37, 0xcb, 0x9c, 0xe3, 0xbb, 0xcb, - 0x4a, 0xb0, 0xa8, 0x49, 0x5d, 0x24, 0x63, 0x87, 0xba, 0x48, 0xfe, 0x6e, 0x09, 0x50, 0x7a, 0x18, - 0xe8, 0x61, 0x18, 0x61, 0xde, 0xf0, 0x82, 0x62, 0x84, 0xfc, 0x39, 0xf3, 0x87, 0xc6, 0xbc, 0x0e, - 0x35, 0x44, 0x24, 0x8c, 0x62, 0x9f, 0x93, 0x59, 0xd6, 0x08, 0x7c, 0x4a, 0xd8, 0x8c, 0xab, 0x31, - 0xd7, 0x89, 0xac, 0x9b, 0xf9, 0x2e, 0x8c, 0xb5, 0x2d, 0x87, 0x3d, 0xef, 0x15, 0xd3, 0x37, 0x71, - 0x03, 0x00, 0x0e, 0x02, 0x4b, 0x58, 0xfa, 0x9f, 0x96, 0xe8, 0xd6, 0x8f, 0xf8, 0xd2, 0x1e, 0x80, - 0xd1, 0x0d, 0x5c, 0xce, 0xe0, 0x88, 0x13, 0x50, 0x2f, 0xf6, 0x95, 0x43, 0xa0, 0x0b, 0x21, 0x40, - 0xfe, 0x30, 0x15, 0xfd, 0xc6, 0x0a, 0x32, 0x8a, 0x3a, 0xb0, 0xda, 0xe4, 0x05, 0xcb, 0x31, 0xdd, - 0x7b, 0x62, 0x79, 0x07, 0x45, 0xbd, 0x1e, 0x02, 0xe4, 0xa8, 0xa3, 0xdf, 0x58, 0x41, 0x46, 0x49, - 0x0b, 0x13, 0x6f, 0x1d, 0x96, 0x10, 0x42, 0x8c, 0xcd, 0xb5, 0x6d, 0x79, 0x77, 0x96, 0x39, 0x69, - 0xa9, 0xe6, 0xb4, 0xc1, 0xb9, 0xbd, 0xf5, 0xdf, 0xd0, 0xe0, 0x42, 0xe6, 0x52, 0xa0, 0x9b, 0x70, - 0x36, 0x32, 0xc6, 0x52, 0x89, 0x7d, 0x39, 0x4a, 0x44, 0x72, 0x3b, 0xd9, 0x00, 0xa7, 0xfb, 0xf0, - 0x6c, 0xb7, 0xa9, 0xcb, 0x44, 0x58, 0x72, 0xa9, 0x0c, 0x8c, 0x5a, 0x8d, 0xb3, 0xfa, 0xe8, 0x1f, - 0x8e, 0x0d, 0x36, 0x5a, 0x2c, 0x7a, 0x32, 0x36, 0x48, 0x2b, 0x74, 0x5d, 0x0b, 0x4f, 0xc6, 0x22, - 0x2d, 0xc4, 0xbc, 0x0e, 0x3d, 0xa4, 0x3a, 0x84, 0x86, 0x74, 0x4b, 0x3a, 0x85, 0xea, 0x3f, 0x09, - 0x0f, 0xe4, 0xbc, 0x57, 0xa2, 0x1a, 0x4c, 0xfa, 0xf7, 0x8c, 0xce, 0x22, 0xd9, 0x32, 0x76, 0x2c, - 0x11, 0x60, 0x80, 0x1b, 0xd9, 0x4d, 0x36, 0x94, 0xf2, 0xfb, 0x89, 0xdf, 0x38, 0xd6, 0x4b, 0x0f, - 0x00, 0x84, 0x31, 0xa6, 0xe5, 0xb4, 0xd0, 0x26, 0x94, 0x0d, 0x91, 0x6c, 0x55, 0xec, 0xe3, 0xf7, - 0x15, 0x12, 0xd5, 0x05, 0x0c, 0x6e, 0x25, 0x2e, 0x7f, 0xe1, 0x10, 0xb6, 0xfe, 0x4f, 0x34, 0xb8, - 0x98, 0xed, 0x52, 0x7e, 0x08, 0x06, 0xa4, 0x0d, 0x13, 0x5e, 0xd4, 0x4d, 0x6c, 0xfa, 0x77, 0xab, - 0x31, 0x45, 0x95, 0x20, 0x5a, 0x94, 0x39, 0xab, 0x7a, 0xae, 0x2f, 0xbf, 0x7c, 0x32, 0xcc, 0x68, - 0x28, 0x18, 0x29, 0x23, 0xc1, 0x2a, 0x7c, 0xfd, 0xf7, 0x4a, 0x00, 0xab, 0x24, 0xb8, 0xe7, 0x7a, - 0xdb, 0x74, 0x89, 0x1e, 0x8c, 0xc9, 0x03, 0xe5, 0x1f, 0x5c, 0x58, 0x83, 0x07, 0x61, 0xb8, 0xe3, - 0x9a, 0xbe, 0x20, 0x7f, 0x6c, 0x20, 0xcc, 0x4e, 0x89, 0x95, 0xa2, 0x0a, 0x8c, 0xb0, 0xe7, 0x09, - 0x71, 0x33, 0x31, 0x69, 0x82, 0xf2, 0x82, 0x3e, 0xe6, 0xe5, 0x3c, 0x85, 0x16, 0xf3, 0xbc, 0xf0, - 0x85, 0x78, 0x24, 0x52, 0x68, 0xf1, 0x32, 0x1c, 0xd6, 0xa2, 0xeb, 0x00, 0x56, 0xe7, 0x86, 0xd1, - 0xb6, 0x6c, 0xca, 0x99, 0x8e, 0x86, 0x19, 0x5b, 0xa1, 0xbe, 0x26, 0x4b, 0xef, 0xef, 0x55, 0xca, - 0xe2, 0x57, 0x0f, 0x2b, 0xad, 0xf5, 0xbf, 0x1e, 0x82, 0x58, 0x76, 0xe3, 0x48, 0x13, 0xa4, 0x9d, - 0x8c, 0x26, 0xe8, 0x45, 0x98, 0xb5, 0x5d, 0xc3, 0x5c, 0x34, 0x6c, 0x7a, 0x1a, 0xbd, 0x06, 0xff, - 0x8c, 0x86, 0xd3, 0x0a, 0x53, 0xd8, 0x32, 0xaa, 0xb4, 0x9c, 0xd3, 0x06, 0xe7, 0xf6, 0x46, 0x41, - 0x98, 0x53, 0x79, 0xa8, 0xb8, 0x93, 0xa2, 0xba, 0x16, 0xf3, 0xaa, 0xbf, 0x4e, 0xc8, 0x60, 0x24, - 0xd2, 0x2e, 0x7f, 0x52, 0x83, 0x0b, 0x64, 0x97, 0xfb, 0xab, 0xad, 0x7b, 0xc6, 0xe6, 0xa6, 0xd5, - 0x14, 0xd6, 0xa3, 0xfc, 0xc3, 0x2e, 0xef, 0xef, 0x55, 0x2e, 0x2c, 0x65, 0x35, 0xb8, 0xbf, 0x57, - 0xb9, 0x96, 0xe9, 0x3e, 0xc8, 0x3e, 0x6b, 0x66, 0x17, 0x9c, 0x8d, 0x6a, 0xee, 0x69, 0x98, 0x38, - 0x82, 0xcf, 0x41, 0xcc, 0x49, 0xf0, 0xf7, 0x4b, 0x30, 0x49, 0xf7, 0xdd, 0xb2, 0xdb, 0x34, 0xec, - 0xda, 0x6a, 0xe3, 0x08, 0x39, 0xc1, 0xd1, 0x32, 0x9c, 0xdf, 0x74, 0xbd, 0x26, 0x59, 0xaf, 0xae, - 0xad, 0xbb, 0xe2, 0x61, 0xa4, 0xb6, 0xda, 0x10, 0x54, 0x9a, 0x89, 0x7a, 0x37, 0x32, 0xea, 0x71, - 0x66, 0x2f, 0x74, 0x07, 0x2e, 0x44, 0xe5, 0x77, 0x3b, 0xdc, 0xdc, 0x84, 0x82, 0x1b, 0x8a, 0xcc, - 0x65, 0x6e, 0x64, 0x35, 0xc0, 0xd9, 0xfd, 0x90, 0x01, 0x97, 0x45, 0xe4, 0x90, 0x1b, 0xae, 0x77, - 0xcf, 0xf0, 0xcc, 0x38, 0xd8, 0xe1, 0x48, 0x71, 0x5c, 0xcb, 0x6f, 0x86, 0xfb, 0xc1, 0xd0, 0x7f, - 0x69, 0x14, 0x14, 0xa7, 0xb2, 0x23, 0x24, 0x5d, 0xfa, 0x55, 0x0d, 0xce, 0x37, 0x6d, 0x8b, 0x38, - 0x41, 0xc2, 0x83, 0x88, 0x93, 0xa3, 0xbb, 0x85, 0xbc, 0xdd, 0x3a, 0xc4, 0xa9, 0xd7, 0x84, 0x75, - 0x4e, 0x35, 0x03, 0xb8, 0xb0, 0x60, 0xca, 0xa8, 0xc1, 0x99, 0x83, 0x61, 0xf3, 0x61, 0xe5, 0xf5, - 0x9a, 0x1a, 0xf2, 0xa0, 0x2a, 0xca, 0x70, 0x58, 0x8b, 0x9e, 0x80, 0x89, 0x96, 0xe7, 0x76, 0x3b, - 0x7e, 0x95, 0x99, 0x04, 0xf3, 0xbd, 0xcf, 0xf8, 0xc2, 0x9b, 0x51, 0x31, 0x56, 0xdb, 0x50, 0x2e, - 0x97, 0xff, 0x5c, 0xf3, 0xc8, 0xa6, 0xb5, 0x2b, 0x88, 0x1c, 0xe3, 0x72, 0x6f, 0x2a, 0xe5, 0x38, - 0xd6, 0x8a, 0x79, 0x2d, 0xfb, 0x7e, 0x97, 0x78, 0x77, 0xf1, 0xb2, 0xc8, 0xb6, 0xc0, 0xbd, 0x96, - 0x65, 0x21, 0x8e, 0xea, 0xd1, 0xe7, 0x34, 0x98, 0xf6, 0xc8, 0xab, 0x5d, 0xcb, 0x23, 0x26, 0x43, - 0xea, 0x0b, 0xcf, 0x3e, 0x3c, 0x98, 0x37, 0xe1, 0x3c, 0x8e, 0x01, 0xe5, 0x14, 0x22, 0x54, 0xae, - 0xc5, 0x2b, 0x71, 0x62, 0x04, 0x74, 0xa9, 0x7c, 0xab, 0xe5, 0x58, 0x4e, 0x6b, 0xc1, 0x6e, 0xf9, - 0xb3, 0x65, 0x46, 0xf4, 0x38, 0x0b, 0x1d, 0x15, 0x63, 0xb5, 0x0d, 0x15, 0x2f, 0xbb, 0x3e, 0x3d, - 0xf7, 0x6d, 0xc2, 0xd7, 0x77, 0x3c, 0xd2, 0x3e, 0xde, 0x55, 0x2b, 0x70, 0xbc, 0x1d, 0xba, 0x0e, - 0xd3, 0xb2, 0x40, 0xac, 0x32, 0xf0, 0x58, 0x77, 0x74, 0x9c, 0x77, 0x63, 0x35, 0x38, 0xd1, 0x72, - 0x6e, 0x01, 0xce, 0x65, 0x4c, 0xf3, 0x48, 0xc4, 0xe5, 0xff, 0x6a, 0x70, 0x81, 0x67, 0x8c, 0x94, - 0x79, 0x1a, 0x64, 0x50, 0xbb, 0xec, 0xf8, 0x70, 0xda, 0x89, 0xc6, 0x87, 0xfb, 0x01, 0xc4, 0xc1, - 0xd3, 0x7f, 0xbd, 0x04, 0x6f, 0x3d, 0xf0, 0x5c, 0xa2, 0x7f, 0xa8, 0xc1, 0x04, 0xd9, 0x0d, 0x3c, - 0x23, 0xf4, 0x9b, 0xa0, 0x9b, 0x74, 0xf3, 0x44, 0x88, 0xc0, 0xfc, 0x52, 0x84, 0x88, 0x6f, 0xdc, - 0x90, 0xc5, 0x52, 0x6a, 0xb0, 0x3a, 0x1e, 0x2a, 0xb4, 0xf2, 0x58, 0x90, 0xea, 0x33, 0x85, 0x48, - 0xe4, 0x2b, 0x6a, 0xe6, 0xde, 0x0f, 0x33, 0x49, 0xc8, 0x47, 0xda, 0x2b, 0xbf, 0x5b, 0x82, 0xb1, - 0x35, 0xcf, 0xa5, 0xdc, 0xdf, 0x29, 0x04, 0x3f, 0x30, 0x62, 0xf1, 0xd1, 0x0b, 0xf9, 0x33, 0x8b, - 0xc1, 0xe6, 0xe6, 0x66, 0xb0, 0x12, 0xb9, 0x19, 0x16, 0x06, 0x41, 0xd2, 0x3f, 0x19, 0xc3, 0xd7, - 0x35, 0x98, 0x10, 0x2d, 0x4f, 0xc1, 0xc5, 0xff, 0x23, 0x71, 0x17, 0xff, 0xf7, 0x0e, 0x30, 0xaf, - 0x1c, 0xdf, 0xfe, 0x2f, 0x6a, 0x30, 0x25, 0x5a, 0xac, 0x90, 0xf6, 0x06, 0xf1, 0xd0, 0x0d, 0x18, - 0xf3, 0xbb, 0xec, 0x43, 0x8a, 0x09, 0x5d, 0x56, 0xe5, 0x09, 0x6f, 0xc3, 0x68, 0xb2, 0x6c, 0xd4, - 0xbc, 0x89, 0x92, 0xf1, 0x80, 0x17, 0x60, 0xd9, 0x99, 0x4a, 0x2f, 0x9e, 0x6b, 0xa7, 0x82, 0x3e, - 0x61, 0xd7, 0x26, 0x98, 0xd5, 0x50, 0xc6, 0x9c, 0xfe, 0x95, 0x2a, 0x3c, 0xc6, 0x98, 0xd3, 0x6a, - 0x1f, 0xf3, 0x72, 0xfd, 0x53, 0xc3, 0xe1, 0x62, 0xb3, 0xa8, 0xe4, 0xb7, 0x60, 0xbc, 0xe9, 0x11, - 0x23, 0x20, 0xe6, 0x62, 0xef, 0x30, 0x83, 0x63, 0xd7, 0x55, 0x55, 0xf6, 0xc0, 0x51, 0x67, 0x7a, - 0x33, 0xa8, 0x2f, 0x43, 0xa5, 0xe8, 0x12, 0xcd, 0x7d, 0x15, 0x7a, 0x1f, 0x8c, 0xb8, 0xf7, 0x9c, - 0xd0, 0xc0, 0xa4, 0x2f, 0x62, 0x36, 0x95, 0x3b, 0xb4, 0x35, 0xe6, 0x9d, 0xd4, 0xa0, 0x67, 0xc3, - 0x7d, 0x82, 0x9e, 0xd9, 0x30, 0xd6, 0x66, 0x9f, 0x61, 0xa0, 0x00, 0xf8, 0xb1, 0x0f, 0xaa, 0xa6, - 0x48, 0x62, 0x90, 0xb1, 0x44, 0x41, 0x6f, 0x78, 0x7a, 0x0b, 0xf9, 0x1d, 0xa3, 0x49, 0xd4, 0x1b, - 0x7e, 0x55, 0x16, 0xe2, 0xa8, 0x1e, 0xf5, 0xe2, 0xd1, 0xf4, 0xc6, 0x8a, 0x6b, 0xf0, 0xc4, 0xf0, - 0x94, 0x00, 0x7a, 0x7c, 0xe9, 0x73, 0x23, 0xea, 0xfd, 0xdc, 0x70, 0xb8, 0x49, 0x45, 0x3e, 0x8b, - 0xec, 0x0c, 0xca, 0x5a, 0xa1, 0x0c, 0xca, 0x3f, 0x2e, 0xa3, 0xbe, 0x96, 0x62, 0xe9, 0xbc, 0xc2, - 0xa8, 0xaf, 0x93, 0x02, 0x75, 0x2c, 0xd2, 0x6b, 0x17, 0xce, 0xf9, 0x81, 0x61, 0x93, 0x86, 0x25, - 0x34, 0x1d, 0x7e, 0x60, 0xb4, 0x3b, 0x05, 0xc2, 0xae, 0x72, 0x2f, 0x83, 0x34, 0x28, 0x9c, 0x05, - 0x1f, 0xfd, 0x8c, 0x06, 0xb3, 0xac, 0x7c, 0xa1, 0x1b, 0xb8, 0x3c, 0x3e, 0x78, 0x84, 0xfc, 0xe8, - 0xcf, 0xcf, 0x4c, 0x00, 0x6c, 0xe4, 0xc0, 0xc3, 0xb9, 0x98, 0xd0, 0xeb, 0x70, 0x81, 0xde, 0xc0, - 0x0b, 0xcd, 0xc0, 0xda, 0xb1, 0x82, 0x5e, 0x34, 0x84, 0xa3, 0xc7, 0x5a, 0x65, 0xc2, 0xc6, 0x72, - 0x16, 0x30, 0x9c, 0x8d, 0x43, 0xff, 0x4b, 0x0d, 0x50, 0x7a, 0x0b, 0x21, 0x1b, 0xca, 0xa6, 0x34, - 0xfb, 0xd7, 0x8e, 0x25, 0xd4, 0x63, 0x48, 0x99, 0x43, 0x6f, 0x81, 0x10, 0x03, 0x72, 0x61, 0xfc, - 0xde, 0x96, 0x15, 0x10, 0xdb, 0xf2, 0x83, 0x63, 0x8a, 0x2c, 0x19, 0x86, 0x59, 0x7b, 0x41, 0x02, - 0xc6, 0x11, 0x0e, 0xfd, 0xe7, 0x87, 0xa1, 0x1c, 0x06, 0xba, 0x3e, 0xf8, 0x25, 0xb6, 0x0b, 0xa8, - 0xa9, 0x24, 0x0b, 0x1b, 0x44, 0x03, 0xc3, 0x98, 0xb0, 0x6a, 0x0a, 0x18, 0xce, 0x40, 0x80, 0x5e, - 0x87, 0xf3, 0x96, 0xb3, 0xe9, 0x19, 0x7e, 0xe0, 0x75, 0x99, 0xae, 0x7c, 0x90, 0x9c, 0x5b, 0x4c, - 0x86, 0xaa, 0x67, 0x80, 0xc3, 0x99, 0x48, 0x10, 0x81, 0x31, 0x1e, 0xcf, 0x5f, 0x06, 0xfd, 0x2b, - 0x94, 0x7d, 0x95, 0xe7, 0x09, 0x88, 0xa8, 0x26, 0xff, 0xed, 0x63, 0x09, 0x9b, 0x07, 0xe4, 0xe0, - 0xff, 0xcb, 0x57, 0x63, 0xb1, 0xef, 0xab, 0xc5, 0xf1, 0x45, 0x89, 0x7c, 0x79, 0x40, 0x8e, 0x78, - 0x21, 0x4e, 0x22, 0xd4, 0xff, 0x48, 0x83, 0x11, 0xee, 0x4e, 0x7b, 0xf2, 0x1c, 0xdc, 0x4f, 0xc6, - 0x38, 0xb8, 0x42, 0x69, 0x83, 0xd8, 0x50, 0x73, 0x13, 0xda, 0x7c, 0x4d, 0x83, 0x71, 0xd6, 0xe2, - 0x14, 0x58, 0xaa, 0x97, 0xe3, 0x2c, 0xd5, 0xd3, 0x85, 0x67, 0x93, 0xc3, 0x50, 0xfd, 0xd1, 0x90, - 0x98, 0x0b, 0xe3, 0x58, 0xea, 0x70, 0x4e, 0xd8, 0xac, 0x2e, 0x5b, 0x9b, 0x84, 0x6e, 0xf1, 0x9a, - 0xd1, 0xe3, 0x0f, 0x44, 0x23, 0xc2, 0x63, 0x2a, 0x5d, 0x8d, 0xb3, 0xfa, 0xa0, 0xdf, 0xd7, 0x28, - 0x6f, 0x10, 0x78, 0x56, 0x73, 0xa0, 0x2c, 0x31, 0xe1, 0xd8, 0xe6, 0x57, 0x38, 0x30, 0x2e, 0x99, - 0xdc, 0x8d, 0x98, 0x04, 0x56, 0x7a, 0x7f, 0xaf, 0x52, 0xc9, 0x50, 0x99, 0x45, 0x19, 0x23, 0xfc, - 0xe0, 0x93, 0x7f, 0xd6, 0xb7, 0x09, 0x53, 0x53, 0xcb, 0x11, 0xa3, 0x5b, 0x30, 0xe2, 0x37, 0xdd, - 0x0e, 0x39, 0x4a, 0xde, 0xab, 0x70, 0x81, 0x1b, 0xb4, 0x27, 0xe6, 0x00, 0xe6, 0x5e, 0x81, 0x49, - 0x75, 0xe4, 0x19, 0x92, 0x4f, 0x4d, 0x95, 0x7c, 0x8e, 0xfc, 0xd2, 0xa5, 0x4a, 0x4a, 0x7f, 0x50, - 0x82, 0x51, 0x9e, 0x7d, 0xf9, 0x10, 0xca, 0x78, 0x4b, 0x86, 0xe6, 0x1f, 0x20, 0xa9, 0xbc, 0x1a, - 0xc7, 0xf2, 0x25, 0xd7, 0x51, 0xd6, 0x40, 0x8d, 0xce, 0x8f, 0x9c, 0x30, 0xba, 0xe9, 0x50, 0xf1, - 0xdc, 0x3c, 0x7c, 0x62, 0x27, 0x1d, 0xcf, 0xf4, 0x4f, 0x34, 0x98, 0x8c, 0x85, 0x8b, 0x6d, 0xc3, - 0x90, 0x17, 0x66, 0x6d, 0x2b, 0xfa, 0x56, 0x21, 0x2d, 0x9f, 0x2e, 0xf7, 0x69, 0x84, 0x29, 0x9e, - 0x30, 0xb2, 0x6c, 0xe9, 0x98, 0x22, 0xcb, 0xea, 0x9f, 0xd7, 0xe0, 0xa2, 0x9c, 0x50, 0x3c, 0x6e, - 0x12, 0x7a, 0x14, 0xca, 0x46, 0xc7, 0x62, 0x2a, 0x35, 0x55, 0x29, 0xb9, 0xb0, 0x56, 0x67, 0x65, - 0x38, 0xac, 0x45, 0xef, 0x80, 0xb2, 0xdc, 0x78, 0x82, 0xed, 0x0c, 0x69, 0x56, 0xf8, 0xfa, 0x12, - 0xb6, 0x40, 0x6f, 0x53, 0xb2, 0x27, 0x8c, 0x44, 0x7c, 0x42, 0x88, 0x98, 0xbf, 0x02, 0xeb, 0xef, - 0x86, 0xf1, 0x46, 0xe3, 0xd6, 0x42, 0xb3, 0x49, 0x7c, 0xff, 0x08, 0xca, 0x65, 0xfd, 0x33, 0x43, - 0x30, 0x25, 0x02, 0xc0, 0x59, 0x8e, 0x69, 0x39, 0xad, 0x53, 0xb8, 0x53, 0xd6, 0x61, 0x9c, 0x6b, - 0x33, 0x0e, 0xc8, 0xb0, 0xd7, 0x90, 0x8d, 0x92, 0x61, 0x96, 0xc3, 0x0a, 0x1c, 0x01, 0x42, 0xb7, - 0x61, 0xf4, 0x55, 0x4a, 0xdf, 0xe4, 0xb9, 0x38, 0x14, 0x99, 0x09, 0x37, 0x3d, 0x23, 0x8d, 0x3e, - 0x16, 0x20, 0x90, 0xcf, 0x4c, 0xf3, 0x18, 0xc3, 0x35, 0x48, 0x84, 0x89, 0xd8, 0xca, 0x86, 0xb9, - 0x53, 0x26, 0x85, 0x85, 0x1f, 0xfb, 0x85, 0x43, 0x44, 0x2c, 0x46, 0x7c, 0xac, 0xc7, 0x9b, 0x24, - 0x46, 0x7c, 0x6c, 0xcc, 0x39, 0x57, 0xe3, 0xd3, 0x70, 0x21, 0x73, 0x31, 0x0e, 0x66, 0x67, 0xf5, - 0xdf, 0x2a, 0xc1, 0x70, 0x83, 0x10, 0xf3, 0x14, 0x76, 0xe6, 0xcb, 0x31, 0x6e, 0xe7, 0x7d, 0x85, - 0xa3, 0xd4, 0xe7, 0x29, 0xab, 0x36, 0x13, 0xca, 0xaa, 0xf7, 0x17, 0xc6, 0xd0, 0x5f, 0x53, 0xf5, - 0xcb, 0x25, 0x00, 0xda, 0x6c, 0xd1, 0x68, 0x6e, 0x73, 0x8a, 0x13, 0xee, 0x66, 0x2d, 0x4e, 0x71, - 0xd2, 0xdb, 0xf0, 0x34, 0x1f, 0x6f, 0x75, 0x18, 0xf5, 0xd8, 0x4d, 0x24, 0xde, 0x3d, 0x80, 0xa7, - 0x7d, 0xa6, 0x25, 0x58, 0xd4, 0xc4, 0xa9, 0xc5, 0xf0, 0x31, 0x51, 0x0b, 0x7d, 0x17, 0x58, 0x9e, - 0xce, 0xda, 0x6a, 0x03, 0xb5, 0x95, 0xd5, 0x29, 0x15, 0xe7, 0xe5, 0x05, 0xb8, 0x03, 0x4f, 0xf9, - 0x67, 0x34, 0x38, 0x93, 0x68, 0x7b, 0x08, 0x99, 0xee, 0x44, 0x68, 0xa6, 0xfe, 0x87, 0x1a, 0x94, - 0xe9, 0x58, 0x4e, 0x81, 0xd0, 0xfc, 0xff, 0x71, 0x42, 0xf3, 0x9e, 0xa2, 0x4b, 0x9c, 0x43, 0x5f, - 0xfe, 0xbc, 0x04, 0x2c, 0x1d, 0x84, 0x30, 0x51, 0x50, 0x5e, 0xfe, 0xb5, 0x9c, 0x97, 0xff, 0xab, - 0xc2, 0x70, 0x20, 0xa1, 0xa3, 0x54, 0x8c, 0x07, 0xde, 0xa1, 0xd8, 0x06, 0x0c, 0xc5, 0x8f, 0x4d, - 0x86, 0x7d, 0xc0, 0x6b, 0x30, 0xe5, 0x6f, 0xb9, 0x6e, 0x10, 0xc6, 0x1f, 0x18, 0x2e, 0xae, 0x8f, - 0x66, 0x76, 0xd0, 0x72, 0x2a, 0xfc, 0x01, 0xaa, 0xa1, 0xc2, 0xc6, 0x71, 0x54, 0x68, 0x1e, 0x60, - 0xc3, 0x76, 0x9b, 0xdb, 0xd5, 0x7a, 0x0d, 0x4b, 0xbb, 0x57, 0x66, 0xb4, 0xb4, 0x18, 0x96, 0x62, - 0xa5, 0xc5, 0x40, 0xb6, 0x0c, 0xdf, 0xd3, 0xf8, 0x4a, 0x1f, 0x61, 0xf3, 0x9e, 0x22, 0x45, 0x79, - 0x7b, 0x82, 0xa2, 0x28, 0xc9, 0xe4, 0x63, 0x54, 0xa5, 0x22, 0x19, 0xf6, 0xe1, 0x48, 0xff, 0x1c, - 0x4b, 0x82, 0xf5, 0xbb, 0x62, 0x9a, 0x61, 0x46, 0x91, 0x0e, 0x4c, 0xd9, 0x6a, 0x62, 0x53, 0x71, - 0x46, 0x0a, 0xe5, 0x44, 0x0d, 0x1d, 0x29, 0x62, 0xc5, 0x38, 0x8e, 0x00, 0x3d, 0x05, 0x53, 0x72, - 0x76, 0x74, 0x31, 0xa5, 0xe5, 0x06, 0xdb, 0x0e, 0x6b, 0x6a, 0x05, 0x8e, 0xb7, 0xd3, 0xff, 0xc1, - 0x30, 0x3c, 0xc4, 0xc7, 0xce, 0x34, 0x06, 0x35, 0xd2, 0x21, 0x8e, 0x49, 0x9c, 0x66, 0x8f, 0xf1, - 0xac, 0xa6, 0xdb, 0x42, 0x3f, 0xad, 0x41, 0x99, 0x38, 0x66, 0xc7, 0xb5, 0x1c, 0xa9, 0xea, 0xff, - 0x50, 0xf1, 0x9c, 0x2c, 0x39, 0x58, 0x96, 0x04, 0x02, 0x11, 0x25, 0x53, 0xfc, 0xc2, 0x21, 0x62, - 0x74, 0x0f, 0x46, 0x3a, 0x9e, 0xbb, 0x21, 0x85, 0xb5, 0xe7, 0x8f, 0x7d, 0x04, 0x6b, 0x14, 0x3a, - 0xff, 0xb8, 0xec, 0x5f, 0xcc, 0xf1, 0xa1, 0xd7, 0x61, 0xf4, 0x1e, 0x21, 0x66, 0xa8, 0xd0, 0x7f, - 0xe1, 0xd8, 0x31, 0xbf, 0xc0, 0xc0, 0xf3, 0x0b, 0x8d, 0xff, 0x8f, 0x05, 0x4a, 0x8a, 0x9c, 0x8d, - 0x42, 0x72, 0x96, 0x2f, 0x9c, 0xcc, 0xb4, 0x05, 0x72, 0xfe, 0x3f, 0x16, 0x28, 0x75, 0x0c, 0x6f, - 0x3b, 0xd4, 0x37, 0x3b, 0x8a, 0x0c, 0x71, 0x07, 0xf4, 0x83, 0x87, 0x73, 0x14, 0x80, 0x6b, 0xf0, - 0xf0, 0x21, 0xe6, 0x77, 0x9c, 0x10, 0xf9, 0x27, 0x3a, 0x0a, 0xc4, 0xef, 0x68, 0xf0, 0x88, 0x02, - 0x72, 0x69, 0x97, 0x4a, 0x5e, 0x55, 0xa3, 0x63, 0x34, 0xad, 0xa0, 0xc7, 0xfd, 0xde, 0x8f, 0x94, - 0xc4, 0xe3, 0x33, 0x1a, 0x8c, 0x71, 0x63, 0x27, 0x79, 0x45, 0xbe, 0x3c, 0xe0, 0xbe, 0xc8, 0x1d, - 0x92, 0x8c, 0x0e, 0x2d, 0xe7, 0xc6, 0x7f, 0xfb, 0x58, 0xe2, 0xd7, 0xff, 0xcd, 0x08, 0xfc, 0xc8, - 0xe1, 0x01, 0xa1, 0xef, 0x69, 0xe9, 0x8c, 0xc1, 0xed, 0x93, 0x1d, 0x7c, 0xa8, 0x69, 0x12, 0xca, - 0x8b, 0x17, 0x52, 0x19, 0x78, 0x8e, 0x49, 0x89, 0xa5, 0xa4, 0x27, 0xfe, 0xa7, 0x1a, 0x4c, 0x52, - 0xd6, 0x21, 0xbc, 0x00, 0xf8, 0x67, 0xea, 0x9c, 0xf0, 0x4c, 0x57, 0x15, 0x94, 0x09, 0x1f, 0x56, - 0xb5, 0x0a, 0xc7, 0xc6, 0x86, 0xee, 0xc6, 0x5f, 0xec, 0xb8, 0x48, 0x7c, 0x25, 0x8b, 0x63, 0x3c, - 0x4a, 0x7e, 0xab, 0x39, 0x1b, 0xa6, 0xe3, 0x2b, 0x7f, 0x92, 0x2a, 0xb8, 0xb9, 0x67, 0xe1, 0x6c, - 0x6a, 0xf6, 0x47, 0x52, 0x40, 0xfd, 0xf4, 0x30, 0x54, 0x94, 0xa5, 0x8e, 0x99, 0x3b, 0x4a, 0xbe, - 0xed, 0x4b, 0x1a, 0x4c, 0x18, 0x8e, 0x23, 0x4c, 0x66, 0xe4, 0xfe, 0x35, 0x07, 0xfc, 0xaa, 0x59, - 0xa8, 0xe6, 0x17, 0x22, 0x34, 0x09, 0x9b, 0x10, 0xa5, 0x06, 0xab, 0xa3, 0xe9, 0x63, 0xf8, 0x58, - 0x3a, 0x35, 0xc3, 0x47, 0xf4, 0x31, 0xc9, 0x2c, 0xf1, 0x6d, 0xf4, 0xe2, 0x09, 0xac, 0x0d, 0xe3, - 0xbd, 0xb2, 0x35, 0x9e, 0x73, 0xef, 0x87, 0x99, 0xe4, 0xca, 0x1d, 0x69, 0x17, 0xfc, 0xd6, 0x50, - 0x8c, 0x54, 0xe7, 0xa2, 0x3f, 0x84, 0x9e, 0xf7, 0xcb, 0x89, 0xcd, 0xc2, 0x49, 0x80, 0x75, 0x52, - 0x0b, 0x72, 0xbc, 0x3b, 0x66, 0xe8, 0xf4, 0x4c, 0x65, 0x07, 0xfd, 0x64, 0x8b, 0x70, 0x41, 0x59, - 0x1f, 0x25, 0x9f, 0xe0, 0x63, 0x30, 0xb6, 0x63, 0xf9, 0x96, 0x8c, 0x48, 0xa4, 0xdc, 0xd0, 0xcf, - 0xf3, 0x62, 0x2c, 0xeb, 0xf5, 0xe5, 0xd8, 0xd9, 0x5f, 0x77, 0x3b, 0xae, 0xed, 0xb6, 0x7a, 0x0b, - 0xf7, 0x0c, 0x8f, 0x60, 0xb7, 0x1b, 0x08, 0x68, 0x87, 0xbd, 0xef, 0x57, 0xe0, 0xaa, 0x02, 0x2d, - 0x33, 0xb4, 0xc2, 0x51, 0xc0, 0x7d, 0x7d, 0x4c, 0x8a, 0x17, 0xc2, 0xf7, 0xf4, 0x77, 0x34, 0xb8, - 0x44, 0xf2, 0xae, 0x02, 0xc1, 0xa2, 0xbf, 0x78, 0x52, 0x57, 0x8d, 0x88, 0x58, 0x9b, 0x57, 0x8d, - 0xf3, 0x47, 0x86, 0x7a, 0xb1, 0xac, 0x9a, 0xa5, 0x41, 0x74, 0xa5, 0x19, 0xdf, 0xbb, 0x5f, 0x4e, - 0x4d, 0xf4, 0x2b, 0x1a, 0x9c, 0xb7, 0x33, 0x8e, 0x8e, 0xe0, 0xab, 0x1b, 0x27, 0x70, 0x2a, 0xf9, - 0xbb, 0x74, 0x56, 0x0d, 0xce, 0x1c, 0x0a, 0xfa, 0xb5, 0xdc, 0x98, 0x1f, 0xfc, 0xd9, 0x78, 0x7d, - 0xc0, 0x41, 0x1e, 0x57, 0xf8, 0x8f, 0x2f, 0x68, 0x80, 0xcc, 0x14, 0x5b, 0x2c, 0x2c, 0x7d, 0x9e, - 0x3b, 0x76, 0x09, 0x85, 0x1b, 0x16, 0xa4, 0xcb, 0x71, 0xc6, 0x20, 0xd8, 0x77, 0x0e, 0x32, 0x8e, - 0xaf, 0x08, 0xe6, 0x3b, 0xe8, 0x77, 0xce, 0xa2, 0x0c, 0xfc, 0x3b, 0x67, 0xd5, 0xe0, 0xcc, 0xa1, - 0xe8, 0x9f, 0x1f, 0xe3, 0x9a, 0x34, 0xf6, 0xf2, 0xbb, 0x01, 0xa3, 0x1b, 0x4c, 0xf3, 0x2a, 0xce, - 0x6d, 0x61, 0x35, 0x2f, 0xd7, 0xdf, 0x72, 0x41, 0x8e, 0xff, 0x8f, 0x05, 0x64, 0xf4, 0x12, 0x0c, - 0x99, 0x8e, 0x2f, 0x0e, 0xdc, 0x7b, 0x07, 0x50, 0x58, 0x46, 0xee, 0x56, 0xb5, 0xd5, 0x06, 0xa6, - 0x40, 0x91, 0x03, 0x65, 0x47, 0x28, 0x9f, 0x84, 0x80, 0x5c, 0x38, 0x61, 0x6b, 0xa8, 0xc4, 0x0a, - 0x55, 0x67, 0xb2, 0x04, 0x87, 0x38, 0x28, 0xbe, 0xc4, 0x6b, 0x4b, 0x61, 0x7c, 0xa1, 0xfa, 0xb5, - 0x9f, 0x86, 0x7b, 0x4d, 0x55, 0xa6, 0x8e, 0x1c, 0x5e, 0x99, 0x3a, 0x95, 0xfb, 0xf8, 0x44, 0x60, - 0x34, 0x30, 0x2c, 0x27, 0xe0, 0xca, 0xb4, 0x82, 0x86, 0x12, 0x74, 0xfc, 0xeb, 0x14, 0x4a, 0xa4, - 0xb5, 0x62, 0x3f, 0x7d, 0x2c, 0x80, 0xd3, 0x8d, 0xb5, 0xc3, 0xd2, 0xa6, 0x8b, 0x83, 0x59, 0x78, - 0x63, 0xf1, 0xe4, 0xeb, 0x7c, 0x63, 0xf1, 0xff, 0xb1, 0x80, 0x8c, 0x5e, 0x81, 0xb2, 0x2f, 0x4d, - 0x5b, 0xca, 0x83, 0x66, 0xeb, 0x15, 0x76, 0x2d, 0xc2, 0xa7, 0x4a, 0x18, 0xb4, 0x84, 0xf0, 0xd1, - 0x06, 0x8c, 0x59, 0xdc, 0x0b, 0x48, 0x84, 0x40, 0x7a, 0xef, 0x00, 0xc9, 0xea, 0xb8, 0x60, 0x2d, - 0x7e, 0x60, 0x09, 0x58, 0xff, 0x3a, 0xf0, 0xb7, 0x10, 0x61, 0x3d, 0xb8, 0x09, 0x65, 0x09, 0x6e, - 0x10, 0xdf, 0x3e, 0x99, 0x1e, 0x94, 0x4f, 0x2d, 0x4c, 0x16, 0x1a, 0xc2, 0x46, 0xd5, 0x2c, 0x1f, - 0xcd, 0x28, 0x69, 0xc2, 0xe1, 0xfc, 0x33, 0x5f, 0x65, 0xf9, 0xfc, 0x64, 0x3c, 0x83, 0xa1, 0xe2, - 0x5b, 0x2b, 0x8c, 0x75, 0x10, 0xcb, 0xe3, 0x27, 0xc3, 0x21, 0x28, 0x48, 0x72, 0xac, 0x2b, 0x87, - 0x0b, 0x59, 0x57, 0x3e, 0x03, 0x67, 0x84, 0x35, 0x4b, 0x9d, 0xa5, 0xce, 0x0f, 0x7a, 0xc2, 0xfd, - 0x84, 0xd9, 0x39, 0x55, 0xe3, 0x55, 0x38, 0xd9, 0x16, 0xfd, 0x81, 0x06, 0xe5, 0xa6, 0x60, 0x39, - 0xc4, 0xb9, 0x5a, 0x1e, 0xec, 0xc1, 0x6c, 0x5e, 0x72, 0x30, 0x9c, 0x99, 0x7e, 0x5e, 0xd2, 0x08, - 0x59, 0x7c, 0x4c, 0x4a, 0x83, 0x70, 0xd4, 0xe8, 0x8f, 0xa9, 0xbc, 0x60, 0xb3, 0x94, 0xa5, 0xcc, - 0x1b, 0x9d, 0xfb, 0xc5, 0xdc, 0x19, 0x70, 0x16, 0x0b, 0x11, 0x44, 0x3e, 0x91, 0x0f, 0x85, 0x52, - 0x41, 0x54, 0x73, 0x4c, 0x73, 0x51, 0x87, 0x8f, 0xfe, 0xb1, 0x06, 0x8f, 0x70, 0x67, 0xa4, 0x2a, - 0xe5, 0x22, 0x58, 0xe6, 0x77, 0x12, 0xa5, 0x9a, 0x8f, 0x6c, 0x41, 0xcb, 0x47, 0xb6, 0x05, 0x7d, - 0x74, 0x7f, 0xaf, 0xf2, 0x48, 0xf5, 0x10, 0xb0, 0xf1, 0xa1, 0x46, 0x80, 0x5e, 0x83, 0x29, 0x5b, - 0x8d, 0x6b, 0x23, 0x08, 0x4c, 0xa1, 0xe7, 0x98, 0x58, 0x80, 0x1c, 0xae, 0x7f, 0x8f, 0x15, 0xe1, - 0x38, 0xaa, 0xb9, 0x6d, 0x98, 0x8a, 0x6d, 0xb4, 0x13, 0x55, 0x92, 0x38, 0x30, 0x93, 0xdc, 0x0f, - 0x27, 0x6a, 0x17, 0x75, 0x1b, 0xc6, 0xc3, 0x8b, 0x0a, 0x3d, 0xa4, 0x20, 0x8a, 0x18, 0x89, 0xdb, - 0xa4, 0xc7, 0xb1, 0x56, 0x62, 0x02, 0x1e, 0x57, 0xc4, 0x3f, 0x4f, 0x0b, 0x04, 0x40, 0xfd, 0x1b, - 0xe2, 0x95, 0x65, 0x9d, 0xb4, 0x3b, 0xb6, 0x11, 0x90, 0x37, 0xff, 0x1b, 0xbf, 0xfe, 0x5f, 0x35, - 0x7e, 0xdf, 0xf0, 0x6b, 0x15, 0x19, 0x30, 0xd1, 0xe6, 0xc1, 0x9b, 0x59, 0x00, 0x06, 0xad, 0x78, - 0xe8, 0x87, 0x95, 0x08, 0x0c, 0x56, 0x61, 0xa2, 0x7b, 0x30, 0x2e, 0x59, 0x1b, 0xa9, 0x91, 0xb8, - 0x31, 0x18, 0x63, 0x10, 0x72, 0x51, 0xe1, 0xf3, 0xb1, 0x2c, 0xf1, 0x71, 0x84, 0x4b, 0x37, 0x00, - 0xa5, 0xfb, 0x50, 0x29, 0x58, 0xba, 0x3b, 0x68, 0xf1, 0x88, 0x88, 0x29, 0x97, 0x87, 0x03, 0x93, - 0x94, 0xeb, 0x5f, 0x29, 0x41, 0x66, 0xc2, 0x3c, 0xa4, 0xc3, 0x28, 0xf7, 0x40, 0x94, 0xf9, 0xcf, - 0x29, 0x2b, 0xc3, 0xdd, 0x13, 0xb1, 0xa8, 0x41, 0x77, 0xb8, 0x26, 0xc4, 0x31, 0x59, 0x24, 0xc2, - 0x88, 0x4a, 0xa8, 0xbe, 0xae, 0x4b, 0x59, 0x0d, 0x70, 0x76, 0x3f, 0xb4, 0x03, 0xa8, 0x6d, 0xec, - 0x26, 0xa1, 0x0d, 0x90, 0x9a, 0x6a, 0x25, 0x05, 0x0d, 0x67, 0x60, 0xa0, 0x17, 0xa9, 0xd1, 0x6c, - 0x92, 0x4e, 0x40, 0x4c, 0x3e, 0x45, 0xf9, 0xc8, 0xcb, 0x2e, 0xd2, 0x85, 0x78, 0x15, 0x4e, 0xb6, - 0xd5, 0xbf, 0x3b, 0x0c, 0x97, 0xe2, 0x8b, 0x48, 0x4f, 0xa8, 0x74, 0x12, 0x7c, 0x56, 0xfa, 0x40, - 0xf0, 0x85, 0x7c, 0x2c, 0xe9, 0x03, 0x31, 0x5b, 0xf5, 0x08, 0xbb, 0x92, 0x0d, 0xdb, 0x97, 0x9d, - 0x62, 0xfe, 0x10, 0x3f, 0x00, 0x8f, 0xbf, 0x1c, 0xcf, 0xc6, 0xa1, 0x13, 0xf5, 0x6c, 0x7c, 0x43, - 0x83, 0xb9, 0x78, 0xf1, 0x0d, 0xcb, 0xb1, 0xfc, 0x2d, 0x11, 0x4f, 0xef, 0xe8, 0x2e, 0x18, 0x2c, - 0x7d, 0xc5, 0x72, 0x2e, 0x44, 0xdc, 0x07, 0x1b, 0xfa, 0xac, 0x06, 0x97, 0x13, 0xeb, 0x12, 0x8b, - 0xee, 0x77, 0x74, 0x6f, 0x0c, 0xe6, 0xa3, 0xbd, 0x9c, 0x0f, 0x12, 0xf7, 0xc3, 0xa7, 0xff, 0x8b, - 0x12, 0x8c, 0x30, 0x1b, 0x85, 0x37, 0x87, 0x51, 0x3a, 0x1b, 0x6a, 0xae, 0x9d, 0x56, 0x2b, 0x61, - 0xa7, 0xf5, 0x6c, 0x71, 0x14, 0xfd, 0x0d, 0xb5, 0x3e, 0x04, 0x17, 0x59, 0xb3, 0x05, 0x93, 0xa9, - 0x65, 0x7c, 0x62, 0x2e, 0x98, 0x26, 0x8b, 0x10, 0x71, 0xb0, 0x2e, 0xfa, 0x21, 0x18, 0xea, 0x7a, - 0x76, 0x32, 0x66, 0xca, 0x5d, 0xbc, 0x8c, 0x69, 0xb9, 0xfe, 0x86, 0x06, 0x33, 0x0c, 0xb6, 0x72, - 0x7c, 0xd1, 0x0e, 0x94, 0x3d, 0x71, 0x84, 0xc5, 0xb7, 0x59, 0x2e, 0x3c, 0xb5, 0x0c, 0xb2, 0x20, - 0x52, 0x7a, 0x8a, 0x5f, 0x38, 0xc4, 0xa5, 0x7f, 0x7b, 0x14, 0x66, 0xf3, 0x3a, 0xa1, 0xcf, 0x69, - 0x70, 0xb1, 0x19, 0x71, 0x73, 0x0b, 0xdd, 0x60, 0xcb, 0xf5, 0xac, 0xc0, 0x12, 0xc6, 0x3b, 0x05, - 0xc5, 0xdc, 0xea, 0x42, 0x38, 0x2a, 0x16, 0x8d, 0xae, 0x9a, 0x89, 0x01, 0xe7, 0x60, 0x46, 0xaf, - 0x03, 0x6c, 0x47, 0xe1, 0x6f, 0x4b, 0xc5, 0x13, 0x6d, 0xb0, 0x69, 0x2b, 0x21, 0x72, 0xe5, 0xa0, - 0x98, 0x66, 0x53, 0x29, 0x57, 0xd0, 0x51, 0xe4, 0xbe, 0xbf, 0x75, 0x9b, 0xf4, 0x3a, 0x86, 0x25, - 0x6d, 0x14, 0x8a, 0x23, 0x6f, 0x34, 0x6e, 0x09, 0x50, 0x71, 0xe4, 0x4a, 0xb9, 0x82, 0x0e, 0x7d, - 0x52, 0x83, 0x29, 0x57, 0x75, 0x27, 0x1f, 0xc4, 0x02, 0x36, 0xd3, 0x2f, 0x9d, 0xb3, 0xd0, 0xf1, - 0xaa, 0x38, 0x4a, 0xba, 0x27, 0xce, 0xfa, 0xc9, 0x2b, 0x4b, 0x10, 0xb5, 0x95, 0xc1, 0xf3, 0xf1, - 0x2a, 0xf7, 0x1f, 0x17, 0xc7, 0xd3, 0xd5, 0x69, 0xf4, 0x6c, 0x50, 0x24, 0x68, 0x9a, 0x4b, 0x4e, - 0xd3, 0xeb, 0x31, 0xcf, 0x50, 0x3a, 0xa8, 0xd1, 0xe2, 0x83, 0x5a, 0x5a, 0xaf, 0xd6, 0x62, 0xc0, - 0xe2, 0x83, 0x4a, 0x57, 0xa7, 0xd1, 0xeb, 0x9f, 0x28, 0xc1, 0x03, 0x39, 0x7b, 0xec, 0x6f, 0x8c, - 0xff, 0xff, 0xd7, 0x34, 0x18, 0x67, 0x6b, 0xf0, 0x26, 0x71, 0x22, 0x62, 0x63, 0xcd, 0xb1, 0x64, - 0xfc, 0x43, 0x0d, 0xce, 0xa6, 0xe2, 0xa0, 0x1e, 0xca, 0x05, 0xe5, 0xd4, 0x8c, 0xec, 0xde, 0x16, - 0xc5, 0x3c, 0x1f, 0x8a, 0x1c, 0x9a, 0x93, 0xf1, 0xce, 0xf5, 0x17, 0x60, 0x2a, 0x66, 0xc8, 0x18, - 0xc6, 0x6a, 0xd2, 0x32, 0x63, 0x35, 0xa9, 0xa1, 0x98, 0x4a, 0xfd, 0x42, 0x31, 0x45, 0x5b, 0x3e, - 0x4d, 0xd9, 0xfe, 0xc6, 0x6c, 0xf9, 0xef, 0x9c, 0x11, 0x5b, 0x9e, 0xbd, 0x38, 0xbc, 0x0c, 0xa3, - 0x2c, 0xf0, 0x93, 0xbc, 0x31, 0xaf, 0x17, 0x0e, 0x28, 0xe5, 0x73, 0x49, 0x8a, 0xff, 0x8f, 0x05, - 0x54, 0x54, 0x83, 0x99, 0xa6, 0xed, 0x76, 0x4d, 0x91, 0xa2, 0x74, 0x35, 0x12, 0xda, 0xc2, 0xb8, - 0xa0, 0xd5, 0x44, 0x3d, 0x4e, 0xf5, 0x40, 0x98, 0xbf, 0x59, 0xf0, 0xfb, 0xac, 0x50, 0x5c, 0xd0, - 0xda, 0x6a, 0x83, 0x67, 0xbf, 0x08, 0xdf, 0x2a, 0x5e, 0x05, 0x20, 0x72, 0xf3, 0x4a, 0xdf, 0xcf, - 0x67, 0x8a, 0x45, 0x3c, 0x0d, 0x8f, 0x80, 0x64, 0x3e, 0xc3, 0x22, 0x1f, 0x2b, 0x48, 0x90, 0x07, - 0x13, 0x5b, 0xd6, 0x06, 0xf1, 0x1c, 0xce, 0x47, 0x8d, 0x14, 0x67, 0x11, 0x6f, 0x45, 0x60, 0xb8, - 0x8c, 0xaf, 0x14, 0x60, 0x15, 0x09, 0xf2, 0x38, 0x3b, 0xc2, 0xd5, 0xc3, 0x83, 0x24, 0xeb, 0x8f, - 0xf4, 0xce, 0xd1, 0x3c, 0xa3, 0x32, 0xac, 0x60, 0x41, 0x0e, 0x80, 0x13, 0x46, 0x7c, 0x1b, 0xe4, - 0xc5, 0x21, 0x8a, 0x1b, 0xc7, 0x19, 0x8f, 0xe8, 0x37, 0x56, 0x30, 0xd0, 0x75, 0x6d, 0x47, 0x21, - 0x04, 0x85, 0x0e, 0xf1, 0xd9, 0x01, 0xc3, 0x38, 0x0a, 0xdd, 0x49, 0x54, 0x80, 0x55, 0x24, 0x74, - 0x8e, 0xed, 0x30, 0xf0, 0x9f, 0xd0, 0x11, 0x16, 0x9a, 0x63, 0x14, 0x3e, 0x50, 0xa4, 0x50, 0x0b, - 0x7f, 0x63, 0x05, 0x03, 0x7a, 0x45, 0x79, 0xea, 0x82, 0xe2, 0x1a, 0xa8, 0x43, 0x3d, 0x73, 0xbd, - 0x2b, 0x52, 0xc4, 0x4c, 0xb0, 0xb3, 0x7a, 0x59, 0x51, 0xc2, 0xb0, 0x80, 0x88, 0x94, 0x7e, 0xa4, - 0x94, 0x32, 0x91, 0x09, 0xf5, 0x64, 0x5f, 0x13, 0xea, 0x2a, 0xe5, 0xd0, 0x14, 0x97, 0x1e, 0x46, - 0x14, 0xa6, 0xa2, 0x17, 0x8e, 0x46, 0xb2, 0x12, 0xa7, 0xdb, 0x73, 0xa2, 0x4f, 0x4c, 0xd6, 0x77, - 0x5a, 0x25, 0xfa, 0xbc, 0x0c, 0x87, 0xb5, 0x68, 0x07, 0x26, 0x7d, 0xc5, 0x1e, 0x5b, 0xe4, 0xbd, - 0x1c, 0xe0, 0x6d, 0x4a, 0xd8, 0x62, 0xb3, 0x50, 0x58, 0x6a, 0x09, 0x8e, 0xe1, 0x41, 0xaf, 0xab, - 0xc6, 0x8d, 0x33, 0xc5, 0x9d, 0x6f, 0xb3, 0x03, 0x3d, 0x46, 0x1a, 0xb6, 0xd0, 0xae, 0x4e, 0xb5, - 0x39, 0xec, 0xc6, 0xcd, 0xf8, 0xce, 0x1e, 0x4b, 0xb0, 0x81, 0x03, 0xcd, 0xfc, 0xe8, 0xa7, 0x25, - 0xbb, 0x1d, 0xd7, 0xef, 0x7a, 0x84, 0x05, 0xb0, 0x65, 0x9f, 0x07, 0x45, 0x9f, 0x76, 0x29, 0x59, - 0x89, 0xd3, 0xed, 0xd1, 0xa7, 0x35, 0x98, 0xe1, 0x69, 0x43, 0xe9, 0xd5, 0xe5, 0x3a, 0xc4, 0x09, - 0x7c, 0x96, 0x17, 0xb3, 0xa0, 0x7f, 0x6c, 0x23, 0x01, 0x8b, 0xe7, 0x5a, 0x4a, 0x96, 0xe2, 0x14, - 0x4e, 0xba, 0x73, 0xd4, 0x70, 0x05, 0x2c, 0xbd, 0x66, 0xc1, 0x9d, 0xa3, 0x86, 0x42, 0xe0, 0x3b, - 0x47, 0x2d, 0xc1, 0x31, 0x3c, 0xe8, 0x29, 0x98, 0xf2, 0x65, 0x0e, 0x1c, 0xb6, 0x82, 0x17, 0xa2, - 0x78, 0x62, 0x0d, 0xb5, 0x02, 0xc7, 0xdb, 0xe9, 0xff, 0x56, 0x03, 0x08, 0xb5, 0x07, 0xa7, 0xa1, - 0x13, 0x37, 0x63, 0x0a, 0x95, 0xc5, 0x81, 0xb4, 0x1d, 0x24, 0x57, 0x33, 0xfe, 0x2d, 0x0d, 0xa6, - 0xa3, 0x66, 0xa7, 0xc0, 0xaa, 0x37, 0xe3, 0xac, 0xfa, 0xfb, 0x07, 0x9b, 0x57, 0x0e, 0xbf, 0xfe, - 0x7f, 0x4a, 0xea, 0xac, 0x18, 0x37, 0xb6, 0x13, 0x7b, 0x63, 0xa6, 0xa8, 0x6f, 0x0d, 0xf2, 0xc6, - 0xac, 0xba, 0x50, 0x47, 0xf3, 0xcd, 0x78, 0x73, 0xfe, 0x3b, 0x31, 0x5e, 0x68, 0x80, 0x40, 0x01, - 0x21, 0xe3, 0x23, 0x51, 0xf3, 0x05, 0x38, 0x88, 0x31, 0x7a, 0x55, 0x25, 0x95, 0xfc, 0xb5, 0xfa, - 0x03, 0xc5, 0xbc, 0xd3, 0x95, 0x09, 0xf7, 0x25, 0x90, 0xfa, 0xd7, 0xa6, 0x60, 0x42, 0x51, 0xb4, - 0x25, 0x5e, 0xcc, 0xb5, 0xd3, 0x78, 0x31, 0x0f, 0x60, 0xa2, 0x19, 0x06, 0x84, 0x97, 0xcb, 0x3e, - 0x20, 0xce, 0x90, 0x44, 0x47, 0xa1, 0xe6, 0x7d, 0xac, 0xa2, 0xa1, 0x8c, 0x44, 0xb8, 0xc7, 0x86, - 0x8e, 0xc1, 0x8e, 0xa1, 0xdf, 0xbe, 0x7a, 0x27, 0x80, 0xe4, 0x45, 0x89, 0x29, 0x22, 0x7a, 0x86, - 0x46, 0xe8, 0x75, 0xff, 0x56, 0x58, 0x87, 0x95, 0x76, 0xe9, 0x17, 0xd8, 0x91, 0x53, 0x7b, 0x81, - 0xa5, 0xdb, 0xc0, 0x96, 0x59, 0x83, 0x06, 0xb2, 0xc9, 0x09, 0x73, 0x0f, 0x45, 0xdb, 0x20, 0x2c, - 0xf2, 0xb1, 0x82, 0x24, 0xc7, 0x70, 0x62, 0xac, 0x90, 0xe1, 0x44, 0x17, 0xce, 0x79, 0x24, 0xf0, - 0x7a, 0xd5, 0x5e, 0x93, 0x25, 0xd3, 0xf2, 0x02, 0x26, 0x51, 0x96, 0x8b, 0x45, 0x98, 0xc2, 0x69, - 0x50, 0x38, 0x0b, 0x7e, 0x8c, 0x19, 0x1b, 0xef, 0xcb, 0x8c, 0xbd, 0x0b, 0x26, 0x02, 0xd2, 0xdc, - 0x72, 0xac, 0xa6, 0x61, 0xd7, 0x6b, 0x22, 0xdc, 0x65, 0xc4, 0x57, 0x44, 0x55, 0x58, 0x6d, 0x87, - 0x16, 0x61, 0xa8, 0x6b, 0x99, 0x82, 0x1b, 0xfd, 0xb1, 0x50, 0x65, 0x5d, 0xaf, 0xdd, 0xdf, 0xab, - 0xbc, 0x35, 0xb2, 0x44, 0x08, 0x67, 0x75, 0xad, 0xb3, 0xdd, 0xba, 0x16, 0xf4, 0x3a, 0xc4, 0x9f, - 0xbf, 0x5b, 0xaf, 0x61, 0xda, 0x39, 0xcb, 0xa8, 0x64, 0xf2, 0x08, 0x46, 0x25, 0x5f, 0xd0, 0xe0, - 0x9c, 0x91, 0xd4, 0xb6, 0x13, 0x7f, 0x76, 0xaa, 0x38, 0xb5, 0xcc, 0xd6, 0xe0, 0x2f, 0x5e, 0x16, - 0xf3, 0x3b, 0xb7, 0x90, 0x46, 0x87, 0xb3, 0xc6, 0x80, 0x3c, 0x40, 0x6d, 0xab, 0x15, 0x26, 0xf0, - 0x11, 0x5f, 0x7d, 0xba, 0x98, 0x1e, 0x61, 0x25, 0x05, 0x09, 0x67, 0x40, 0x47, 0xf7, 0x60, 0xa2, - 0x19, 0xe9, 0xe4, 0x05, 0x57, 0x5d, 0x3b, 0x8e, 0x47, 0x01, 0x2e, 0x79, 0xa9, 0x0a, 0x7f, 0x15, - 0x53, 0xf8, 0x9a, 0xa6, 0x88, 0xbc, 0xe2, 0x45, 0x89, 0xcd, 0x7a, 0xa6, 0xf8, 0x6b, 0x5a, 0x36, - 0x44, 0xdc, 0x07, 0x1b, 0x8b, 0xeb, 0x64, 0xc7, 0xf3, 0x6c, 0xb1, 0x14, 0xf3, 0x05, 0x7d, 0xc1, - 0x13, 0x29, 0xbb, 0xf8, 0xd6, 0x4c, 0x14, 0xe2, 0x24, 0x42, 0xfd, 0x9b, 0x9a, 0x50, 0x98, 0x9d, - 0xa2, 0x35, 0xc4, 0x49, 0x3f, 0xa5, 0xe9, 0x7f, 0xa1, 0x41, 0x8a, 0x47, 0x47, 0x1b, 0x30, 0x46, - 0x41, 0xd4, 0x56, 0x1b, 0x62, 0x5a, 0xef, 0x2d, 0x76, 0x5d, 0x32, 0x10, 0x5c, 0xfb, 0x28, 0x7e, - 0x60, 0x09, 0x98, 0x72, 0xfd, 0x8e, 0x12, 0x71, 0x5b, 0xcc, 0xb0, 0x10, 0x3f, 0xa2, 0x46, 0xee, - 0xe6, 0x5c, 0xbf, 0x5a, 0x82, 0x63, 0x78, 0xf4, 0x65, 0x80, 0x48, 0xae, 0x1a, 0xd8, 0x40, 0xe6, - 0xfb, 0x23, 0x70, 0x61, 0x50, 0x67, 0x03, 0x96, 0xde, 0x89, 0xec, 0x58, 0xcd, 0x60, 0x61, 0x33, - 0x20, 0xde, 0x9d, 0x3b, 0x2b, 0xeb, 0x5b, 0x1e, 0xf1, 0xb7, 0x5c, 0xdb, 0x2c, 0x98, 0x5f, 0x8a, - 0x3d, 0xa8, 0x2d, 0x65, 0x42, 0xc4, 0x39, 0x98, 0x98, 0x4c, 0x29, 0xd2, 0x4d, 0x63, 0xca, 0x4c, - 0x76, 0x3d, 0x3f, 0x10, 0x51, 0x6d, 0xb8, 0x4c, 0x99, 0xac, 0xc4, 0xe9, 0xf6, 0x49, 0x20, 0xcb, - 0x56, 0xdb, 0xe2, 0x19, 0x7c, 0xb4, 0x34, 0x10, 0x56, 0x89, 0xd3, 0xed, 0x55, 0x20, 0xfc, 0x4b, - 0xd1, 0xd3, 0x3e, 0x92, 0x06, 0x12, 0x56, 0xe2, 0x74, 0x7b, 0x64, 0xc2, 0x83, 0x1e, 0x69, 0xba, - 0xed, 0x36, 0x71, 0x4c, 0x9e, 0x39, 0xd1, 0xf0, 0x5a, 0x96, 0x73, 0xc3, 0x33, 0x58, 0x43, 0xa6, - 0xa2, 0xd3, 0x58, 0x1e, 0x8a, 0x07, 0x71, 0x9f, 0x76, 0xb8, 0x2f, 0x14, 0xd4, 0x86, 0x33, 0x5d, - 0x96, 0xf3, 0xc3, 0xab, 0x3b, 0x01, 0xf1, 0x76, 0x0c, 0x5b, 0xe8, 0xe1, 0x0a, 0xa5, 0x8c, 0xbe, - 0x1b, 0x07, 0x85, 0x93, 0xb0, 0x51, 0x8f, 0xf2, 0x1d, 0x62, 0x38, 0x0a, 0xca, 0x72, 0xf1, 0x04, - 0x68, 0x38, 0x0d, 0x0e, 0x67, 0xe1, 0xd0, 0xbf, 0xa0, 0x81, 0xb0, 0x44, 0x46, 0x0f, 0xc6, 0xde, - 0x3a, 0xca, 0x89, 0x77, 0x0e, 0x99, 0x79, 0xa2, 0x94, 0x99, 0x79, 0xe2, 0xed, 0x4a, 0xb8, 0xa4, - 0xf1, 0x88, 0xf6, 0x71, 0xc8, 0x4a, 0xd6, 0x9c, 0xc7, 0x61, 0x9c, 0xf0, 0x67, 0xb4, 0x90, 0xa3, - 0x65, 0xd6, 0xdd, 0x4b, 0xb2, 0x10, 0x47, 0xf5, 0xfa, 0x9f, 0x68, 0x20, 0x20, 0xb0, 0x1c, 0x4f, - 0x87, 0xca, 0xf5, 0x73, 0xa0, 0x69, 0x93, 0x92, 0xa3, 0x68, 0x28, 0x37, 0x47, 0xd1, 0x09, 0xa5, - 0xee, 0xf9, 0x1d, 0x0d, 0xce, 0xc4, 0xe3, 0x57, 0xf9, 0xe8, 0x6d, 0x30, 0x26, 0x22, 0x5c, 0x8a, - 0x10, 0x75, 0xac, 0xab, 0x08, 0x31, 0x81, 0x65, 0x5d, 0x5c, 0x1d, 0x36, 0x80, 0x88, 0x99, 0x1d, - 0x46, 0xeb, 0x00, 0x69, 0xef, 0x53, 0x33, 0x30, 0xca, 0xc3, 0x23, 0x52, 0x9a, 0x96, 0xe1, 0xb6, - 0x79, 0xbb, 0x78, 0x14, 0xc6, 0x22, 0xbe, 0x76, 0x6a, 0x26, 0x82, 0x52, 0xdf, 0x4c, 0x04, 0x98, - 0xa7, 0x44, 0x1b, 0xe0, 0xe9, 0xa3, 0x8a, 0xeb, 0x22, 0x13, 0xba, 0x4c, 0x87, 0x16, 0xc4, 0xde, - 0x04, 0x86, 0x8b, 0x73, 0x6e, 0x7c, 0x01, 0x94, 0x97, 0x81, 0xe9, 0xbe, 0xaf, 0x02, 0x32, 0xfe, - 0xdc, 0x48, 0x71, 0x53, 0x43, 0xb1, 0xe4, 0x87, 0x88, 0x3f, 0x17, 0x1e, 0xa4, 0xd1, 0xdc, 0x83, - 0xb4, 0x09, 0x63, 0xe2, 0x28, 0x08, 0xe2, 0xf8, 0xde, 0x01, 0x72, 0x8b, 0x29, 0x21, 0x93, 0x79, - 0x01, 0x96, 0xc0, 0xe9, 0x8d, 0xdb, 0x36, 0x76, 0xad, 0x76, 0xb7, 0xcd, 0x28, 0xe2, 0x88, 0xda, - 0x94, 0x15, 0x63, 0x59, 0xcf, 0x9a, 0x72, 0x0b, 0x4d, 0x26, 0x48, 0xa9, 0x4d, 0x79, 0x31, 0x96, - 0xf5, 0xe8, 0x25, 0x28, 0xb7, 0x8d, 0xdd, 0x46, 0xd7, 0x6b, 0x11, 0xf1, 0x22, 0x90, 0xcf, 0xe3, - 0x75, 0x03, 0xcb, 0x9e, 0xa7, 0xe2, 0x7f, 0xe0, 0xcd, 0xd7, 0x9d, 0xe0, 0x8e, 0xd7, 0x08, 0xbc, - 0x30, 0xc1, 0xd0, 0x8a, 0x80, 0x82, 0x43, 0x78, 0xc8, 0x86, 0xe9, 0xb6, 0xb1, 0x7b, 0xd7, 0x31, - 0x78, 0x68, 0x41, 0x9b, 0x3f, 0x04, 0x14, 0xc1, 0xc0, 0x9e, 0x85, 0x57, 0x62, 0xb0, 0x70, 0x02, - 0x76, 0xc6, 0x0b, 0xf4, 0xe4, 0x49, 0xbd, 0x40, 0x2f, 0x84, 0xfe, 0x36, 0x5c, 0x6e, 0xbb, 0x94, - 0xe9, 0xd9, 0xde, 0xd7, 0x97, 0xe6, 0xe5, 0xd0, 0x97, 0x66, 0xba, 0xf8, 0x93, 0x69, 0x1f, 0x3f, - 0x9a, 0x2e, 0x4c, 0x50, 0x0e, 0x9b, 0x97, 0x52, 0xc1, 0xaa, 0xb0, 0x0a, 0xb2, 0x16, 0x82, 0x51, - 0x12, 0xd8, 0x46, 0xa0, 0xb1, 0x8a, 0x07, 0xdd, 0xe1, 0x09, 0xe9, 0x6d, 0x12, 0x44, 0x4d, 0x98, - 0x40, 0x3f, 0xc3, 0xce, 0x4f, 0x98, 0x3f, 0x3e, 0xd5, 0x00, 0x67, 0xf7, 0x8b, 0x22, 0xe5, 0x9c, - 0xcd, 0x8e, 0x94, 0x83, 0x7e, 0x3e, 0x4b, 0xcf, 0x8f, 0xd8, 0x9a, 0x7e, 0xb0, 0x38, 0x6d, 0x28, - 0xac, 0xed, 0xff, 0x97, 0x1a, 0xcc, 0xb6, 0x73, 0x32, 0xbd, 0x8a, 0xe7, 0x87, 0xf5, 0x01, 0xe8, - 0x43, 0x6e, 0xf6, 0xd8, 0xc5, 0x47, 0xf6, 0xf7, 0x2a, 0x07, 0xe6, 0x98, 0xc5, 0xb9, 0x63, 0x43, - 0x1e, 0x8c, 0xf9, 0x3d, 0xbf, 0x19, 0xd8, 0xfe, 0xec, 0xf9, 0xe2, 0x09, 0x45, 0x05, 0x65, 0x6d, - 0x70, 0x48, 0x9c, 0xb4, 0x46, 0x81, 0xfa, 0x79, 0x29, 0x96, 0x88, 0x06, 0xf5, 0xd3, 0x1e, 0x20, - 0x38, 0xe8, 0xdc, 0x75, 0x98, 0x54, 0x07, 0x79, 0x24, 0xf7, 0xf0, 0x5f, 0xd5, 0x60, 0x26, 0x79, - 0x69, 0xa9, 0x39, 0xff, 0xb5, 0x93, 0xcd, 0xf9, 0xaf, 0xd8, 0xbf, 0x94, 0xfa, 0xd8, 0xbf, 0x3c, - 0x03, 0x17, 0xb3, 0xf7, 0x32, 0xe5, 0x20, 0x0d, 0xdb, 0x76, 0xef, 0x09, 0xc9, 0x2d, 0xca, 0xe1, - 0x45, 0x0b, 0x31, 0xaf, 0xd3, 0x3f, 0x06, 0xc9, 0x50, 0xd0, 0xe8, 0x15, 0x18, 0xf7, 0xfd, 0x2d, - 0x1e, 0xe5, 0x53, 0x4c, 0xb2, 0x98, 0xc8, 0x2e, 0x43, 0x85, 0x0a, 0x97, 0x46, 0xf9, 0x13, 0x47, - 0xe0, 0x17, 0x5f, 0xfc, 0xea, 0x77, 0xaf, 0xbc, 0xe5, 0x1b, 0xdf, 0xbd, 0xf2, 0x96, 0x6f, 0x7f, - 0xf7, 0xca, 0x5b, 0x7e, 0x6a, 0xff, 0x8a, 0xf6, 0xd5, 0xfd, 0x2b, 0xda, 0x37, 0xf6, 0xaf, 0x68, - 0xdf, 0xde, 0xbf, 0xa2, 0xfd, 0xa7, 0xfd, 0x2b, 0xda, 0x2f, 0xfc, 0xe7, 0x2b, 0x6f, 0x79, 0xe9, - 0xc9, 0x08, 0xfb, 0x35, 0x89, 0x34, 0xfa, 0xa7, 0xb3, 0xdd, 0xba, 0x46, 0xb1, 0x4b, 0xd7, 0x22, - 0x86, 0xfd, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xf5, 0xa2, 0xb7, 0xf3, 0x7f, 0xea, 0x00, 0x00, + // 12050 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x7b, 0x6c, 0x24, 0xc9, + 0x79, 0x18, 0xae, 0x1e, 0xbe, 0x86, 0x1f, 0x1f, 0xcb, 0xad, 0x7d, 0x1c, 0x97, 0x7b, 0xb7, 0xb3, + 0xea, 0x3b, 0xe9, 0x77, 0xe7, 0x93, 0xb9, 0xbe, 0xb3, 0xe4, 0xd3, 0xad, 0x7c, 0x77, 0x22, 0x67, + 0xb8, 0xbb, 0xe3, 0x25, 0xb9, 0xbc, 0x1a, 0xf2, 0xee, 0x74, 0xf6, 0xef, 0xec, 0xe6, 0x74, 0x71, + 0xd8, 0xc7, 0x9e, 0xee, 0xb9, 0xee, 0x1e, 0x2e, 0xe7, 0xce, 0x8e, 0x2d, 0xd9, 0x72, 0xac, 0xb3, + 0x15, 0x18, 0x06, 0x1c, 0x45, 0x92, 0x13, 0xcb, 0x30, 0x9c, 0x97, 0x03, 0xc7, 0x70, 0xe0, 0x00, + 0xb6, 0x11, 0xc0, 0x10, 0x90, 0x58, 0x32, 0x2c, 0x43, 0x90, 0x12, 0x44, 0x42, 0x62, 0x3a, 0x62, + 0x14, 0x39, 0x40, 0x02, 0x23, 0x80, 0x11, 0x04, 0xd9, 0x18, 0x4e, 0x50, 0xaf, 0xee, 0xea, 0xd7, + 0x90, 0xec, 0x21, 0x29, 0x1d, 0xec, 0xbf, 0xc8, 0xa9, 0xc7, 0xf7, 0x55, 0x55, 0x57, 0x7d, 0xf5, + 0x7d, 0x5f, 0x7d, 0x0f, 0x58, 0x6c, 0x59, 0xc1, 0x76, 0x77, 0x73, 0xbe, 0xe9, 0xb6, 0x6f, 0xb4, + 0x0c, 0xcf, 0x24, 0x0e, 0xf1, 0xa2, 0x7f, 0x3a, 0x3b, 0xad, 0x1b, 0x46, 0xc7, 0xf2, 0x6f, 0x34, + 0x5d, 0x8f, 0xdc, 0xd8, 0x7d, 0x6a, 0x93, 0x04, 0xc6, 0x53, 0x37, 0x5a, 0xb4, 0xce, 0x08, 0x88, + 0x39, 0xdf, 0xf1, 0xdc, 0xc0, 0x45, 0x4f, 0x47, 0x30, 0xe6, 0x65, 0xd7, 0xe8, 0x9f, 0xce, 0x4e, + 0x6b, 0x9e, 0xc2, 0x98, 0xa7, 0x30, 0xe6, 0x05, 0x8c, 0xb9, 0xef, 0x56, 0xf1, 0xba, 0x2d, 0xf7, + 0x06, 0x03, 0xb5, 0xd9, 0xdd, 0x62, 0xbf, 0xd8, 0x0f, 0xf6, 0x1f, 0x47, 0x31, 0xf7, 0xc4, 0xce, + 0x07, 0xfd, 0x79, 0xcb, 0xa5, 0x83, 0xb9, 0x61, 0x74, 0x03, 0xd7, 0x6f, 0x1a, 0xb6, 0xe5, 0xb4, + 0x6e, 0xec, 0xa6, 0x46, 0x33, 0xa7, 0x2b, 0x4d, 0xc5, 0xb0, 0xfb, 0xb6, 0xf1, 0x36, 0x8d, 0x66, + 0x56, 0x9b, 0xf7, 0x47, 0x6d, 0xda, 0x46, 0x73, 0xdb, 0x72, 0x88, 0xd7, 0x93, 0x0b, 0x72, 0xc3, + 0x23, 0xbe, 0xdb, 0xf5, 0x9a, 0xe4, 0x58, 0xbd, 0xfc, 0x1b, 0x6d, 0x12, 0x18, 0x59, 0xb8, 0x6e, + 0xe4, 0xf5, 0xf2, 0xba, 0x4e, 0x60, 0xb5, 0xd3, 0x68, 0xbe, 0xef, 0xb0, 0x0e, 0x7e, 0x73, 0x9b, + 0xb4, 0x8d, 0x54, 0xbf, 0xef, 0xcd, 0xeb, 0xd7, 0x0d, 0x2c, 0xfb, 0x86, 0xe5, 0x04, 0x7e, 0xe0, + 0x25, 0x3b, 0xe9, 0x6f, 0x6b, 0x30, 0xb3, 0xb0, 0x56, 0x6f, 0x10, 0x6f, 0x97, 0x78, 0xcb, 0x6e, + 0xab, 0x65, 0x39, 0x2d, 0xf4, 0x24, 0x8c, 0xef, 0x12, 0x6f, 0xd3, 0xf5, 0xad, 0xa0, 0x37, 0xab, + 0x5d, 0xd7, 0x1e, 0x1f, 0x59, 0x9c, 0x3a, 0xd8, 0xaf, 0x8c, 0xbf, 0x24, 0x0b, 0x71, 0x54, 0x8f, + 0xea, 0x70, 0x61, 0x3b, 0x08, 0x3a, 0x0b, 0xcd, 0x26, 0xf1, 0xfd, 0xb0, 0xc5, 0x6c, 0x89, 0x75, + 0x7b, 0xe8, 0x60, 0xbf, 0x72, 0xe1, 0xce, 0xfa, 0xfa, 0x5a, 0xa2, 0x1a, 0x67, 0xf5, 0xd1, 0x7f, + 0x4b, 0x83, 0xf3, 0xe1, 0x60, 0x30, 0x79, 0xa3, 0x4b, 0xfc, 0xc0, 0x47, 0x18, 0x2e, 0xb7, 0x8d, + 0xbd, 0x55, 0xd7, 0x59, 0xe9, 0x06, 0x46, 0x60, 0x39, 0xad, 0xba, 0xb3, 0x65, 0x5b, 0xad, 0xed, + 0x40, 0x0c, 0x6d, 0xee, 0x60, 0xbf, 0x72, 0x79, 0x25, 0xb3, 0x05, 0xce, 0xe9, 0x49, 0x07, 0xdd, + 0x36, 0xf6, 0x52, 0x00, 0x95, 0x41, 0xaf, 0xa4, 0xab, 0x71, 0x56, 0x1f, 0xfd, 0x69, 0x18, 0x59, + 0x30, 0x4d, 0xd7, 0x41, 0x4f, 0xc0, 0x18, 0x71, 0x8c, 0x4d, 0x9b, 0x98, 0x6c, 0x60, 0xe5, 0xc5, + 0x73, 0x5f, 0xd8, 0xaf, 0xbc, 0xeb, 0x60, 0xbf, 0x32, 0xb6, 0xc4, 0x8b, 0xb1, 0xac, 0xd7, 0x7f, + 0xb1, 0x04, 0xa3, 0xac, 0x93, 0x8f, 0x7e, 0x41, 0x83, 0x0b, 0x3b, 0xdd, 0x4d, 0xe2, 0x39, 0x24, + 0x20, 0x7e, 0xcd, 0xf0, 0xb7, 0x37, 0x5d, 0xc3, 0xe3, 0x20, 0x26, 0x9e, 0xbe, 0x3d, 0x7f, 0xfc, + 0xf3, 0x37, 0x7f, 0x37, 0x0d, 0x8e, 0xcf, 0x29, 0xa3, 0x02, 0x67, 0x21, 0x47, 0xbb, 0x30, 0xe9, + 0xb4, 0x2c, 0x67, 0xaf, 0xee, 0xb4, 0x3c, 0xe2, 0xfb, 0x6c, 0x5d, 0x26, 0x9e, 0xfe, 0x70, 0x91, + 0xc1, 0xac, 0x2a, 0x70, 0x16, 0x67, 0x0e, 0xf6, 0x2b, 0x93, 0x6a, 0x09, 0x8e, 0xe1, 0xd1, 0xff, + 0x4a, 0x83, 0x73, 0x0b, 0x66, 0xdb, 0xf2, 0x7d, 0xcb, 0x75, 0xd6, 0xec, 0x6e, 0xcb, 0x72, 0xd0, + 0x75, 0x18, 0x76, 0x8c, 0x36, 0x61, 0x0b, 0x32, 0xbe, 0x38, 0x29, 0xd6, 0x74, 0x78, 0xd5, 0x68, + 0x13, 0xcc, 0x6a, 0xd0, 0x8b, 0x30, 0xda, 0x74, 0x9d, 0x2d, 0xab, 0x25, 0xc6, 0xf9, 0xdd, 0xf3, + 0xfc, 0x24, 0xcc, 0xab, 0x27, 0x81, 0x0d, 0x4f, 0x9c, 0xa0, 0x79, 0x6c, 0xdc, 0x5f, 0xda, 0x0b, + 0x88, 0x43, 0xd1, 0x2c, 0xc2, 0xc1, 0x7e, 0x65, 0xb4, 0xca, 0x00, 0x60, 0x01, 0x08, 0x3d, 0x0e, + 0x65, 0xd3, 0xf2, 0xf9, 0xc7, 0x1c, 0x62, 0x1f, 0x73, 0xf2, 0x60, 0xbf, 0x52, 0xae, 0x89, 0x32, + 0x1c, 0xd6, 0xa2, 0x65, 0xb8, 0x48, 0x57, 0x90, 0xf7, 0x6b, 0x90, 0xa6, 0x47, 0x02, 0x3a, 0xb4, + 0xd9, 0x61, 0x36, 0xdc, 0xd9, 0x83, 0xfd, 0xca, 0xc5, 0xbb, 0x19, 0xf5, 0x38, 0xb3, 0x97, 0x7e, + 0x0b, 0xca, 0x0b, 0x36, 0xf1, 0xe8, 0x06, 0x43, 0x37, 0x61, 0x9a, 0xb4, 0x0d, 0xcb, 0xc6, 0xa4, + 0x49, 0xac, 0x5d, 0xe2, 0xf9, 0xb3, 0xda, 0xf5, 0xa1, 0xc7, 0xc7, 0x17, 0xd1, 0xc1, 0x7e, 0x65, + 0x7a, 0x29, 0x56, 0x83, 0x13, 0x2d, 0xf5, 0x8f, 0x6a, 0x30, 0xb1, 0xd0, 0x35, 0xad, 0x80, 0xcf, + 0x0b, 0x79, 0x30, 0x61, 0xd0, 0x9f, 0x6b, 0xae, 0x6d, 0x35, 0x7b, 0x62, 0x73, 0xbd, 0x50, 0xe4, + 0x7b, 0x2e, 0x44, 0x60, 0x16, 0xcf, 0x1d, 0xec, 0x57, 0x26, 0x94, 0x02, 0xac, 0x22, 0xd1, 0xb7, + 0x41, 0xad, 0x43, 0x1f, 0x81, 0x49, 0x3e, 0xdd, 0x15, 0xa3, 0x83, 0xc9, 0x96, 0x18, 0xc3, 0xa3, + 0xca, 0xb7, 0x92, 0x88, 0xe6, 0xef, 0x6d, 0xbe, 0x4e, 0x9a, 0x01, 0x26, 0x5b, 0xc4, 0x23, 0x4e, + 0x93, 0xf0, 0x6d, 0x53, 0x55, 0x3a, 0xe3, 0x18, 0x28, 0xfd, 0x4f, 0x29, 0x11, 0xdb, 0x35, 0x2c, + 0xdb, 0xd8, 0xb4, 0x6c, 0x2b, 0xe8, 0xbd, 0xea, 0x3a, 0xe4, 0x08, 0xfb, 0x66, 0x03, 0x1e, 0xea, + 0x3a, 0x06, 0xef, 0x67, 0x93, 0x15, 0xbe, 0x53, 0xd6, 0x7b, 0x1d, 0x42, 0x37, 0x3c, 0x5d, 0xe9, + 0xab, 0x07, 0xfb, 0x95, 0x87, 0x36, 0xb2, 0x9b, 0xe0, 0xbc, 0xbe, 0x94, 0x5e, 0x29, 0x55, 0x2f, + 0xb9, 0x76, 0xb7, 0x2d, 0xa0, 0x0e, 0x31, 0xa8, 0x8c, 0x5e, 0x6d, 0x64, 0xb6, 0xc0, 0x39, 0x3d, + 0xf5, 0x2f, 0x94, 0x60, 0x72, 0xd1, 0x68, 0xee, 0x74, 0x3b, 0x8b, 0xdd, 0xe6, 0x0e, 0x09, 0xd0, + 0x8f, 0x40, 0x99, 0x5e, 0x38, 0xa6, 0x11, 0x18, 0x62, 0x25, 0xbf, 0x27, 0x77, 0xd7, 0xb3, 0x8f, + 0x48, 0x5b, 0x47, 0x6b, 0xbb, 0x42, 0x02, 0x63, 0x11, 0x89, 0x35, 0x81, 0xa8, 0x0c, 0x87, 0x50, + 0xd1, 0x16, 0x0c, 0xfb, 0x1d, 0xd2, 0x14, 0x67, 0xaa, 0x56, 0x64, 0xaf, 0xa8, 0x23, 0x6e, 0x74, + 0x48, 0x33, 0xfa, 0x0a, 0xf4, 0x17, 0x66, 0xf0, 0x91, 0x03, 0xa3, 0x7e, 0x60, 0x04, 0x5d, 0x9f, + 0x1d, 0xb4, 0x89, 0xa7, 0x6f, 0x0d, 0x8c, 0x89, 0x41, 0x5b, 0x9c, 0x16, 0xb8, 0x46, 0xf9, 0x6f, + 0x2c, 0xb0, 0xe8, 0xff, 0x5e, 0x83, 0x19, 0xb5, 0xf9, 0xb2, 0xe5, 0x07, 0xe8, 0x87, 0x52, 0xcb, + 0x39, 0x7f, 0xb4, 0xe5, 0xa4, 0xbd, 0xd9, 0x62, 0xce, 0x08, 0x74, 0x65, 0x59, 0xa2, 0x2c, 0x25, + 0x81, 0x11, 0x2b, 0x20, 0x6d, 0xbe, 0xad, 0x0a, 0xd2, 0x51, 0x75, 0xc8, 0x8b, 0x53, 0x02, 0xd9, + 0x48, 0x9d, 0x82, 0xc5, 0x1c, 0xba, 0xfe, 0x23, 0x70, 0x51, 0x6d, 0xb5, 0xe6, 0xb9, 0xbb, 0x96, + 0x49, 0x3c, 0x7a, 0x12, 0x82, 0x5e, 0x27, 0x75, 0x12, 0xe8, 0xce, 0xc2, 0xac, 0x06, 0xbd, 0x17, + 0x46, 0x3d, 0xd2, 0xb2, 0x5c, 0x87, 0x7d, 0xed, 0xf1, 0x68, 0xed, 0x30, 0x2b, 0xc5, 0xa2, 0x56, + 0xff, 0x9f, 0xa5, 0xf8, 0xda, 0xd1, 0xcf, 0x88, 0x76, 0xa1, 0xdc, 0x11, 0xa8, 0xc4, 0xda, 0xdd, + 0x19, 0x74, 0x82, 0x72, 0xe8, 0xd1, 0xaa, 0xca, 0x12, 0x1c, 0xe2, 0x42, 0x16, 0x4c, 0xcb, 0xff, + 0xab, 0x03, 0x90, 0x7f, 0x46, 0x4e, 0xd7, 0x62, 0x80, 0x70, 0x02, 0x30, 0x5a, 0x87, 0x71, 0x9f, + 0x11, 0x69, 0x4a, 0xb8, 0x86, 0xf2, 0x09, 0x57, 0x43, 0x36, 0x12, 0x84, 0xeb, 0xbc, 0x18, 0xfe, + 0x78, 0x58, 0x81, 0x23, 0x40, 0xf4, 0x92, 0xf1, 0x09, 0x31, 0x95, 0xeb, 0x82, 0x5d, 0x32, 0x0d, + 0x51, 0x86, 0xc3, 0x5a, 0xfd, 0x73, 0xc3, 0x80, 0xd2, 0x5b, 0x5c, 0x5d, 0x01, 0x5e, 0x22, 0xd6, + 0x7f, 0x90, 0x15, 0x10, 0xa7, 0x25, 0x01, 0x18, 0xbd, 0x09, 0x53, 0xb6, 0xe1, 0x07, 0xf7, 0x3a, + 0x94, 0x7b, 0x94, 0x1b, 0x65, 0xe2, 0xe9, 0x85, 0x22, 0x5f, 0x7a, 0x59, 0x05, 0xb4, 0x78, 0xfe, + 0x60, 0xbf, 0x32, 0x15, 0x2b, 0xc2, 0x71, 0x54, 0xe8, 0x75, 0x18, 0xa7, 0x05, 0x4b, 0x9e, 0xe7, + 0x7a, 0x62, 0xf5, 0x9f, 0x2b, 0x8a, 0x97, 0x01, 0xe1, 0xdc, 0x6c, 0xf8, 0x13, 0x47, 0xe0, 0xd1, + 0x0f, 0x00, 0x72, 0x37, 0x7d, 0xca, 0x80, 0x9a, 0xb7, 0x39, 0xab, 0x4c, 0x27, 0x4b, 0xbf, 0xce, + 0xd0, 0xe2, 0x9c, 0xf8, 0x9a, 0xe8, 0x5e, 0xaa, 0x05, 0xce, 0xe8, 0x85, 0x76, 0x00, 0x85, 0xec, + 0x76, 0xb8, 0x01, 0x66, 0x47, 0x8e, 0xbe, 0x7d, 0x2e, 0x53, 0x64, 0xb7, 0x53, 0x20, 0x70, 0x06, + 0x58, 0xfd, 0x5f, 0x97, 0x60, 0x82, 0x6f, 0x91, 0x25, 0x27, 0xf0, 0x7a, 0x67, 0x70, 0x41, 0x90, + 0xd8, 0x05, 0x51, 0x2d, 0x7e, 0xe6, 0xd9, 0x80, 0x73, 0xef, 0x87, 0x76, 0xe2, 0x7e, 0x58, 0x1a, + 0x14, 0x51, 0xff, 0xeb, 0xe1, 0xdf, 0x69, 0x70, 0x4e, 0x69, 0x7d, 0x06, 0xb7, 0x83, 0x19, 0xbf, + 0x1d, 0x5e, 0x18, 0x70, 0x7e, 0x39, 0x97, 0x83, 0x1b, 0x9b, 0x16, 0x23, 0xdc, 0x4f, 0x03, 0x6c, + 0x32, 0x72, 0xb2, 0x1a, 0xf1, 0x49, 0xe1, 0x27, 0x5f, 0x0c, 0x6b, 0xb0, 0xd2, 0x2a, 0x46, 0xb3, + 0x4a, 0x7d, 0x69, 0xd6, 0x7f, 0x19, 0x82, 0xf3, 0xa9, 0x65, 0x4f, 0xd3, 0x11, 0xed, 0xdb, 0x44, + 0x47, 0x4a, 0xdf, 0x0e, 0x3a, 0x32, 0x54, 0x88, 0x8e, 0x1c, 0xf9, 0x9e, 0x40, 0x1e, 0xa0, 0xb6, + 0xd5, 0xe2, 0xdd, 0x1a, 0x81, 0xe1, 0x05, 0xeb, 0x56, 0x9b, 0x08, 0x8a, 0xf3, 0x5d, 0x47, 0xdb, + 0xb2, 0xb4, 0x07, 0x27, 0x3c, 0x2b, 0x29, 0x48, 0x38, 0x03, 0xba, 0xfe, 0x95, 0x61, 0x80, 0xea, + 0x02, 0x76, 0x03, 0x3e, 0xd8, 0x17, 0x60, 0xa4, 0xb3, 0x6d, 0xf8, 0x72, 0x3f, 0x3d, 0x21, 0x37, + 0xe3, 0x1a, 0x2d, 0x7c, 0xb0, 0x5f, 0x99, 0xad, 0x7a, 0xc4, 0x24, 0x4e, 0x60, 0x19, 0xb6, 0x2f, + 0x3b, 0xb1, 0x3a, 0xcc, 0xfb, 0xd1, 0x39, 0xd0, 0x65, 0xac, 0xba, 0xed, 0x8e, 0x4d, 0x68, 0x2d, + 0x9b, 0x43, 0xa9, 0xd8, 0x1c, 0x96, 0x53, 0x90, 0x70, 0x06, 0x74, 0x89, 0xb3, 0xee, 0x58, 0x81, + 0x65, 0x84, 0x38, 0x87, 0x8a, 0xe3, 0x8c, 0x43, 0xc2, 0x19, 0xd0, 0xd1, 0xdb, 0x1a, 0xcc, 0xc5, + 0x8b, 0x6f, 0x59, 0x8e, 0xe5, 0x6f, 0x13, 0x93, 0x21, 0x1f, 0x3e, 0x36, 0xf2, 0x6b, 0x07, 0xfb, + 0x95, 0xb9, 0xe5, 0x5c, 0x88, 0xb8, 0x0f, 0x36, 0xf4, 0x49, 0x0d, 0xae, 0x26, 0xd6, 0xc5, 0xb3, + 0x5a, 0x2d, 0xe2, 0x89, 0xd1, 0x1c, 0x7f, 0x0b, 0x55, 0x0e, 0xf6, 0x2b, 0x57, 0x97, 0xf3, 0x41, + 0xe2, 0x7e, 0xf8, 0xf4, 0xcf, 0x6b, 0x30, 0x54, 0xc5, 0x75, 0xf4, 0x64, 0x4c, 0x88, 0x7b, 0x48, + 0x15, 0xe2, 0x1e, 0xec, 0x57, 0xc6, 0xaa, 0xb8, 0xae, 0xc8, 0x73, 0x9f, 0xd4, 0xe0, 0x7c, 0xd3, + 0x75, 0x02, 0x83, 0x8e, 0x0b, 0x73, 0x4e, 0x47, 0x52, 0xd5, 0x42, 0xf2, 0x4b, 0x35, 0x01, 0x6c, + 0xf1, 0x8a, 0x18, 0xc0, 0xf9, 0x64, 0x8d, 0x8f, 0xd3, 0x98, 0xf5, 0xaf, 0x69, 0x30, 0x59, 0xb5, + 0xdd, 0xae, 0xb9, 0xe6, 0xb9, 0x5b, 0x96, 0x4d, 0xde, 0x19, 0x42, 0x9b, 0x3a, 0xe2, 0xbc, 0x4b, + 0x99, 0x09, 0x51, 0x6a, 0xc3, 0x77, 0x88, 0x10, 0xa5, 0x0e, 0x39, 0xe7, 0x9e, 0xfc, 0xc5, 0xb1, + 0xf8, 0xcc, 0xd8, 0x4d, 0xf9, 0x38, 0x94, 0x9b, 0xc6, 0x62, 0xd7, 0x31, 0xed, 0x50, 0x8a, 0xa2, + 0xa3, 0xac, 0x2e, 0xf0, 0x32, 0x1c, 0xd6, 0xa2, 0x37, 0x01, 0x22, 0x85, 0x9a, 0xf8, 0x0c, 0xb7, + 0x06, 0x53, 0xe2, 0x35, 0x48, 0x10, 0x58, 0x4e, 0xcb, 0x8f, 0x3e, 0x7d, 0x54, 0x87, 0x15, 0x6c, + 0xe8, 0xc7, 0x60, 0x4a, 0x2c, 0x72, 0xbd, 0x6d, 0xb4, 0x84, 0xbe, 0xa1, 0xe0, 0x4a, 0xad, 0x28, + 0x80, 0x16, 0x2f, 0x09, 0xc4, 0x53, 0x6a, 0xa9, 0x8f, 0xe3, 0xd8, 0x50, 0x0f, 0x26, 0xdb, 0xaa, + 0x0e, 0x65, 0xb8, 0x38, 0x3b, 0xa3, 0xe8, 0x53, 0x16, 0x2f, 0x0a, 0xe4, 0x93, 0x31, 0xed, 0x4b, + 0x0c, 0x55, 0x86, 0x28, 0x38, 0x72, 0x5a, 0xa2, 0x20, 0x81, 0x31, 0x2e, 0x0c, 0xfb, 0xb3, 0xa3, + 0x6c, 0x82, 0x37, 0x8b, 0x4c, 0x90, 0xcb, 0xd5, 0x91, 0x86, 0x98, 0xff, 0xf6, 0xb1, 0x84, 0x8d, + 0x76, 0x61, 0x92, 0xde, 0xea, 0x0d, 0x62, 0x93, 0x66, 0xe0, 0x7a, 0xb3, 0x63, 0xc5, 0x35, 0xb0, + 0x0d, 0x05, 0x0e, 0x57, 0xa5, 0xa9, 0x25, 0x38, 0x86, 0x27, 0xd4, 0x15, 0x94, 0x73, 0x75, 0x05, + 0x5d, 0x98, 0xd8, 0x55, 0x74, 0x5a, 0xe3, 0x6c, 0x11, 0x9e, 0x2f, 0x32, 0xb0, 0x48, 0xc1, 0xb5, + 0x78, 0x41, 0x20, 0x9a, 0x50, 0x95, 0x61, 0x2a, 0x1e, 0xfd, 0x1f, 0x00, 0x9c, 0xaf, 0xda, 0x5d, + 0x3f, 0x20, 0xde, 0x82, 0x78, 0x24, 0x22, 0x1e, 0xfa, 0x98, 0x06, 0x97, 0xd9, 0xbf, 0x35, 0xf7, + 0xbe, 0x53, 0x23, 0xb6, 0xd1, 0x5b, 0xd8, 0xa2, 0x2d, 0x4c, 0xf3, 0x78, 0x14, 0xa8, 0xd6, 0x15, + 0x5c, 0x24, 0x53, 0xce, 0x35, 0x32, 0x21, 0xe2, 0x1c, 0x4c, 0xe8, 0x67, 0x35, 0xb8, 0x92, 0x51, + 0x55, 0x23, 0x36, 0x09, 0x24, 0xe7, 0x72, 0xdc, 0x71, 0x3c, 0x72, 0xb0, 0x5f, 0xb9, 0xd2, 0xc8, + 0x03, 0x8a, 0xf3, 0xf1, 0xa1, 0xbf, 0xa3, 0xc1, 0x5c, 0x46, 0xed, 0x2d, 0xc3, 0xb2, 0xbb, 0x9e, + 0x64, 0x6a, 0x8e, 0x3b, 0x1c, 0xc6, 0x5b, 0x34, 0x72, 0xa1, 0xe2, 0x3e, 0x18, 0xd1, 0x8f, 0xc3, + 0xa5, 0xb0, 0x76, 0xc3, 0x71, 0x08, 0x31, 0x63, 0x2c, 0xce, 0x71, 0x87, 0x72, 0xe5, 0x60, 0xbf, + 0x72, 0xa9, 0x91, 0x05, 0x10, 0x67, 0xe3, 0x41, 0x2d, 0x78, 0x24, 0xaa, 0x08, 0x2c, 0xdb, 0x7a, + 0x93, 0x73, 0x61, 0xdb, 0x1e, 0xf1, 0xb7, 0x5d, 0xdb, 0x64, 0xc4, 0x42, 0x5b, 0x7c, 0xf7, 0xc1, + 0x7e, 0xe5, 0x91, 0x46, 0xbf, 0x86, 0xb8, 0x3f, 0x1c, 0x64, 0xc2, 0xa4, 0xdf, 0x34, 0x9c, 0xba, + 0x13, 0x10, 0x6f, 0xd7, 0xb0, 0x67, 0x47, 0x0b, 0x4d, 0x90, 0x1f, 0x51, 0x05, 0x0e, 0x8e, 0x41, + 0x45, 0x1f, 0x84, 0x32, 0xd9, 0xeb, 0x18, 0x8e, 0x49, 0x38, 0x59, 0x18, 0x5f, 0x7c, 0x98, 0x5e, + 0x46, 0x4b, 0xa2, 0xec, 0xc1, 0x7e, 0x65, 0x52, 0xfe, 0xbf, 0xe2, 0x9a, 0x04, 0x87, 0xad, 0xd1, + 0x8f, 0xc2, 0x45, 0xf6, 0x1e, 0x66, 0x12, 0x46, 0xe4, 0x7c, 0xc9, 0xe8, 0x96, 0x0b, 0x8d, 0x93, + 0xbd, 0x6d, 0xac, 0x64, 0xc0, 0xc3, 0x99, 0x58, 0xe8, 0x67, 0x68, 0x1b, 0x7b, 0xb7, 0x3d, 0xa3, + 0x49, 0xb6, 0xba, 0xf6, 0x3a, 0xf1, 0xda, 0x96, 0xc3, 0x65, 0x09, 0xd2, 0x74, 0x1d, 0x93, 0x92, + 0x12, 0xed, 0xf1, 0x11, 0xfe, 0x19, 0x56, 0xfa, 0x35, 0xc4, 0xfd, 0xe1, 0xa0, 0xf7, 0xc3, 0xa4, + 0xd5, 0x72, 0x5c, 0x8f, 0xac, 0x1b, 0x96, 0x13, 0xf8, 0xb3, 0xc0, 0xd4, 0xee, 0x6c, 0x59, 0xeb, + 0x4a, 0x39, 0x8e, 0xb5, 0x42, 0xbb, 0x80, 0x1c, 0x72, 0x7f, 0xcd, 0x35, 0xd9, 0x16, 0xd8, 0xe8, + 0xb0, 0x8d, 0x3c, 0x3b, 0x51, 0x68, 0x69, 0x98, 0x1c, 0xb0, 0x9a, 0x82, 0x86, 0x33, 0x30, 0xa0, + 0x5b, 0x80, 0xda, 0xc6, 0xde, 0x52, 0xbb, 0x13, 0xf4, 0x16, 0xbb, 0xf6, 0x8e, 0xa0, 0x1a, 0x93, + 0x6c, 0x2d, 0xb8, 0x1c, 0x96, 0xaa, 0xc5, 0x19, 0x3d, 0xf4, 0xfd, 0x21, 0x18, 0xaf, 0xba, 0x8e, + 0x69, 0x31, 0x31, 0xec, 0xa9, 0x98, 0xce, 0xf7, 0x11, 0x95, 0x8e, 0x3f, 0xd8, 0xaf, 0x4c, 0x85, + 0x0d, 0x15, 0xc2, 0xfe, 0x6c, 0xa8, 0x68, 0xe1, 0x82, 0xfd, 0xbb, 0xe3, 0x1a, 0x92, 0x07, 0xfb, + 0x95, 0x73, 0x61, 0xb7, 0xb8, 0xd2, 0x84, 0xae, 0x1d, 0xe5, 0xe6, 0xd7, 0x3d, 0xc3, 0xf1, 0xad, + 0x01, 0xe4, 0xa7, 0x50, 0x32, 0x5e, 0x4e, 0x41, 0xc3, 0x19, 0x18, 0xd0, 0xeb, 0x30, 0x4d, 0x4b, + 0x37, 0x3a, 0xa6, 0x11, 0x90, 0x82, 0x62, 0xd3, 0x65, 0x81, 0x73, 0x7a, 0x39, 0x06, 0x09, 0x27, + 0x20, 0x73, 0x1d, 0xb9, 0xe1, 0xbb, 0x0e, 0x23, 0x17, 0x31, 0x1d, 0x39, 0x2d, 0xc5, 0xa2, 0x16, + 0x3d, 0x01, 0x63, 0x6d, 0xe2, 0xfb, 0x46, 0x8b, 0xb0, 0xf3, 0x3f, 0x1e, 0x5d, 0xf2, 0x2b, 0xbc, + 0x18, 0xcb, 0x7a, 0xf4, 0x3e, 0x18, 0x69, 0xba, 0x26, 0xf1, 0x67, 0xc7, 0xd8, 0x0e, 0xa5, 0x5f, + 0x7b, 0xa4, 0x4a, 0x0b, 0x1e, 0xec, 0x57, 0xc6, 0x99, 0x1e, 0x81, 0xfe, 0xc2, 0xbc, 0x91, 0xfe, + 0xcb, 0x94, 0xe7, 0x4e, 0x08, 0x19, 0x47, 0xd0, 0xed, 0x9f, 0x9d, 0x9a, 0x5c, 0xff, 0x14, 0x15, + 0x78, 0x5c, 0x27, 0xf0, 0x5c, 0x7b, 0xcd, 0x36, 0x1c, 0x82, 0x7e, 0x5a, 0x83, 0x99, 0x6d, 0xab, + 0xb5, 0xad, 0x3e, 0xce, 0x89, 0x8b, 0xb9, 0x90, 0x6c, 0x72, 0x27, 0x01, 0x6b, 0xf1, 0xe2, 0xc1, + 0x7e, 0x65, 0x26, 0x59, 0x8a, 0x53, 0x38, 0xf5, 0x4f, 0x94, 0xe0, 0xa2, 0x18, 0x99, 0x4d, 0x6f, + 0xca, 0x8e, 0xed, 0xf6, 0xda, 0xc4, 0x39, 0x8b, 0x77, 0x34, 0xf9, 0x85, 0x4a, 0xb9, 0x5f, 0xa8, + 0x9d, 0xfa, 0x42, 0x43, 0x45, 0xbe, 0x50, 0xb8, 0x91, 0x0f, 0xf9, 0x4a, 0x7f, 0xa6, 0xc1, 0x6c, + 0xd6, 0x5a, 0x9c, 0x81, 0x0c, 0xd7, 0x8e, 0xcb, 0x70, 0x77, 0x8a, 0x0a, 0xe5, 0xc9, 0xa1, 0xe7, + 0xc8, 0x72, 0xdf, 0x2a, 0xc1, 0xe5, 0xa8, 0x79, 0xdd, 0xf1, 0x03, 0xc3, 0xb6, 0xb9, 0x9a, 0xea, + 0xf4, 0xbf, 0x7b, 0x27, 0x26, 0x8a, 0xaf, 0x0e, 0x36, 0x55, 0x75, 0xec, 0xb9, 0x9a, 0xf2, 0xbd, + 0x84, 0xa6, 0x7c, 0xed, 0x04, 0x71, 0xf6, 0x57, 0x9a, 0xff, 0x37, 0x0d, 0xe6, 0xb2, 0x3b, 0x9e, + 0xc1, 0xa6, 0x72, 0xe3, 0x9b, 0xea, 0x07, 0x4e, 0x6e, 0xd6, 0x39, 0xdb, 0xea, 0xb7, 0x4a, 0x79, + 0xb3, 0x65, 0xca, 0x82, 0x2d, 0x38, 0x47, 0xa5, 0x38, 0x3f, 0x10, 0x2a, 0xdd, 0xe3, 0xd9, 0x3a, + 0x48, 0x1d, 0xd7, 0x39, 0x1c, 0x87, 0x81, 0x93, 0x40, 0xd1, 0x2a, 0x8c, 0x51, 0xd1, 0x8d, 0xc2, + 0x2f, 0x1d, 0x1d, 0x7e, 0x78, 0x1b, 0x35, 0x78, 0x5f, 0x2c, 0x81, 0xa0, 0x1f, 0x82, 0x29, 0x33, + 0x3c, 0x51, 0x87, 0x3c, 0x74, 0x26, 0xa1, 0x32, 0xe5, 0x7b, 0x4d, 0xed, 0x8d, 0xe3, 0xc0, 0xf4, + 0xbf, 0xd4, 0xe0, 0xe1, 0x7e, 0x7b, 0x0b, 0xbd, 0x01, 0xd0, 0x94, 0xec, 0x05, 0x37, 0x75, 0x29, + 0xa8, 0x9e, 0x0f, 0x99, 0x94, 0xe8, 0x80, 0x86, 0x45, 0x3e, 0x56, 0x90, 0x64, 0xbc, 0x9f, 0x96, + 0x4e, 0xe9, 0xfd, 0x54, 0xff, 0xef, 0x9a, 0x4a, 0x8a, 0xd4, 0x6f, 0xfb, 0x4e, 0x23, 0x45, 0xea, + 0xd8, 0x73, 0xf5, 0x83, 0x5f, 0x2d, 0xc1, 0xf5, 0xec, 0x2e, 0xca, 0xdd, 0xfb, 0x61, 0x18, 0xed, + 0x70, 0x7b, 0xa4, 0x21, 0x76, 0x37, 0x3e, 0x4e, 0x29, 0x0b, 0xb7, 0x16, 0x7a, 0xb0, 0x5f, 0x99, + 0xcb, 0x22, 0xf4, 0xc2, 0xce, 0x48, 0xf4, 0x43, 0x56, 0x42, 0x4b, 0xc2, 0xb9, 0xbf, 0xef, 0x3d, + 0x22, 0x71, 0x31, 0x36, 0x89, 0x7d, 0x64, 0xc5, 0xc8, 0x47, 0x35, 0x98, 0x8e, 0xed, 0x68, 0x7f, + 0x76, 0x84, 0xed, 0xd1, 0x42, 0x4f, 0x57, 0xb1, 0xa3, 0x12, 0xdd, 0xdc, 0xb1, 0x62, 0x1f, 0x27, + 0x10, 0x26, 0xc8, 0xac, 0xba, 0xaa, 0xef, 0x38, 0x32, 0xab, 0x0e, 0x3e, 0x87, 0xcc, 0xfe, 0x52, + 0x29, 0x6f, 0xb6, 0x8c, 0xcc, 0xde, 0x87, 0x71, 0x69, 0xa9, 0x2b, 0xc9, 0xc5, 0xad, 0x41, 0xc7, + 0xc4, 0xc1, 0x45, 0x66, 0x1b, 0xb2, 0xc4, 0xc7, 0x11, 0x2e, 0xf4, 0x53, 0x1a, 0x40, 0xf4, 0x61, + 0xc4, 0xa1, 0x5a, 0x3f, 0xb9, 0xe5, 0x50, 0xd8, 0x9a, 0x69, 0x7a, 0xa4, 0x95, 0x4d, 0xa1, 0xe0, + 0xd5, 0xff, 0xf7, 0x10, 0xa0, 0xf4, 0xd8, 0x29, 0xbb, 0xb9, 0x63, 0x39, 0x66, 0x52, 0x20, 0xb8, + 0x6b, 0x39, 0x26, 0x66, 0x35, 0x47, 0x60, 0x48, 0x9f, 0x83, 0x73, 0x2d, 0xdb, 0xdd, 0x34, 0x6c, + 0xbb, 0x27, 0x4c, 0x57, 0x85, 0x11, 0xe4, 0x05, 0x7a, 0x31, 0xdd, 0x8e, 0x57, 0xe1, 0x64, 0x5b, + 0xd4, 0x81, 0x19, 0x8f, 0x8a, 0xe2, 0x4d, 0xcb, 0x66, 0xa2, 0x93, 0xdb, 0x0d, 0x0a, 0xea, 0x7a, + 0x18, 0x7b, 0x8f, 0x13, 0xb0, 0x70, 0x0a, 0x3a, 0x7a, 0x0f, 0x8c, 0x75, 0x3c, 0xab, 0x6d, 0x78, + 0x3d, 0x26, 0x9c, 0x95, 0x17, 0x27, 0xe8, 0x0d, 0xb7, 0xc6, 0x8b, 0xb0, 0xac, 0x43, 0x3f, 0x0a, + 0xe3, 0xb6, 0xb5, 0x45, 0x9a, 0xbd, 0xa6, 0x4d, 0x84, 0x72, 0xe6, 0xde, 0xc9, 0x6c, 0x99, 0x65, + 0x09, 0x56, 0x3c, 0x09, 0xcb, 0x9f, 0x38, 0x42, 0x88, 0xea, 0x70, 0xe1, 0xbe, 0xeb, 0xed, 0x10, + 0xcf, 0x26, 0xbe, 0xdf, 0xe8, 0x76, 0x3a, 0xae, 0x17, 0x10, 0x93, 0xa9, 0x70, 0xca, 0xdc, 0x3e, + 0xf7, 0xe5, 0x74, 0x35, 0xce, 0xea, 0xa3, 0xbf, 0x5d, 0x82, 0xab, 0x7d, 0x06, 0x81, 0x30, 0x3d, + 0x1b, 0x62, 0x8d, 0xc4, 0x4e, 0x78, 0x3f, 0xdf, 0xcf, 0xa2, 0xf0, 0xc1, 0x7e, 0xe5, 0xd1, 0x3e, + 0x00, 0x1a, 0x74, 0x2b, 0x92, 0x56, 0x0f, 0x47, 0x60, 0x50, 0x1d, 0x46, 0xcd, 0x48, 0xa3, 0x39, + 0xbe, 0xf8, 0x14, 0xa5, 0xd6, 0x5c, 0xf7, 0x70, 0x54, 0x68, 0x02, 0x00, 0x5a, 0x86, 0x31, 0xfe, + 0x90, 0x4c, 0x04, 0xe5, 0x7f, 0x9a, 0x89, 0xc7, 0xbc, 0xe8, 0xa8, 0xc0, 0x24, 0x08, 0xfd, 0x7f, + 0x69, 0x30, 0x56, 0x75, 0x3d, 0x52, 0x5b, 0x6d, 0xa0, 0x1e, 0x4c, 0x28, 0x2e, 0x04, 0x82, 0x0a, + 0x16, 0x24, 0x0b, 0x0c, 0xe2, 0x42, 0x04, 0x4d, 0x9a, 0xbb, 0x86, 0x05, 0x58, 0xc5, 0x85, 0xde, + 0xa0, 0x6b, 0x7e, 0xdf, 0xb3, 0x02, 0x8a, 0x78, 0x90, 0xf7, 0x37, 0x8e, 0x18, 0x4b, 0x58, 0x7c, + 0x47, 0x85, 0x3f, 0x71, 0x84, 0x45, 0x5f, 0xa3, 0x14, 0x20, 0x39, 0x4c, 0x74, 0x13, 0x86, 0xdb, + 0xae, 0x29, 0xbf, 0xfb, 0x7b, 0xe5, 0xf9, 0x5e, 0x71, 0x4d, 0xba, 0xb6, 0x97, 0xd3, 0x3d, 0x98, + 0x96, 0x90, 0xf5, 0xd1, 0x57, 0x61, 0x26, 0x89, 0x1f, 0xdd, 0x84, 0xe9, 0xa6, 0xdb, 0x6e, 0xbb, + 0x4e, 0xa3, 0xbb, 0xb5, 0x65, 0xed, 0x91, 0x98, 0x1d, 0x72, 0x35, 0x56, 0x83, 0x13, 0x2d, 0xf5, + 0xcf, 0x6a, 0x30, 0x44, 0xbf, 0x8b, 0x0e, 0xa3, 0xa6, 0xdb, 0x36, 0x2c, 0x47, 0x8c, 0x8a, 0xd9, + 0x5c, 0xd7, 0x58, 0x09, 0x16, 0x35, 0xa8, 0x03, 0xe3, 0x92, 0x69, 0x1a, 0xc8, 0x16, 0xa6, 0xb6, + 0xda, 0x08, 0xed, 0x07, 0x43, 0x4a, 0x2e, 0x4b, 0x7c, 0x1c, 0x21, 0xd1, 0x0d, 0x38, 0x5f, 0x5b, + 0x6d, 0xd4, 0x9d, 0xa6, 0xdd, 0x35, 0xc9, 0xd2, 0x1e, 0xfb, 0x43, 0x69, 0x89, 0xc5, 0x4b, 0xc4, + 0x3c, 0x19, 0x2d, 0x11, 0x8d, 0xb0, 0xac, 0xa3, 0xcd, 0x08, 0xef, 0x21, 0x8c, 0x85, 0x59, 0x33, + 0x01, 0x04, 0xcb, 0x3a, 0xfd, 0x6b, 0x25, 0x98, 0x50, 0x06, 0x84, 0x6c, 0x18, 0xe3, 0xd3, 0x95, + 0xb6, 0x7a, 0x4b, 0x05, 0xa7, 0x18, 0x1f, 0x35, 0xc7, 0xce, 0x17, 0xd4, 0xc7, 0x12, 0x85, 0x4a, + 0x17, 0x4b, 0x7d, 0xe8, 0xe2, 0x3c, 0x80, 0x1f, 0x59, 0xae, 0xf3, 0x23, 0xc9, 0xae, 0x1e, 0xc5, + 0x5e, 0x5d, 0x69, 0x81, 0x1e, 0x16, 0x37, 0x08, 0x37, 0x46, 0x29, 0x27, 0x6e, 0x8f, 0x2d, 0x18, + 0x79, 0xd3, 0x75, 0x88, 0x2f, 0xde, 0xe0, 0x4e, 0x68, 0x82, 0xe3, 0x94, 0x3f, 0x78, 0x95, 0xc2, + 0xc5, 0x1c, 0xbc, 0xfe, 0x2b, 0x1a, 0x40, 0xcd, 0x08, 0x0c, 0xfe, 0x64, 0x74, 0x04, 0x7b, 0xef, + 0x87, 0x63, 0x17, 0x5f, 0x39, 0x65, 0x03, 0x3b, 0xec, 0x5b, 0x6f, 0xca, 0xe9, 0x87, 0x0c, 0x35, + 0x87, 0xde, 0xb0, 0xde, 0x24, 0x98, 0xd5, 0xa3, 0x27, 0x61, 0x9c, 0x38, 0x4d, 0xaf, 0xd7, 0xa1, + 0xc4, 0x7b, 0x98, 0xad, 0x2a, 0x3b, 0xa1, 0x4b, 0xb2, 0x10, 0x47, 0xf5, 0xfa, 0x53, 0x10, 0x97, + 0x8a, 0x0e, 0x1f, 0xa5, 0xfe, 0x8d, 0x61, 0xb8, 0xb2, 0xb4, 0x5e, 0xad, 0x09, 0x78, 0x96, 0xeb, + 0xdc, 0x25, 0xbd, 0xbf, 0x31, 0xaf, 0xf9, 0x1b, 0xf3, 0x9a, 0x13, 0x34, 0xaf, 0x79, 0xa0, 0xc1, + 0xcc, 0xd2, 0x5e, 0xc7, 0xf2, 0x98, 0x9f, 0x01, 0xf1, 0xa8, 0x18, 0x8b, 0x9e, 0x80, 0xb1, 0x5d, + 0xfe, 0xaf, 0xd8, 0x5c, 0xa1, 0xaa, 0x40, 0xb4, 0xc0, 0xb2, 0x1e, 0x6d, 0xc1, 0x34, 0x61, 0xdd, + 0x19, 0xbf, 0x6a, 0x04, 0x45, 0x36, 0x10, 0x77, 0x63, 0x89, 0x41, 0xc1, 0x09, 0xa8, 0xa8, 0x01, + 0xd3, 0x4d, 0xdb, 0xf0, 0x7d, 0x6b, 0xcb, 0x6a, 0x46, 0x16, 0x74, 0xe3, 0x8b, 0x4f, 0xb2, 0xab, + 0x27, 0x56, 0xf3, 0x60, 0xbf, 0x72, 0x49, 0x8c, 0x33, 0x5e, 0x81, 0x13, 0x20, 0xf4, 0x4f, 0x97, + 0x60, 0x6a, 0x69, 0xaf, 0xe3, 0xfa, 0x5d, 0x8f, 0xb0, 0xa6, 0x67, 0x20, 0x81, 0x3f, 0x01, 0x63, + 0xdb, 0x86, 0x63, 0xda, 0xc4, 0x13, 0xd4, 0x27, 0x5c, 0xdb, 0x3b, 0xbc, 0x18, 0xcb, 0x7a, 0xf4, + 0x16, 0x80, 0xdf, 0xdc, 0x26, 0x66, 0x97, 0x71, 0x30, 0xfc, 0x90, 0xdc, 0x2d, 0x42, 0x43, 0x63, + 0x73, 0x6c, 0x84, 0x20, 0x05, 0x65, 0x0f, 0x7f, 0x63, 0x05, 0x9d, 0xfe, 0x75, 0x0d, 0xce, 0xc7, + 0xfa, 0x9d, 0x81, 0x60, 0xb9, 0x15, 0x17, 0x2c, 0x17, 0x06, 0x9e, 0x6b, 0x8e, 0x3c, 0xf9, 0x33, + 0x25, 0x78, 0x28, 0x67, 0x4d, 0x52, 0xe6, 0x16, 0xda, 0x19, 0x99, 0x5b, 0x74, 0x61, 0x22, 0x70, + 0x6d, 0x61, 0xe8, 0x29, 0x57, 0xa0, 0x90, 0x31, 0xc5, 0x7a, 0x08, 0x26, 0x32, 0xa6, 0x88, 0xca, + 0x7c, 0xac, 0xe2, 0xd1, 0x3f, 0xaf, 0xc1, 0x78, 0xa8, 0xbf, 0xfa, 0x8e, 0x7a, 0x43, 0x3a, 0xba, + 0xe7, 0x9d, 0xfe, 0x47, 0x25, 0xb8, 0x1c, 0xc2, 0x96, 0x72, 0x42, 0x23, 0xa0, 0x74, 0xe3, 0x70, + 0x21, 0xf8, 0x61, 0x71, 0x0f, 0x2b, 0xbc, 0x80, 0xc2, 0x29, 0x50, 0xbe, 0xa9, 0xeb, 0x75, 0x5c, + 0x5f, 0xb2, 0x03, 0x9c, 0x6f, 0xe2, 0x45, 0x58, 0xd6, 0xa1, 0x55, 0x18, 0xf1, 0x29, 0x3e, 0x71, + 0x9b, 0x1c, 0x73, 0x35, 0x18, 0x47, 0xc3, 0xc6, 0x8b, 0x39, 0x18, 0xf4, 0x96, 0xaa, 0xd2, 0x18, + 0x29, 0xae, 0x66, 0xa1, 0x33, 0x31, 0xe5, 0x8a, 0x64, 0x78, 0xa3, 0x64, 0xa9, 0x35, 0xf4, 0x65, + 0x98, 0x11, 0x16, 0x1b, 0x7c, 0xdb, 0x38, 0x4d, 0x82, 0x3e, 0x18, 0xdb, 0x19, 0x8f, 0x25, 0x5e, + 0x91, 0x2f, 0x26, 0xdb, 0x47, 0x3b, 0x46, 0xf7, 0xa1, 0x7c, 0x5b, 0x0c, 0x12, 0xcd, 0x41, 0xc9, + 0x92, 0xdf, 0x02, 0x04, 0x8c, 0x52, 0xbd, 0x86, 0x4b, 0x96, 0x19, 0xf2, 0x43, 0xa5, 0x5c, 0xae, + 0x4d, 0xb9, 0x96, 0x86, 0xfa, 0x5f, 0x4b, 0xfa, 0x37, 0x4b, 0x70, 0x51, 0x62, 0x95, 0x73, 0xac, + 0x89, 0x37, 0xb8, 0x43, 0x78, 0xc3, 0xc3, 0x95, 0x22, 0xf7, 0x60, 0x98, 0x11, 0xc0, 0x42, 0x6f, + 0x73, 0x21, 0x40, 0x3a, 0x1c, 0xcc, 0x00, 0xa1, 0x1f, 0x85, 0x51, 0xdb, 0xd8, 0x24, 0xb6, 0xb4, + 0x94, 0x2b, 0xa4, 0x42, 0xca, 0x9a, 0x2e, 0xd7, 0x6c, 0xfa, 0xdc, 0x1b, 0x20, 0x7c, 0xb2, 0xe1, + 0x85, 0x58, 0xe0, 0x9c, 0x7b, 0x16, 0x26, 0x94, 0x66, 0x68, 0x06, 0x86, 0x76, 0x08, 0x7f, 0x9b, + 0x1d, 0xc7, 0xf4, 0x5f, 0x74, 0x11, 0x46, 0x76, 0x0d, 0xbb, 0x2b, 0x96, 0x04, 0xf3, 0x1f, 0x37, + 0x4b, 0x1f, 0xd4, 0xf4, 0xdf, 0xd0, 0x60, 0xe2, 0x8e, 0xb5, 0x49, 0x3c, 0x6e, 0x76, 0xc1, 0x44, + 0xa1, 0x98, 0xe3, 0xf3, 0x44, 0x96, 0xd3, 0x33, 0xda, 0x83, 0x71, 0x71, 0xd3, 0x84, 0x56, 0xb9, + 0xb7, 0x8b, 0x3d, 0x02, 0x87, 0xa8, 0x05, 0x05, 0x57, 0x1d, 0xad, 0x24, 0x06, 0x1c, 0x21, 0xd3, + 0xdf, 0x82, 0x0b, 0x19, 0x9d, 0x50, 0x85, 0x1d, 0x5f, 0x2f, 0x10, 0xdb, 0x42, 0x9e, 0x47, 0x2f, + 0xc0, 0xbc, 0x1c, 0x5d, 0x81, 0x21, 0xe2, 0x98, 0x62, 0x4f, 0x8c, 0x1d, 0xec, 0x57, 0x86, 0x96, + 0x1c, 0x13, 0xd3, 0x32, 0x4a, 0xa6, 0x6c, 0x37, 0xc6, 0x93, 0x30, 0x32, 0xb5, 0x2c, 0xca, 0x70, + 0x58, 0xcb, 0x9e, 0xed, 0x93, 0x2f, 0xd4, 0x94, 0x3b, 0x9d, 0xd9, 0x4a, 0x9c, 0x9e, 0x41, 0x1e, + 0xc6, 0x93, 0x27, 0x71, 0x71, 0x56, 0x2c, 0x48, 0xea, 0x4c, 0xe3, 0x14, 0x5e, 0xfd, 0x77, 0x87, + 0xe1, 0x91, 0x3b, 0xae, 0x67, 0xbd, 0xe9, 0x3a, 0x81, 0x61, 0xaf, 0xb9, 0x66, 0x64, 0x60, 0x27, + 0x88, 0xf2, 0xc7, 0x35, 0x78, 0xa8, 0xd9, 0xe9, 0x72, 0xee, 0x56, 0xda, 0x3d, 0xad, 0x11, 0xcf, + 0x72, 0x8b, 0xda, 0xd9, 0x31, 0xd7, 0xda, 0xea, 0xda, 0x46, 0x16, 0x48, 0x9c, 0x87, 0x8b, 0x99, + 0xfb, 0x99, 0xee, 0x7d, 0x87, 0x0d, 0xae, 0x11, 0xb0, 0xd5, 0x7c, 0x33, 0xfa, 0x08, 0x05, 0xcd, + 0xfd, 0x6a, 0x99, 0x10, 0x71, 0x0e, 0x26, 0xf4, 0xe3, 0x70, 0xc9, 0xe2, 0x83, 0xc3, 0xc4, 0x30, + 0x2d, 0x87, 0xf8, 0x3e, 0xb7, 0x15, 0x1a, 0xc0, 0x9e, 0xad, 0x9e, 0x05, 0x10, 0x67, 0xe3, 0x41, + 0xaf, 0x01, 0xf8, 0x3d, 0xa7, 0x29, 0xd6, 0x7f, 0xa4, 0x10, 0x56, 0xce, 0x04, 0x86, 0x50, 0xb0, + 0x02, 0x91, 0x4a, 0xb8, 0x41, 0xb8, 0x29, 0x47, 0x99, 0x6d, 0x1c, 0x93, 0x70, 0xa3, 0x3d, 0x14, + 0xd5, 0xeb, 0xff, 0x4c, 0x83, 0x31, 0xe1, 0xbe, 0x8f, 0xde, 0x9b, 0xd0, 0xf2, 0x84, 0xb4, 0x27, + 0xa1, 0xe9, 0xe9, 0xb1, 0xa7, 0x3e, 0xa1, 0xe1, 0x13, 0xac, 0x44, 0x21, 0x35, 0x81, 0x40, 0x1c, + 0xa9, 0x0b, 0x63, 0x4f, 0x7e, 0x52, 0x85, 0xa8, 0x20, 0xd3, 0x3f, 0xa7, 0xc1, 0xf9, 0x54, 0xaf, + 0x23, 0xf0, 0x0b, 0x67, 0x68, 0x45, 0xf3, 0xd5, 0x61, 0x98, 0x66, 0xc6, 0x7e, 0x8e, 0x61, 0x73, + 0x05, 0xcc, 0x19, 0x08, 0x28, 0x4f, 0xc2, 0xb8, 0xd5, 0x6e, 0x77, 0x03, 0x4a, 0xaa, 0x85, 0x0e, + 0x9d, 0x7d, 0xf3, 0xba, 0x2c, 0xc4, 0x51, 0x3d, 0x72, 0xc4, 0x55, 0xc8, 0x89, 0xf8, 0x72, 0xb1, + 0x2f, 0xa7, 0x4e, 0x70, 0x9e, 0x5e, 0x5b, 0xfc, 0xbe, 0xca, 0xba, 0x29, 0x7f, 0x5a, 0x03, 0xf0, + 0x03, 0xcf, 0x72, 0x5a, 0xb4, 0x50, 0x5c, 0x97, 0xf8, 0x04, 0xd0, 0x36, 0x42, 0xa0, 0x1c, 0x79, + 0xb8, 0x46, 0x51, 0x05, 0x56, 0x30, 0xa3, 0x05, 0xc1, 0x25, 0x70, 0x8a, 0xff, 0xdd, 0x09, 0x7e, + 0xe8, 0x91, 0x74, 0x74, 0x1a, 0xe1, 0xd2, 0x19, 0xb1, 0x11, 0x73, 0xcf, 0xc0, 0x78, 0x88, 0xef, + 0xb0, 0x5b, 0x77, 0x52, 0xb9, 0x75, 0xe7, 0x9e, 0x83, 0x73, 0x89, 0xe1, 0x1e, 0xeb, 0xd2, 0xfe, + 0x0f, 0x1a, 0xa0, 0xf8, 0xec, 0xcf, 0x40, 0xb4, 0x6b, 0xc5, 0x45, 0xbb, 0xc5, 0xc1, 0x3f, 0x59, + 0x8e, 0x6c, 0xf7, 0xe5, 0x29, 0x60, 0xd1, 0x4d, 0xc2, 0xe8, 0x31, 0xe2, 0xe2, 0xa2, 0xf7, 0x6c, + 0xe4, 0x21, 0x21, 0x4e, 0xee, 0x00, 0xf7, 0xec, 0xdd, 0x04, 0xac, 0xe8, 0x9e, 0x4d, 0xd6, 0xe0, + 0x14, 0x5e, 0xf4, 0x09, 0x0d, 0x66, 0x8c, 0x78, 0x74, 0x13, 0xb9, 0x32, 0x85, 0xbc, 0x67, 0x13, + 0x91, 0x52, 0xa2, 0xb1, 0x24, 0x2a, 0x7c, 0x9c, 0x42, 0x8b, 0xde, 0x0f, 0x93, 0x46, 0xc7, 0x5a, + 0xe8, 0x9a, 0x16, 0x15, 0x0d, 0x64, 0x68, 0x0a, 0x26, 0xae, 0x2e, 0xac, 0xd5, 0xc3, 0x72, 0x1c, + 0x6b, 0x15, 0x86, 0x11, 0x11, 0x0b, 0x39, 0x3c, 0x60, 0x18, 0x11, 0xb1, 0x86, 0x51, 0x18, 0x11, + 0xb1, 0x74, 0x2a, 0x12, 0xe4, 0x00, 0xb8, 0x96, 0xd9, 0x14, 0x28, 0xf9, 0xab, 0x5d, 0x21, 0x09, + 0xf9, 0x5e, 0xbd, 0x56, 0x15, 0x18, 0xd9, 0xed, 0x17, 0xfd, 0xc6, 0x0a, 0x06, 0xf4, 0x29, 0x0d, + 0xa6, 0x04, 0xed, 0x16, 0x38, 0xc7, 0xd8, 0x27, 0x7a, 0xb5, 0xe8, 0x7e, 0x49, 0xec, 0xc9, 0x79, + 0xac, 0x02, 0xe7, 0x74, 0x27, 0x74, 0xb0, 0x89, 0xd5, 0xe1, 0xf8, 0x38, 0xd0, 0xdf, 0xd5, 0xe0, + 0xa2, 0x4f, 0xbc, 0x5d, 0xab, 0x49, 0x16, 0x9a, 0x4d, 0xb7, 0xeb, 0xc8, 0xef, 0x50, 0x2e, 0x1e, + 0x75, 0xa1, 0x91, 0x01, 0x8f, 0x5b, 0x76, 0x67, 0xd5, 0xe0, 0x4c, 0xfc, 0x94, 0x2d, 0x3b, 0x77, + 0xdf, 0x08, 0x9a, 0xdb, 0x55, 0xa3, 0xb9, 0xcd, 0x74, 0xe5, 0xdc, 0x98, 0xbb, 0xe0, 0xbe, 0x7e, + 0x39, 0x0e, 0x8a, 0xbf, 0x3a, 0x27, 0x0a, 0x71, 0x12, 0x21, 0x72, 0xa1, 0xec, 0x89, 0x90, 0x51, + 0xb3, 0x50, 0x9c, 0xa5, 0x48, 0xc5, 0x9f, 0xe2, 0x8c, 0xbd, 0xfc, 0x85, 0x43, 0x24, 0xa8, 0x05, + 0x8f, 0x70, 0xd1, 0x66, 0xc1, 0x71, 0x9d, 0x5e, 0xdb, 0xed, 0xfa, 0x0b, 0xdd, 0x60, 0x9b, 0x38, + 0x81, 0xd4, 0x55, 0x4e, 0xb0, 0x6b, 0x94, 0xd9, 0xb3, 0x2f, 0xf5, 0x6b, 0x88, 0xfb, 0xc3, 0x41, + 0xaf, 0x40, 0x99, 0xec, 0x12, 0x27, 0x58, 0x5f, 0x5f, 0x66, 0x76, 0xe1, 0xc7, 0xe7, 0xf6, 0xd8, + 0x14, 0x96, 0x04, 0x0c, 0x1c, 0x42, 0x43, 0x3b, 0x30, 0x66, 0xf3, 0x98, 0x5f, 0xb3, 0x53, 0xc5, + 0x89, 0x62, 0x32, 0x7e, 0x18, 0x97, 0xff, 0xc4, 0x0f, 0x2c, 0x31, 0xa0, 0x0e, 0x5c, 0x37, 0xc9, + 0x96, 0xd1, 0xb5, 0x83, 0x55, 0x37, 0xa0, 0x2c, 0x6d, 0x2f, 0xd2, 0x4f, 0x49, 0x17, 0x80, 0x69, + 0xe6, 0x20, 0xfd, 0xd8, 0xc1, 0x7e, 0xe5, 0x7a, 0xed, 0x90, 0xb6, 0xf8, 0x50, 0x68, 0xa8, 0x07, + 0x8f, 0x8a, 0x36, 0x1b, 0x8e, 0x47, 0x8c, 0xe6, 0x36, 0x5d, 0xe5, 0x34, 0xd2, 0x73, 0x0c, 0xe9, + 0xff, 0x77, 0xb0, 0x5f, 0x79, 0xb4, 0x76, 0x78, 0x73, 0x7c, 0x14, 0x98, 0x73, 0x1f, 0x06, 0x94, + 0x3e, 0xe7, 0x87, 0x5d, 0xd8, 0x65, 0xf5, 0xc2, 0xfe, 0xcc, 0x08, 0x5c, 0xa5, 0xe4, 0x23, 0x62, + 0x53, 0x57, 0x0c, 0xc7, 0x68, 0x7d, 0x67, 0x5e, 0x6d, 0xbf, 0xa1, 0xc1, 0x43, 0xdb, 0xd9, 0x22, + 0xa4, 0x60, 0x94, 0x5f, 0x2c, 0x24, 0xea, 0xf7, 0x93, 0x4a, 0xf9, 0xc9, 0xea, 0xdb, 0x04, 0xe7, + 0x0d, 0x0a, 0x7d, 0x18, 0x66, 0x1c, 0xd7, 0x24, 0xd5, 0x7a, 0x0d, 0xaf, 0x18, 0xfe, 0x4e, 0x43, + 0xbe, 0xfc, 0x8d, 0x70, 0x9b, 0x93, 0xd5, 0x44, 0x1d, 0x4e, 0xb5, 0x46, 0xbb, 0x80, 0x3a, 0xae, + 0xb9, 0xb4, 0x6b, 0x35, 0xe5, 0x9b, 0x53, 0x71, 0x3b, 0x17, 0xf6, 0xb0, 0xb5, 0x96, 0x82, 0x86, + 0x33, 0x30, 0x30, 0x19, 0x98, 0x0e, 0x66, 0xc5, 0x75, 0xac, 0xc0, 0xf5, 0x98, 0x1f, 0xcc, 0x40, + 0xa2, 0x20, 0x93, 0x81, 0x57, 0x33, 0x21, 0xe2, 0x1c, 0x4c, 0xfa, 0xff, 0xd0, 0xe0, 0x1c, 0xdd, + 0x16, 0x6b, 0x9e, 0xbb, 0xd7, 0xfb, 0x4e, 0xdc, 0x90, 0x4f, 0x08, 0x23, 0x08, 0xae, 0xbb, 0xb9, + 0xa4, 0x18, 0x40, 0x8c, 0xb3, 0x31, 0x47, 0x36, 0x0f, 0xaa, 0xfa, 0x6a, 0x28, 0x5f, 0x7d, 0xa5, + 0x7f, 0xaa, 0xc4, 0x59, 0x4c, 0xa9, 0x3e, 0xfa, 0x8e, 0x3c, 0x87, 0xcf, 0xc0, 0x14, 0x2d, 0x5b, + 0x31, 0xf6, 0xd6, 0x6a, 0x2f, 0xb9, 0xb6, 0x74, 0xe5, 0x61, 0xe6, 0xb9, 0x77, 0xd5, 0x0a, 0x1c, + 0x6f, 0x87, 0x6e, 0xc2, 0x58, 0x87, 0x3b, 0x3c, 0x0b, 0xe1, 0xe6, 0x3a, 0xb7, 0x14, 0x60, 0x45, + 0x0f, 0xf6, 0x2b, 0xe7, 0xa3, 0xc7, 0x12, 0x51, 0x88, 0x65, 0x07, 0xfd, 0x93, 0x97, 0x80, 0x01, + 0xb7, 0x49, 0xf0, 0x9d, 0xb8, 0x26, 0x4f, 0xc1, 0x44, 0xb3, 0xd3, 0xad, 0xde, 0x6a, 0xbc, 0xd8, + 0x75, 0x99, 0xd0, 0xca, 0x62, 0x33, 0x52, 0x9e, 0xb3, 0xba, 0xb6, 0x21, 0x8b, 0xb1, 0xda, 0x86, + 0x52, 0x87, 0x66, 0xa7, 0x2b, 0xe8, 0xed, 0x9a, 0x6a, 0xa3, 0xca, 0xa8, 0x43, 0x75, 0x6d, 0x23, + 0x56, 0x87, 0x53, 0xad, 0xd1, 0x8f, 0xc3, 0x24, 0x11, 0x07, 0xf7, 0x8e, 0xe1, 0x99, 0x82, 0x2e, + 0xd4, 0x8b, 0x4e, 0x3e, 0x5c, 0x5a, 0x49, 0x0d, 0x38, 0xab, 0xbe, 0xa4, 0xa0, 0xc0, 0x31, 0x84, + 0xe8, 0x07, 0xe1, 0x8a, 0xfc, 0x4d, 0xbf, 0xb2, 0x6b, 0x26, 0x09, 0xc5, 0x08, 0xf7, 0x31, 0x5d, + 0xca, 0x6b, 0x84, 0xf3, 0xfb, 0xa3, 0x5f, 0xd7, 0xe0, 0x72, 0x58, 0x6b, 0x39, 0x56, 0xbb, 0xdb, + 0xc6, 0xa4, 0x69, 0x1b, 0x56, 0x5b, 0x30, 0xe8, 0x2f, 0x9f, 0xd8, 0x44, 0xe3, 0xe0, 0x39, 0xb1, + 0xca, 0xae, 0xc3, 0x39, 0x43, 0x42, 0x9f, 0xd3, 0xe0, 0xba, 0xac, 0x5a, 0xf3, 0x88, 0xef, 0x77, + 0x3d, 0x12, 0x39, 0x92, 0x89, 0x25, 0x19, 0x2b, 0x44, 0x3b, 0x19, 0xa7, 0xb2, 0x74, 0x08, 0x6c, + 0x7c, 0x28, 0x76, 0x75, 0xbb, 0x34, 0xdc, 0xad, 0x40, 0x70, 0xf4, 0xa7, 0xb5, 0x5d, 0x28, 0x0a, + 0x1c, 0x43, 0x88, 0xfe, 0xb9, 0x06, 0x0f, 0xa9, 0x05, 0xea, 0x6e, 0xe1, 0xac, 0xfc, 0x2b, 0x27, + 0x36, 0x98, 0x04, 0x7c, 0xae, 0x0b, 0xce, 0xa9, 0xc4, 0x79, 0xa3, 0xa2, 0x64, 0xbb, 0xcd, 0x36, + 0x26, 0x67, 0xf7, 0x47, 0x38, 0xd9, 0xe6, 0x7b, 0xd5, 0xc7, 0xb2, 0x8e, 0x0a, 0xba, 0x1d, 0xd7, + 0x5c, 0xb3, 0x4c, 0x7f, 0xd9, 0x6a, 0x5b, 0x01, 0x63, 0xca, 0x87, 0xf8, 0x72, 0xac, 0xb9, 0xe6, + 0x5a, 0xbd, 0xc6, 0xcb, 0x71, 0xac, 0x15, 0x73, 0xe9, 0xb6, 0xda, 0x46, 0x8b, 0xac, 0x75, 0x6d, + 0x7b, 0xcd, 0x73, 0x99, 0xc2, 0xb0, 0x46, 0x0c, 0xd3, 0xb6, 0x1c, 0x52, 0x90, 0x09, 0x67, 0xc7, + 0xad, 0x9e, 0x07, 0x14, 0xe7, 0xe3, 0x43, 0xf3, 0x00, 0x5b, 0x86, 0x65, 0x37, 0xee, 0x1b, 0x9d, + 0x7b, 0x0e, 0xe3, 0xd4, 0xcb, 0x5c, 0x84, 0xbd, 0x15, 0x96, 0x62, 0xa5, 0x05, 0xdd, 0x4d, 0x94, + 0x0a, 0x62, 0xc2, 0x43, 0x09, 0x31, 0xae, 0xfa, 0x24, 0x76, 0x93, 0x04, 0xc8, 0x97, 0xef, 0xae, + 0x82, 0x02, 0xc7, 0x10, 0xa2, 0x8f, 0x6b, 0x30, 0xed, 0xf7, 0xfc, 0x80, 0xb4, 0xc3, 0x31, 0x9c, + 0x3b, 0xe9, 0x31, 0x30, 0x55, 0x6a, 0x23, 0x86, 0x04, 0x27, 0x90, 0x22, 0x03, 0xae, 0xb2, 0x55, + 0xbd, 0x5d, 0xbd, 0x63, 0xb5, 0xb6, 0x43, 0x47, 0xed, 0x35, 0xe2, 0x35, 0x89, 0x13, 0xcc, 0xce, + 0xb0, 0x7d, 0xc3, 0x4c, 0x69, 0xea, 0xf9, 0xcd, 0x70, 0x3f, 0x18, 0xe8, 0x35, 0x98, 0x13, 0xd5, + 0xcb, 0xee, 0xfd, 0x14, 0x86, 0xf3, 0x0c, 0x03, 0x33, 0x1d, 0xaa, 0xe7, 0xb6, 0xc2, 0x7d, 0x20, + 0xa0, 0x3a, 0x5c, 0xf0, 0x89, 0xc7, 0x5e, 0x42, 0x48, 0xb8, 0x79, 0xfc, 0x59, 0x14, 0x59, 0x0d, + 0x37, 0xd2, 0xd5, 0x38, 0xab, 0x0f, 0x7a, 0x2e, 0x74, 0x4c, 0xea, 0xd1, 0x82, 0x17, 0xd7, 0x1a, + 0xb3, 0x17, 0xd8, 0xf8, 0x2e, 0x28, 0xfe, 0x46, 0xb2, 0x0a, 0x27, 0xdb, 0x52, 0xde, 0x42, 0x16, + 0x2d, 0x76, 0x3d, 0x3f, 0x98, 0xbd, 0xc8, 0x3a, 0x33, 0xde, 0x02, 0xab, 0x15, 0x38, 0xde, 0x0e, + 0xdd, 0x84, 0x69, 0x9f, 0x34, 0x9b, 0x6e, 0xbb, 0x23, 0xc4, 0xab, 0xd9, 0x4b, 0x6c, 0xf4, 0xfc, + 0x0b, 0xc6, 0x6a, 0x70, 0xa2, 0x25, 0xea, 0xc1, 0x85, 0x30, 0xb0, 0xce, 0xb2, 0xdb, 0x5a, 0x31, + 0xf6, 0x18, 0xab, 0x7e, 0xf9, 0xf0, 0x13, 0x38, 0x2f, 0x9f, 0xb6, 0xe7, 0x5f, 0xec, 0x1a, 0x4e, + 0x60, 0x05, 0x3d, 0xbe, 0x5c, 0xd5, 0x34, 0x38, 0x9c, 0x85, 0x03, 0x2d, 0xc3, 0xc5, 0x44, 0xf1, + 0x2d, 0xcb, 0x26, 0xfe, 0xec, 0x43, 0x6c, 0xda, 0x4c, 0x47, 0x52, 0xcd, 0xa8, 0xc7, 0x99, 0xbd, + 0xd0, 0x3d, 0xb8, 0xd4, 0xf1, 0xdc, 0x80, 0x34, 0x83, 0xbb, 0x94, 0x3d, 0xb1, 0xc5, 0x04, 0xfd, + 0xd9, 0x59, 0xb6, 0x16, 0xec, 0x15, 0x68, 0x2d, 0xab, 0x01, 0xce, 0xee, 0x87, 0x3e, 0xa3, 0xc1, + 0x35, 0x3f, 0xf0, 0x88, 0xd1, 0xb6, 0x9c, 0x56, 0xd5, 0x75, 0x1c, 0xc2, 0xc8, 0x64, 0xdd, 0x8c, + 0x8c, 0xee, 0xaf, 0x14, 0xa2, 0x53, 0xfa, 0xc1, 0x7e, 0xe5, 0x5a, 0xa3, 0x2f, 0x64, 0x7c, 0x08, + 0x66, 0xf4, 0x16, 0x40, 0x9b, 0xb4, 0x5d, 0xaf, 0x47, 0x29, 0xd2, 0xec, 0x5c, 0x71, 0x23, 0xa6, + 0x95, 0x10, 0x0a, 0x3f, 0xfe, 0xb1, 0xf7, 0xab, 0xa8, 0x12, 0x2b, 0xe8, 0xf4, 0xfd, 0x12, 0x5c, + 0xca, 0xbc, 0x78, 0xe8, 0x09, 0xe0, 0xed, 0x16, 0x64, 0x90, 0x5d, 0xf1, 0xe4, 0xc3, 0x4e, 0xc0, + 0x4a, 0xbc, 0x0a, 0x27, 0xdb, 0x52, 0xb6, 0x90, 0x9d, 0xd4, 0x5b, 0x8d, 0xa8, 0x7f, 0x29, 0x62, + 0x0b, 0xeb, 0x89, 0x3a, 0x9c, 0x6a, 0x8d, 0xaa, 0x70, 0x5e, 0x94, 0xd5, 0xa9, 0x64, 0xe5, 0xdf, + 0xf2, 0x88, 0x64, 0xb8, 0xa9, 0x8c, 0x72, 0xbe, 0x9e, 0xac, 0xc4, 0xe9, 0xf6, 0x74, 0x16, 0xf4, + 0x87, 0x3a, 0x8a, 0xe1, 0x68, 0x16, 0xab, 0xf1, 0x2a, 0x9c, 0x6c, 0x2b, 0x45, 0xdf, 0xd8, 0x10, + 0x46, 0xa2, 0x59, 0xac, 0x26, 0xea, 0x70, 0xaa, 0xb5, 0xfe, 0x1f, 0x87, 0xe1, 0xd1, 0x23, 0x30, + 0x6b, 0xa8, 0x9d, 0xbd, 0xdc, 0xc7, 0x3f, 0xb8, 0x47, 0xfb, 0x3c, 0x9d, 0x9c, 0xcf, 0x73, 0x7c, + 0x7c, 0x47, 0xfd, 0x9c, 0x7e, 0xde, 0xe7, 0x3c, 0x3e, 0xca, 0xa3, 0x7f, 0xfe, 0x76, 0xf6, 0xe7, + 0x2f, 0xb8, 0xaa, 0x87, 0x6e, 0x97, 0x4e, 0xce, 0x76, 0x29, 0xb8, 0xaa, 0x47, 0xd8, 0x5e, 0x7f, + 0x32, 0x0c, 0x8f, 0x1d, 0x85, 0x71, 0x2c, 0xb8, 0xbf, 0x32, 0x48, 0xde, 0xa9, 0xee, 0xaf, 0x3c, + 0xbf, 0xa6, 0x53, 0xdc, 0x5f, 0x19, 0x28, 0x4f, 0x7b, 0x7f, 0xe5, 0xad, 0xea, 0x69, 0xed, 0xaf, + 0xbc, 0x55, 0x3d, 0xc2, 0xfe, 0xfa, 0x8b, 0xe4, 0xfd, 0x10, 0xf2, 0x8b, 0x75, 0x18, 0x6a, 0x76, + 0xba, 0x05, 0x89, 0x14, 0x33, 0x10, 0xaa, 0xae, 0x6d, 0x60, 0x0a, 0x03, 0x61, 0x18, 0xe5, 0xfb, + 0xa7, 0x20, 0x09, 0x62, 0x1e, 0x32, 0x7c, 0x4b, 0x62, 0x01, 0x89, 0x2e, 0x15, 0xe9, 0x6c, 0x93, + 0x36, 0xf1, 0x0c, 0xbb, 0x11, 0xb8, 0x9e, 0xd1, 0x2a, 0x4a, 0x6d, 0xd8, 0x52, 0x2d, 0x25, 0x60, + 0xe1, 0x14, 0x74, 0xba, 0x20, 0x1d, 0xcb, 0x2c, 0x48, 0x5f, 0xd8, 0x82, 0xac, 0xd5, 0x6b, 0x98, + 0xc2, 0xd0, 0xff, 0xe1, 0x38, 0x28, 0x81, 0xeb, 0xd0, 0x0f, 0xc2, 0x15, 0xc3, 0xb6, 0xdd, 0xfb, + 0x6b, 0x9e, 0xb5, 0x6b, 0xd9, 0xa4, 0x45, 0xcc, 0x90, 0x99, 0xf2, 0x85, 0x19, 0x19, 0x13, 0x98, + 0x16, 0xf2, 0x1a, 0xe1, 0xfc, 0xfe, 0xe8, 0x6d, 0x0d, 0xce, 0x37, 0x93, 0xc1, 0xc2, 0x06, 0x31, + 0x34, 0x49, 0x45, 0x1e, 0xe3, 0xe7, 0x29, 0x55, 0x8c, 0xd3, 0x68, 0xd1, 0x4f, 0x68, 0x5c, 0x29, + 0x17, 0x3e, 0x93, 0x88, 0x6f, 0x76, 0xfb, 0x84, 0x1e, 0x14, 0x23, 0xed, 0x5e, 0xf4, 0x76, 0x15, + 0x47, 0x88, 0x3e, 0xa7, 0xc1, 0xa5, 0x9d, 0xac, 0xb7, 0x04, 0xf1, 0x65, 0xef, 0x15, 0x1d, 0x4a, + 0xce, 0xe3, 0x04, 0x67, 0x67, 0x33, 0x1b, 0xe0, 0xec, 0x81, 0x84, 0xab, 0x14, 0xaa, 0x57, 0x05, + 0x11, 0x28, 0xbc, 0x4a, 0x09, 0x3d, 0x6d, 0xb4, 0x4a, 0x61, 0x05, 0x8e, 0x23, 0x44, 0x1d, 0x18, + 0xdf, 0x91, 0x3a, 0x6d, 0xa1, 0xc7, 0xaa, 0x16, 0xc5, 0xae, 0x28, 0xc6, 0xb9, 0x21, 0x4d, 0x58, + 0x88, 0x23, 0x24, 0x68, 0x1b, 0xc6, 0x76, 0x38, 0x21, 0x12, 0xfa, 0xa7, 0x85, 0x81, 0xe5, 0x63, + 0xae, 0x06, 0x11, 0x45, 0x58, 0x82, 0x57, 0xad, 0x68, 0xcb, 0x87, 0x38, 0x77, 0x7c, 0x46, 0x83, + 0x4b, 0xbb, 0xc4, 0x0b, 0xac, 0x66, 0xf2, 0x25, 0x67, 0xbc, 0xb8, 0x0c, 0xff, 0x52, 0x16, 0x40, + 0xbe, 0x4d, 0x32, 0xab, 0x70, 0xf6, 0x10, 0xa8, 0x44, 0xcf, 0x15, 0xf2, 0x8d, 0xc0, 0x08, 0xac, + 0xe6, 0xba, 0xbb, 0x43, 0x9c, 0x28, 0xbf, 0x0a, 0xd3, 0x04, 0x95, 0xb9, 0x44, 0xbf, 0x94, 0xdf, + 0x0c, 0xf7, 0x83, 0xa1, 0x7f, 0x4b, 0x83, 0x94, 0x5a, 0x19, 0xfd, 0xbc, 0x06, 0x93, 0x5b, 0xc4, + 0x08, 0xba, 0x1e, 0xb9, 0x6d, 0x04, 0xa1, 0xc7, 0xf9, 0x4b, 0x27, 0xa1, 0xcd, 0x9e, 0xbf, 0xa5, + 0x00, 0xe6, 0x06, 0x01, 0x61, 0xd0, 0x4b, 0xb5, 0x0a, 0xc7, 0x46, 0x30, 0xf7, 0x02, 0x9c, 0x4f, + 0x75, 0x3c, 0xd6, 0x0b, 0xe3, 0xbf, 0xd2, 0x20, 0x2b, 0x25, 0x10, 0x7a, 0x0d, 0x46, 0x0c, 0xd3, + 0x0c, 0x63, 0xfc, 0x3f, 0x5b, 0xcc, 0x36, 0xc5, 0x54, 0x1d, 0xfb, 0xd9, 0x4f, 0xcc, 0xc1, 0xa2, + 0x5b, 0x80, 0x8c, 0xd8, 0x0b, 0xf7, 0x4a, 0xe4, 0xae, 0xca, 0x5e, 0xc2, 0x16, 0x52, 0xb5, 0x38, + 0xa3, 0x87, 0xfe, 0x33, 0x1a, 0xa0, 0x74, 0x98, 0x54, 0xe4, 0x41, 0x59, 0x6c, 0x65, 0xf9, 0x95, + 0x6a, 0x05, 0x5d, 0x4a, 0x62, 0xfe, 0x51, 0x91, 0xa1, 0x93, 0x28, 0xf0, 0x71, 0x88, 0x47, 0xff, + 0x4b, 0x0d, 0xa2, 0x38, 0xe0, 0xe8, 0x03, 0x30, 0x61, 0x12, 0xbf, 0xe9, 0x59, 0x9d, 0x20, 0xf2, + 0xa6, 0x0a, 0xbd, 0x32, 0x6a, 0x51, 0x15, 0x56, 0xdb, 0x21, 0x1d, 0x46, 0x03, 0xc3, 0xdf, 0xa9, + 0xd7, 0x84, 0x50, 0xc9, 0x58, 0x80, 0x75, 0x56, 0x82, 0x45, 0x4d, 0x14, 0x32, 0x6c, 0xe8, 0x08, + 0x21, 0xc3, 0xd0, 0xd6, 0x09, 0xc4, 0x47, 0x43, 0x87, 0xc7, 0x46, 0xd3, 0x7f, 0xad, 0x04, 0xe7, + 0x68, 0x93, 0x15, 0xc3, 0x72, 0x02, 0xe2, 0x30, 0xdf, 0x81, 0x82, 0x8b, 0xd0, 0x82, 0xa9, 0x20, + 0xe6, 0x1b, 0x77, 0x7c, 0xcf, 0xb2, 0xd0, 0x9a, 0x26, 0xee, 0x11, 0x17, 0x87, 0x8b, 0x9e, 0x95, + 0xce, 0x1b, 0x5c, 0xfc, 0x7e, 0x54, 0x6e, 0x55, 0xe6, 0x91, 0xf1, 0x40, 0x38, 0x1a, 0x86, 0xc1, + 0xe3, 0x63, 0x7e, 0x1a, 0xcf, 0xc0, 0x94, 0x30, 0xa2, 0xe6, 0xb1, 0xdf, 0x84, 0xf8, 0xcd, 0x6e, + 0x98, 0x5b, 0x6a, 0x05, 0x8e, 0xb7, 0xd3, 0xbf, 0x52, 0x82, 0x78, 0x88, 0xfa, 0xa2, 0xab, 0x94, + 0x0e, 0x7c, 0x57, 0x3a, 0xb5, 0xc0, 0x77, 0xef, 0x63, 0xf9, 0x5d, 0x78, 0x22, 0x30, 0xfe, 0x44, + 0xae, 0x66, 0x65, 0xe1, 0x69, 0xbc, 0xc2, 0x16, 0xd1, 0xb2, 0x0e, 0x1f, 0x7b, 0x59, 0x3f, 0x20, + 0xac, 0x2b, 0x47, 0x62, 0xe1, 0x07, 0xa5, 0x75, 0xe5, 0xf9, 0x58, 0x47, 0xc5, 0xd5, 0xe4, 0x8b, + 0x1a, 0x8c, 0x89, 0xd8, 0xc0, 0x47, 0x70, 0x65, 0xda, 0x82, 0x11, 0x26, 0xf2, 0x0c, 0xc2, 0x0d, + 0x36, 0xb6, 0x5d, 0x37, 0x88, 0x45, 0x48, 0x66, 0xbe, 0x03, 0xec, 0x5f, 0xcc, 0xc1, 0x33, 0x03, + 0x3b, 0xaf, 0xb9, 0x6d, 0x05, 0xa4, 0x19, 0xc8, 0xb8, 0xab, 0xd2, 0xc0, 0x4e, 0x29, 0xc7, 0xb1, + 0x56, 0xfa, 0x67, 0x87, 0xe1, 0xba, 0x00, 0x9c, 0x62, 0x91, 0x42, 0x02, 0xd7, 0x83, 0x0b, 0xe2, + 0xdb, 0xd6, 0x3c, 0xc3, 0x0a, 0x4d, 0x0f, 0x8a, 0x89, 0xbe, 0x22, 0xd9, 0x5d, 0x0a, 0x1c, 0xce, + 0xc2, 0xc1, 0x23, 0x88, 0xb2, 0xe2, 0x3b, 0xc4, 0xb0, 0x83, 0x6d, 0x89, 0xbb, 0x34, 0x48, 0x04, + 0xd1, 0x34, 0x3c, 0x9c, 0x89, 0x85, 0x99, 0x3e, 0x88, 0x8a, 0xaa, 0x47, 0x0c, 0xd5, 0xee, 0x62, + 0x00, 0xf3, 0xff, 0x95, 0x4c, 0x88, 0x38, 0x07, 0x13, 0xd3, 0x21, 0x1a, 0x7b, 0x4c, 0x25, 0x81, + 0x49, 0xe0, 0x59, 0x2c, 0xd2, 0x75, 0xa8, 0x45, 0x5f, 0x89, 0x57, 0xe1, 0x64, 0x5b, 0x74, 0x13, + 0xa6, 0x99, 0x29, 0x49, 0x14, 0xea, 0x6a, 0x24, 0x8a, 0xa6, 0xb0, 0x1a, 0xab, 0xc1, 0x89, 0x96, + 0xfa, 0x47, 0x4b, 0x30, 0xa9, 0x6e, 0xbb, 0x23, 0xf8, 0x35, 0x75, 0x95, 0xcb, 0x70, 0x00, 0x9f, + 0x1b, 0x15, 0xeb, 0x11, 0xee, 0x43, 0xf4, 0x0a, 0x4c, 0x77, 0x19, 0x05, 0x91, 0xe1, 0x3a, 0xc4, + 0xfe, 0xff, 0x1e, 0x3a, 0xcb, 0x8d, 0x58, 0xcd, 0x83, 0xfd, 0xca, 0x9c, 0x0a, 0x3e, 0x5e, 0x8b, + 0x13, 0x70, 0xf4, 0x4f, 0x0e, 0xc1, 0x85, 0x8c, 0xd1, 0x30, 0x93, 0x03, 0x92, 0xb8, 0xb2, 0x07, + 0x31, 0x39, 0x48, 0x5d, 0xff, 0xa1, 0xc9, 0x41, 0xb2, 0x06, 0xa7, 0xf0, 0xa2, 0x97, 0x60, 0xa8, + 0xe9, 0x59, 0x62, 0xc1, 0x9f, 0x29, 0x24, 0x70, 0xe2, 0xfa, 0xe2, 0x84, 0xc0, 0x38, 0x54, 0xc5, + 0x75, 0x4c, 0x01, 0xd2, 0x8b, 0x47, 0x25, 0x17, 0x92, 0x0b, 0x60, 0x17, 0x8f, 0x4a, 0x55, 0x7c, + 0x1c, 0x6f, 0x87, 0x5e, 0x81, 0x59, 0x21, 0x09, 0x48, 0x1f, 0x69, 0xd7, 0xf1, 0x03, 0x7a, 0xb2, + 0x03, 0x41, 0xa8, 0x1f, 0x3e, 0xd8, 0xaf, 0xcc, 0xde, 0xcd, 0x69, 0x83, 0x73, 0x7b, 0xeb, 0x7f, + 0x3e, 0x04, 0x13, 0x4a, 0x64, 0x76, 0xb4, 0x32, 0x88, 0x0a, 0x25, 0x9a, 0xb1, 0x54, 0xa3, 0xac, + 0xc0, 0x50, 0xab, 0xd3, 0x2d, 0xa8, 0x43, 0x09, 0xc1, 0xdd, 0xa6, 0xe0, 0x5a, 0x9d, 0x2e, 0x7a, + 0x29, 0xd4, 0xca, 0x14, 0xd3, 0x9b, 0x84, 0x1e, 0x2d, 0x09, 0xcd, 0x8c, 0x3c, 0x88, 0xc3, 0xb9, + 0x07, 0xb1, 0x0d, 0x63, 0xbe, 0x50, 0xd9, 0x8c, 0x14, 0x8f, 0x4a, 0xa3, 0xac, 0xb4, 0x50, 0xd1, + 0x70, 0x79, 0x4f, 0x6a, 0x70, 0x24, 0x0e, 0xca, 0x4b, 0x76, 0x99, 0x9f, 0x2c, 0x13, 0x64, 0xcb, + 0x9c, 0x97, 0xdc, 0x60, 0x25, 0x58, 0xd4, 0xa4, 0xae, 0xa8, 0xb1, 0x23, 0x5d, 0x51, 0x7f, 0xbb, + 0x04, 0x28, 0x3d, 0x0c, 0xf4, 0x28, 0x8c, 0x30, 0x3f, 0x7b, 0x41, 0x8b, 0x42, 0xce, 0x9f, 0x79, + 0x5a, 0x63, 0x5e, 0x87, 0x1a, 0x22, 0xc6, 0x46, 0xb1, 0xcf, 0xc9, 0x6c, 0x76, 0x04, 0x3e, 0x25, + 0x20, 0xc7, 0xf5, 0x98, 0x53, 0x46, 0xd6, 0x9d, 0xbf, 0x01, 0x63, 0x6d, 0xcb, 0x61, 0x0f, 0x87, + 0xc5, 0x34, 0x59, 0xdc, 0xb4, 0x80, 0x83, 0xc0, 0x12, 0x96, 0xfe, 0x27, 0x25, 0xba, 0xf5, 0x23, + 0x8e, 0xb7, 0x07, 0x60, 0x74, 0x03, 0x97, 0x13, 0x30, 0x71, 0x02, 0xea, 0xc5, 0xbe, 0x72, 0x08, + 0x74, 0x21, 0x04, 0xc8, 0x9f, 0xbc, 0xa2, 0xdf, 0x58, 0x41, 0x46, 0x51, 0x07, 0x56, 0x9b, 0xbc, + 0x6c, 0x39, 0xa6, 0x7b, 0x5f, 0x2c, 0xef, 0xa0, 0xa8, 0xd7, 0x43, 0x80, 0x1c, 0x75, 0xf4, 0x1b, + 0x2b, 0xc8, 0x28, 0x69, 0x61, 0x82, 0xb3, 0xc3, 0x52, 0x65, 0x88, 0xb1, 0xb9, 0xb6, 0x2d, 0x6f, + 0xe5, 0x32, 0x27, 0x2d, 0xd5, 0x9c, 0x36, 0x38, 0xb7, 0xb7, 0xfe, 0xeb, 0x1a, 0x5c, 0xca, 0x5c, + 0x0a, 0x74, 0x1b, 0xce, 0x47, 0x66, 0x5e, 0x2a, 0xb1, 0x2f, 0x47, 0x29, 0x5a, 0xee, 0x26, 0x1b, + 0xe0, 0x74, 0x1f, 0x9e, 0x07, 0x38, 0x75, 0x99, 0x08, 0x1b, 0x31, 0x95, 0x35, 0x52, 0xab, 0x71, + 0x56, 0x1f, 0xfd, 0x07, 0x63, 0x83, 0x8d, 0x16, 0x8b, 0x9e, 0x8c, 0x4d, 0xd2, 0x0a, 0x9d, 0xe2, + 0xc2, 0x93, 0xb1, 0x48, 0x0b, 0x31, 0xaf, 0x43, 0x8f, 0xa8, 0xae, 0xa6, 0x21, 0xdd, 0x92, 0xee, + 0xa6, 0xfa, 0x0f, 0xc3, 0x43, 0x39, 0x2f, 0xa1, 0xa8, 0x06, 0x93, 0xfe, 0x7d, 0xa3, 0xb3, 0x48, + 0xb6, 0x8d, 0x5d, 0x4b, 0x84, 0x2e, 0xe0, 0xe6, 0x7b, 0x93, 0x0d, 0xa5, 0xfc, 0x41, 0xe2, 0x37, + 0x8e, 0xf5, 0xd2, 0x03, 0x00, 0x61, 0xe6, 0x69, 0x39, 0x2d, 0xb4, 0x05, 0x65, 0x43, 0xa4, 0xa1, + 0x15, 0xfb, 0xf8, 0xfb, 0x0b, 0x29, 0x01, 0x04, 0x0c, 0x6e, 0x7f, 0x2e, 0x7f, 0xe1, 0x10, 0xb6, + 0xfe, 0x4f, 0x34, 0xb8, 0x9c, 0xed, 0xac, 0x7e, 0x04, 0xd6, 0xa6, 0x0d, 0x13, 0x5e, 0xd4, 0x4d, + 0x6c, 0xfa, 0xef, 0x53, 0xa3, 0x95, 0x2a, 0xe1, 0xb9, 0x28, 0xdb, 0x57, 0xf5, 0x5c, 0x5f, 0x7e, + 0xf9, 0x64, 0x00, 0xd3, 0x50, 0xe4, 0x52, 0x46, 0x82, 0x55, 0xf8, 0xfa, 0xef, 0x96, 0x00, 0x56, + 0x49, 0x70, 0xdf, 0xf5, 0x76, 0xe8, 0x12, 0x3d, 0x1c, 0x93, 0x34, 0xca, 0xdf, 0xbe, 0x80, 0x09, + 0x0f, 0xc3, 0x70, 0xc7, 0x35, 0x7d, 0x41, 0xfe, 0xd8, 0x40, 0x98, 0x05, 0x14, 0x2b, 0x45, 0x15, + 0x18, 0x61, 0x0f, 0x1f, 0xe2, 0x66, 0x62, 0x72, 0x0a, 0xe5, 0x32, 0x7d, 0xcc, 0xcb, 0x79, 0x72, + 0x31, 0xe6, 0xd3, 0xe1, 0x0b, 0xc1, 0x4b, 0x24, 0x17, 0xe3, 0x65, 0x38, 0xac, 0x45, 0x37, 0x01, + 0xac, 0xce, 0x2d, 0xa3, 0x6d, 0xd9, 0x94, 0xe7, 0x1d, 0x0d, 0x73, 0xd9, 0x42, 0x7d, 0x4d, 0x96, + 0x3e, 0xd8, 0xaf, 0x94, 0xc5, 0xaf, 0x1e, 0x56, 0x5a, 0xeb, 0x7f, 0x35, 0x04, 0xb1, 0xbc, 0xcf, + 0x91, 0x8e, 0x49, 0x3b, 0x1d, 0x1d, 0xd3, 0x2b, 0x30, 0x6b, 0xbb, 0x86, 0xb9, 0x68, 0xd8, 0xf4, + 0x34, 0x7a, 0x0d, 0xfe, 0x19, 0x0d, 0xa7, 0x15, 0x26, 0xf7, 0x65, 0x54, 0x69, 0x39, 0xa7, 0x0d, + 0xce, 0xed, 0x8d, 0x82, 0x30, 0xdb, 0xf4, 0x50, 0x71, 0xf7, 0x47, 0x75, 0x2d, 0xe6, 0x55, 0x4f, + 0xa0, 0x90, 0xc1, 0x48, 0x24, 0xa4, 0xfe, 0x98, 0x06, 0x97, 0xc8, 0x1e, 0xf7, 0x84, 0x5b, 0xf7, + 0x8c, 0xad, 0x2d, 0xab, 0x29, 0xec, 0x52, 0xf9, 0x87, 0x5d, 0x3e, 0xd8, 0xaf, 0x5c, 0x5a, 0xca, + 0x6a, 0xf0, 0x60, 0xbf, 0x72, 0x23, 0xd3, 0x31, 0x91, 0x7d, 0xd6, 0xcc, 0x2e, 0x38, 0x1b, 0xd5, + 0xdc, 0xb3, 0x30, 0x71, 0x0c, 0x6f, 0x86, 0x98, 0xfb, 0xe1, 0xef, 0x95, 0x60, 0x92, 0xee, 0xbb, + 0x65, 0xb7, 0x69, 0xd8, 0xb5, 0xd5, 0xc6, 0x31, 0xb2, 0xa5, 0xa3, 0x65, 0xb8, 0xb8, 0xe5, 0x7a, + 0x4d, 0xb2, 0x5e, 0x5d, 0x5b, 0x77, 0xc5, 0x93, 0x4b, 0x6d, 0xb5, 0x21, 0xa8, 0x34, 0x13, 0x22, + 0x6f, 0x65, 0xd4, 0xe3, 0xcc, 0x5e, 0xe8, 0x1e, 0x5c, 0x8a, 0xca, 0x37, 0x3a, 0xdc, 0x90, 0x85, + 0x82, 0x1b, 0x8a, 0x0c, 0x71, 0x6e, 0x65, 0x35, 0xc0, 0xd9, 0xfd, 0x90, 0x01, 0x57, 0x45, 0x4c, + 0x92, 0x5b, 0xae, 0x77, 0xdf, 0xf0, 0xcc, 0x38, 0xd8, 0xe1, 0x48, 0x25, 0x5d, 0xcb, 0x6f, 0x86, + 0xfb, 0xc1, 0xd0, 0x7f, 0x69, 0x14, 0x14, 0x77, 0xb5, 0x63, 0xa4, 0xa3, 0xfa, 0x55, 0x0d, 0x2e, + 0x36, 0x6d, 0x8b, 0x38, 0x41, 0xc2, 0x37, 0x89, 0x93, 0xa3, 0x8d, 0x42, 0x7e, 0x74, 0x1d, 0xe2, + 0xd4, 0x6b, 0xc2, 0xee, 0xa7, 0x9a, 0x01, 0x5c, 0xd8, 0x46, 0x65, 0xd4, 0xe0, 0xcc, 0xc1, 0xb0, + 0xf9, 0xb0, 0xf2, 0x7a, 0x4d, 0x0d, 0xa6, 0x50, 0x15, 0x65, 0x38, 0xac, 0x45, 0x4f, 0xc1, 0x44, + 0xcb, 0x73, 0xbb, 0x1d, 0xbf, 0xca, 0x8c, 0x8d, 0xf9, 0xde, 0x67, 0x7c, 0xe1, 0xed, 0xa8, 0x18, + 0xab, 0x6d, 0x28, 0x97, 0xcb, 0x7f, 0xae, 0x79, 0x64, 0xcb, 0xda, 0x13, 0x44, 0x8e, 0x71, 0xb9, + 0xb7, 0x95, 0x72, 0x1c, 0x6b, 0xc5, 0xfc, 0xa1, 0x7d, 0xbf, 0x4b, 0xbc, 0x0d, 0xbc, 0x2c, 0xf2, + 0x38, 0x70, 0x7f, 0x68, 0x59, 0x88, 0xa3, 0x7a, 0xf4, 0x0b, 0x1a, 0x4c, 0x7b, 0xe4, 0x8d, 0xae, + 0xe5, 0x11, 0x93, 0x21, 0xf5, 0x85, 0xcf, 0x20, 0x1e, 0xcc, 0x4f, 0x71, 0x1e, 0xc7, 0x80, 0x72, + 0x0a, 0x11, 0xaa, 0xed, 0xe2, 0x95, 0x38, 0x31, 0x02, 0xba, 0x54, 0xbe, 0xd5, 0x72, 0x2c, 0xa7, + 0xb5, 0x60, 0xb7, 0xfc, 0xd9, 0x32, 0x23, 0x7a, 0x9c, 0x85, 0x8e, 0x8a, 0xb1, 0xda, 0x86, 0x8a, + 0x97, 0x5d, 0x9f, 0x9e, 0xfb, 0x36, 0xe1, 0xeb, 0x3b, 0x1e, 0xe9, 0x35, 0x37, 0xd4, 0x0a, 0x1c, + 0x6f, 0x87, 0x6e, 0xc2, 0xb4, 0x2c, 0x10, 0xab, 0x0c, 0x3c, 0x8a, 0x1e, 0x13, 0xf7, 0x63, 0x35, + 0x38, 0xd1, 0x72, 0x6e, 0x01, 0x2e, 0x64, 0x4c, 0xf3, 0x58, 0xc4, 0xe5, 0xff, 0x6a, 0x70, 0x89, + 0xe7, 0xd2, 0x94, 0x19, 0x20, 0x64, 0xb8, 0xbc, 0xec, 0xc8, 0x73, 0xda, 0xa9, 0x46, 0x9e, 0xfb, + 0x36, 0x44, 0xd8, 0xd3, 0xff, 0x51, 0x09, 0xde, 0x7d, 0xe8, 0xb9, 0x44, 0x7f, 0x5f, 0x83, 0x09, + 0xb2, 0x17, 0x78, 0x46, 0xe8, 0x91, 0x41, 0x37, 0xe9, 0xd6, 0xa9, 0x10, 0x81, 0xf9, 0xa5, 0x08, + 0x11, 0xdf, 0xb8, 0x21, 0x8b, 0xa5, 0xd4, 0x60, 0x75, 0x3c, 0x54, 0x68, 0xe5, 0x51, 0x26, 0xd5, + 0x07, 0x10, 0x91, 0xe2, 0x58, 0xd4, 0xcc, 0x3d, 0x0f, 0x33, 0x49, 0xc8, 0xc7, 0xda, 0x2b, 0xbf, + 0x53, 0x82, 0xb1, 0x35, 0xcf, 0xa5, 0xdc, 0xdf, 0x19, 0x84, 0x55, 0x30, 0x62, 0x91, 0xd7, 0x0b, + 0x79, 0x4a, 0x8b, 0xc1, 0xe6, 0x66, 0x7d, 0xb0, 0x12, 0x59, 0x1f, 0x16, 0x06, 0x41, 0xd2, 0x3f, + 0xcd, 0xc3, 0x97, 0x34, 0x98, 0x10, 0x2d, 0xcf, 0x20, 0x78, 0xc0, 0x8f, 0xc4, 0x83, 0x07, 0x7c, + 0x68, 0x80, 0x79, 0xe5, 0x44, 0x0d, 0xf8, 0x8c, 0x06, 0x53, 0xa2, 0xc5, 0x0a, 0x69, 0x6f, 0x12, + 0x0f, 0xdd, 0x82, 0x31, 0xbf, 0xcb, 0x3e, 0xa4, 0x98, 0xd0, 0x55, 0x55, 0x9e, 0xf0, 0x36, 0x8d, + 0x26, 0xcb, 0xd3, 0xcd, 0x9b, 0x28, 0xb9, 0x14, 0x78, 0x01, 0x96, 0x9d, 0xa9, 0xf4, 0xe2, 0xb9, + 0x76, 0x2a, 0x9c, 0x14, 0x76, 0x6d, 0x82, 0x59, 0x0d, 0x65, 0xcc, 0xe9, 0x5f, 0xa9, 0xc2, 0x63, + 0x8c, 0x39, 0xad, 0xf6, 0x31, 0x2f, 0xd7, 0x3f, 0x3e, 0x1c, 0x2e, 0x36, 0x8b, 0x77, 0x7e, 0x07, + 0xc6, 0x9b, 0x1e, 0x31, 0x02, 0x62, 0x2e, 0xf6, 0x8e, 0x32, 0x38, 0x76, 0x5d, 0x55, 0x65, 0x0f, + 0x1c, 0x75, 0xa6, 0x37, 0x83, 0xfa, 0xe6, 0x54, 0x8a, 0x2e, 0xd1, 0xdc, 0xf7, 0xa6, 0xef, 0x87, + 0x11, 0xf7, 0xbe, 0x13, 0x9a, 0xae, 0xf4, 0x45, 0xcc, 0xa6, 0x72, 0x8f, 0xb6, 0xc6, 0xbc, 0x93, + 0x1a, 0x4e, 0x6d, 0xb8, 0x4f, 0x38, 0x35, 0x1b, 0xc6, 0xda, 0xec, 0x33, 0x0c, 0x14, 0x5a, 0x3f, + 0xf6, 0x41, 0xd5, 0xe4, 0x4b, 0x0c, 0x32, 0x96, 0x28, 0xe8, 0x0d, 0x4f, 0x6f, 0x21, 0xbf, 0x63, + 0x34, 0x89, 0x7a, 0xc3, 0xaf, 0xca, 0x42, 0x1c, 0xd5, 0xa3, 0x5e, 0x3c, 0x4e, 0xdf, 0x58, 0x71, + 0x0d, 0x9e, 0x18, 0x9e, 0x12, 0x9a, 0x8f, 0x2f, 0x7d, 0x6e, 0xac, 0xbe, 0x9f, 0x1d, 0x0e, 0x37, + 0xa9, 0xc8, 0x94, 0x91, 0x9d, 0x5b, 0x5a, 0x2b, 0x94, 0x5b, 0xfa, 0x7b, 0x65, 0x3c, 0xd9, 0x52, + 0x2c, 0x51, 0x58, 0x18, 0x4f, 0x76, 0x52, 0xa0, 0x8e, 0xc5, 0x90, 0xed, 0xc2, 0x05, 0x3f, 0x30, + 0x6c, 0xd2, 0xb0, 0x84, 0xa6, 0xc3, 0x0f, 0x8c, 0x76, 0xa7, 0x40, 0x40, 0x57, 0xee, 0xbf, 0x90, + 0x06, 0x85, 0xb3, 0xe0, 0xa3, 0x9f, 0xd2, 0x60, 0x96, 0x95, 0x2f, 0x74, 0x03, 0x97, 0x47, 0x1e, + 0x8f, 0x90, 0x1f, 0xff, 0x61, 0x9b, 0x09, 0x80, 0x8d, 0x1c, 0x78, 0x38, 0x17, 0x13, 0x7a, 0x0b, + 0x2e, 0xd1, 0x1b, 0x78, 0xa1, 0x19, 0x58, 0xbb, 0x56, 0xd0, 0x8b, 0x86, 0x70, 0xfc, 0x28, 0xae, + 0x4c, 0xd8, 0x58, 0xce, 0x02, 0x86, 0xb3, 0x71, 0xe8, 0x7f, 0xa1, 0x01, 0x4a, 0x6f, 0x21, 0x64, + 0x43, 0xd9, 0x94, 0x0e, 0x05, 0xda, 0x89, 0x04, 0x91, 0x0c, 0x29, 0x73, 0xe8, 0x87, 0x10, 0x62, + 0x40, 0x2e, 0x8c, 0xdf, 0xdf, 0xb6, 0x02, 0x62, 0x5b, 0x7e, 0x70, 0x42, 0x31, 0x2b, 0xc3, 0x00, + 0x6e, 0x2f, 0x4b, 0xc0, 0x38, 0xc2, 0xa1, 0xff, 0xdc, 0x30, 0x94, 0xc3, 0x10, 0xda, 0x87, 0xbf, + 0xf1, 0x76, 0x01, 0x35, 0x95, 0x34, 0x64, 0x83, 0x68, 0x60, 0x18, 0x13, 0x56, 0x4d, 0x01, 0xc3, + 0x19, 0x08, 0xd0, 0x5b, 0x70, 0xd1, 0x72, 0xb6, 0x3c, 0xc3, 0x0f, 0xbc, 0x2e, 0xd3, 0x95, 0x0f, + 0x92, 0xcd, 0x8b, 0xc9, 0x50, 0xf5, 0x0c, 0x70, 0x38, 0x13, 0x09, 0x22, 0x30, 0xc6, 0x33, 0x05, + 0xc8, 0x70, 0x82, 0x85, 0xf2, 0xd2, 0xf2, 0x0c, 0x04, 0x11, 0xd5, 0xe4, 0xbf, 0x7d, 0x2c, 0x61, + 0xf3, 0x50, 0x1f, 0xfc, 0x7f, 0xf9, 0x1e, 0x2d, 0xf6, 0x7d, 0xb5, 0x38, 0xbe, 0x28, 0xc5, 0x31, + 0x0f, 0xf5, 0x11, 0x2f, 0xc4, 0x49, 0x84, 0xfa, 0x1f, 0x6a, 0x30, 0xc2, 0x1d, 0x75, 0x4f, 0x9f, + 0x83, 0xfb, 0xe1, 0x18, 0x07, 0x57, 0x28, 0x21, 0x11, 0x1b, 0x6a, 0x6e, 0xaa, 0x9c, 0x2f, 0x6a, + 0x30, 0xce, 0x5a, 0x9c, 0x01, 0x4b, 0xf5, 0x5a, 0x9c, 0xa5, 0x7a, 0xb6, 0xf0, 0x6c, 0x72, 0x18, + 0xaa, 0x3f, 0x1c, 0x12, 0x73, 0x61, 0x1c, 0x4b, 0x1d, 0x2e, 0x08, 0x6b, 0xd8, 0x65, 0x6b, 0x8b, + 0xd0, 0x2d, 0x5e, 0x33, 0x7a, 0xfc, 0x81, 0x68, 0x44, 0xf8, 0x62, 0xa5, 0xab, 0x71, 0x56, 0x1f, + 0xf4, 0x7b, 0x1a, 0xe5, 0x0d, 0x02, 0xcf, 0x6a, 0x0e, 0x94, 0x7f, 0x26, 0x1c, 0xdb, 0xfc, 0x0a, + 0x07, 0xc6, 0x25, 0x93, 0x8d, 0x88, 0x49, 0x60, 0xa5, 0x0f, 0xf6, 0x2b, 0x95, 0x0c, 0x95, 0x59, + 0x94, 0x8b, 0xc2, 0x0f, 0x3e, 0xf6, 0xa7, 0x7d, 0x9b, 0x30, 0x35, 0xb5, 0x1c, 0x31, 0xba, 0x03, + 0x23, 0x7e, 0xd3, 0xed, 0x90, 0xe3, 0x64, 0xd4, 0x0a, 0x17, 0xb8, 0x41, 0x7b, 0x62, 0x0e, 0x60, + 0xee, 0x75, 0x98, 0x54, 0x47, 0x9e, 0x21, 0xf9, 0xd4, 0x54, 0xc9, 0xe7, 0xd8, 0x2f, 0x5d, 0xaa, + 0xa4, 0xf4, 0xfb, 0x25, 0x18, 0xe5, 0x79, 0xa9, 0x8f, 0xa0, 0x8c, 0xb7, 0x64, 0xd0, 0xff, 0x01, + 0xd2, 0xed, 0xab, 0x11, 0x32, 0x5f, 0x75, 0x1d, 0x65, 0x0d, 0xd4, 0xb8, 0xff, 0xc8, 0x09, 0xe3, + 0xa6, 0x0e, 0x15, 0xcf, 0xfa, 0xc3, 0x27, 0x76, 0xda, 0x91, 0x52, 0xff, 0x58, 0x83, 0xc9, 0x58, + 0x20, 0xda, 0x36, 0x0c, 0x79, 0x61, 0x3e, 0xb8, 0xa2, 0x6f, 0x15, 0xd2, 0xa6, 0xea, 0x6a, 0x9f, + 0x46, 0x98, 0xe2, 0x09, 0x63, 0xd6, 0x96, 0x4e, 0x28, 0x66, 0xad, 0xfe, 0x29, 0x0d, 0x2e, 0xcb, + 0x09, 0xc5, 0x23, 0x32, 0xa1, 0xc7, 0xa1, 0x6c, 0x74, 0x2c, 0xa6, 0x52, 0x53, 0x95, 0x92, 0x0b, + 0x6b, 0x75, 0x56, 0x86, 0xc3, 0x5a, 0xf4, 0x3e, 0x28, 0xcb, 0x8d, 0x27, 0xd8, 0xce, 0x90, 0x66, + 0x85, 0xaf, 0x2f, 0x61, 0x0b, 0xf4, 0x1e, 0x25, 0x2f, 0xc3, 0x48, 0xc4, 0x27, 0x84, 0x88, 0xf9, + 0x2b, 0xb0, 0xfe, 0x7d, 0x30, 0xde, 0x68, 0xdc, 0x59, 0x68, 0x36, 0x89, 0xef, 0x1f, 0x43, 0xb9, + 0xac, 0x7f, 0x62, 0x08, 0xa6, 0x44, 0x68, 0x39, 0xcb, 0x31, 0x2d, 0xa7, 0x75, 0x06, 0x77, 0xca, + 0x3a, 0x8c, 0x73, 0x6d, 0xc6, 0x21, 0xb9, 0xfb, 0x1a, 0xb2, 0x51, 0x32, 0x80, 0x73, 0x58, 0x81, + 0x23, 0x40, 0xe8, 0x2e, 0x8c, 0xbe, 0x41, 0xe9, 0x9b, 0x3c, 0x17, 0x47, 0x22, 0x33, 0xe1, 0xa6, + 0x67, 0xa4, 0xd1, 0xc7, 0x02, 0x04, 0xf2, 0x99, 0xd1, 0x1f, 0x63, 0xb8, 0x06, 0x89, 0x5d, 0x11, + 0x5b, 0xd9, 0x30, 0x2b, 0xcb, 0xa4, 0xb0, 0x1d, 0x64, 0xbf, 0x70, 0x88, 0x88, 0x45, 0x9f, 0x8f, + 0xf5, 0x78, 0x87, 0x44, 0x9f, 0x8f, 0x8d, 0x39, 0xe7, 0x6a, 0x7c, 0x16, 0x2e, 0x65, 0x2e, 0xc6, + 0xe1, 0xec, 0xac, 0xfe, 0x9b, 0x25, 0x18, 0x6e, 0x10, 0x62, 0x9e, 0xc1, 0xce, 0x7c, 0x2d, 0xc6, + 0xed, 0x7c, 0x7f, 0xe1, 0xf8, 0xf7, 0x79, 0xca, 0xaa, 0xad, 0x84, 0xb2, 0xea, 0xf9, 0xc2, 0x18, + 0xfa, 0x6b, 0xaa, 0x7e, 0xb9, 0x04, 0x40, 0x9b, 0x2d, 0x1a, 0xcd, 0x1d, 0x4e, 0x71, 0xc2, 0xdd, + 0xac, 0xc5, 0x29, 0x4e, 0x7a, 0x1b, 0x9e, 0xe5, 0xe3, 0xad, 0x0e, 0xa3, 0x1e, 0xbb, 0x89, 0xc4, + 0xbb, 0x07, 0xf0, 0x84, 0xd2, 0xb4, 0x04, 0x8b, 0x9a, 0x38, 0xb5, 0x18, 0x3e, 0x21, 0x6a, 0xa1, + 0xef, 0x01, 0xcb, 0x00, 0x5a, 0x5b, 0x6d, 0xa0, 0xb6, 0xb2, 0x3a, 0xa5, 0xe2, 0xbc, 0xbc, 0x00, + 0x77, 0xe8, 0x29, 0xff, 0x84, 0x06, 0xe7, 0x12, 0x6d, 0x8f, 0x20, 0xd3, 0x9d, 0x0a, 0xcd, 0xd4, + 0xff, 0x40, 0x83, 0x32, 0x1d, 0xcb, 0x19, 0x10, 0x9a, 0xff, 0x3f, 0x4e, 0x68, 0x3e, 0x58, 0x74, + 0x89, 0x73, 0xe8, 0xcb, 0x9f, 0x95, 0x80, 0x25, 0x9a, 0x10, 0x26, 0x0a, 0xca, 0xcb, 0xbf, 0x96, + 0xf3, 0xf2, 0x7f, 0x5d, 0x18, 0x0e, 0x24, 0x74, 0x94, 0x8a, 0xf1, 0xc0, 0xfb, 0x14, 0xdb, 0x80, + 0xa1, 0xf8, 0xb1, 0xc9, 0xb0, 0x0f, 0x78, 0x13, 0xa6, 0xfc, 0x6d, 0xd7, 0x0d, 0xc2, 0xc8, 0x06, + 0xc3, 0xc5, 0xf5, 0xd1, 0xcc, 0xc2, 0x5a, 0x4e, 0x85, 0x3f, 0x40, 0x35, 0x54, 0xd8, 0x38, 0x8e, + 0x0a, 0xcd, 0x03, 0x6c, 0xda, 0x6e, 0x73, 0xa7, 0x5a, 0xaf, 0x61, 0x69, 0x51, 0xcb, 0x8c, 0x96, + 0x16, 0xc3, 0x52, 0xac, 0xb4, 0x18, 0xc8, 0x96, 0xe1, 0x9b, 0x1a, 0x5f, 0xe9, 0x63, 0x6c, 0xde, + 0x33, 0xa4, 0x28, 0xef, 0x4d, 0x50, 0x14, 0x25, 0x4d, 0x7d, 0x8c, 0xaa, 0x54, 0x24, 0xc3, 0x3e, + 0x1c, 0xe9, 0x9f, 0x63, 0xe9, 0xb5, 0x7e, 0x47, 0x4c, 0x33, 0xcc, 0x55, 0xd2, 0x81, 0x29, 0x5b, + 0x4d, 0x99, 0x2a, 0xce, 0x48, 0xa1, 0x6c, 0xab, 0xa1, 0x8b, 0x46, 0xac, 0x18, 0xc7, 0x11, 0xa0, + 0x67, 0x60, 0x4a, 0xce, 0x8e, 0x2e, 0xa6, 0xb4, 0xdc, 0x60, 0xdb, 0x61, 0x4d, 0xad, 0xc0, 0xf1, + 0x76, 0xfa, 0xdf, 0x1b, 0x86, 0x47, 0xf8, 0xd8, 0x99, 0xc6, 0xa0, 0x46, 0x3a, 0xc4, 0x31, 0x89, + 0xd3, 0xec, 0x31, 0x9e, 0xd5, 0x74, 0x5b, 0xe8, 0x27, 0x35, 0x28, 0x13, 0xc7, 0xec, 0xb8, 0x96, + 0x23, 0x55, 0xfd, 0x1f, 0x29, 0x9e, 0xed, 0x25, 0x07, 0xcb, 0x92, 0x40, 0x20, 0xe2, 0x6f, 0x8a, + 0x5f, 0x38, 0x44, 0x8c, 0xee, 0xc3, 0x48, 0xc7, 0x73, 0x37, 0xa5, 0xb0, 0xf6, 0xd2, 0x89, 0x8f, + 0x60, 0x8d, 0x42, 0xe7, 0x1f, 0x97, 0xfd, 0x8b, 0x39, 0x3e, 0xf4, 0x16, 0x8c, 0xde, 0x27, 0xc4, + 0x0c, 0x15, 0xfa, 0x2f, 0x9f, 0x38, 0xe6, 0x97, 0x19, 0x78, 0x7e, 0xa1, 0xf1, 0xff, 0xb1, 0x40, + 0x49, 0x91, 0xb3, 0x51, 0x48, 0xce, 0xf2, 0xe5, 0xd3, 0x99, 0xb6, 0x40, 0xce, 0xff, 0xc7, 0x02, + 0xa5, 0x8e, 0xe1, 0x3d, 0x47, 0xfa, 0x66, 0xc7, 0x91, 0x21, 0xee, 0x81, 0x7e, 0xf8, 0x70, 0x8e, + 0x03, 0x70, 0x0d, 0x1e, 0x3d, 0xc2, 0xfc, 0x4e, 0x12, 0x22, 0xff, 0x44, 0xc7, 0x81, 0xf8, 0x75, + 0x0d, 0x1e, 0x53, 0x40, 0x2e, 0xed, 0x51, 0xc9, 0xab, 0x6a, 0x74, 0x8c, 0xa6, 0x15, 0xf4, 0xb8, + 0x47, 0xfd, 0xb1, 0xd2, 0x83, 0x7c, 0x42, 0x83, 0x31, 0x6e, 0xec, 0x24, 0xaf, 0xc8, 0xd7, 0x06, + 0xdc, 0x17, 0xb9, 0x43, 0x92, 0x71, 0xa7, 0xe5, 0xdc, 0xf8, 0x6f, 0x1f, 0x4b, 0xfc, 0xfa, 0xbf, + 0x19, 0x81, 0xef, 0x3a, 0x3a, 0x20, 0xf4, 0x4d, 0x2d, 0x9d, 0x8b, 0xb8, 0x7d, 0xba, 0x83, 0x0f, + 0x35, 0x4d, 0x42, 0x79, 0xf1, 0x72, 0x2a, 0xb7, 0xcf, 0x09, 0x29, 0xb1, 0x94, 0xc4, 0xc7, 0xff, + 0x54, 0x83, 0x49, 0xca, 0x3a, 0x84, 0x17, 0x00, 0xff, 0x4c, 0x9d, 0x53, 0x9e, 0xe9, 0xaa, 0x82, + 0x32, 0xe1, 0x1d, 0xab, 0x56, 0xe1, 0xd8, 0xd8, 0xd0, 0x46, 0xfc, 0xc5, 0x8e, 0x8b, 0xc4, 0xd7, + 0xb2, 0x38, 0xc6, 0xe3, 0x64, 0xce, 0x9a, 0xb3, 0x61, 0x3a, 0xbe, 0xf2, 0xa7, 0xa9, 0x82, 0x9b, + 0x7b, 0x01, 0xce, 0xa7, 0x66, 0x7f, 0x2c, 0x05, 0xd4, 0x4f, 0x0e, 0x43, 0x45, 0x59, 0xea, 0x98, + 0xb9, 0xa3, 0xe4, 0xdb, 0x3e, 0xab, 0xc1, 0x84, 0xe1, 0x38, 0xc2, 0x64, 0x46, 0xee, 0x5f, 0x73, + 0xc0, 0xaf, 0x9a, 0x85, 0x6a, 0x7e, 0x21, 0x42, 0x93, 0xb0, 0x09, 0x51, 0x6a, 0xb0, 0x3a, 0x9a, + 0x3e, 0x86, 0x8f, 0xa5, 0x33, 0x33, 0x7c, 0x44, 0x3f, 0x26, 0x99, 0x25, 0xbe, 0x8d, 0x5e, 0x39, + 0x85, 0xb5, 0x61, 0xbc, 0x57, 0xb6, 0xc6, 0x73, 0xee, 0x79, 0x98, 0x49, 0xae, 0xdc, 0xb1, 0x76, + 0xc1, 0x6f, 0x0e, 0xc5, 0x48, 0x75, 0x2e, 0xfa, 0x23, 0xe8, 0x79, 0x3f, 0x97, 0xd8, 0x2c, 0x9c, + 0x04, 0x58, 0xa7, 0xb5, 0x20, 0x27, 0xbb, 0x63, 0x86, 0xce, 0xce, 0x54, 0x76, 0xd0, 0x4f, 0xb6, + 0x08, 0x97, 0x94, 0xf5, 0x51, 0x32, 0x15, 0x3e, 0x01, 0x63, 0xbb, 0x96, 0x6f, 0xc9, 0x58, 0x47, + 0xca, 0x0d, 0xfd, 0x12, 0x2f, 0xc6, 0xb2, 0x5e, 0x5f, 0x8e, 0x9d, 0xfd, 0x75, 0xb7, 0xe3, 0xda, + 0x6e, 0xab, 0xb7, 0x70, 0xdf, 0xf0, 0x08, 0x76, 0xbb, 0x81, 0x80, 0x76, 0xd4, 0xfb, 0x7e, 0x05, + 0xae, 0x2b, 0xd0, 0x32, 0x83, 0x36, 0x1c, 0x07, 0xdc, 0x97, 0xc6, 0xa4, 0x78, 0x21, 0xbc, 0x5a, + 0x7f, 0x5b, 0x83, 0x2b, 0x24, 0xef, 0x2a, 0x10, 0x2c, 0xfa, 0x2b, 0xa7, 0x75, 0xd5, 0x88, 0x58, + 0xb8, 0x79, 0xd5, 0x38, 0x7f, 0x64, 0xa8, 0x17, 0xcb, 0xd7, 0x59, 0x1a, 0x44, 0x57, 0x9a, 0xf1, + 0xbd, 0xfb, 0x65, 0xeb, 0x44, 0xbf, 0xa2, 0xc1, 0x45, 0x3b, 0xe3, 0xe8, 0x08, 0xbe, 0xba, 0x71, + 0x0a, 0xa7, 0x92, 0xbf, 0x4b, 0x67, 0xd5, 0xe0, 0xcc, 0xa1, 0xa0, 0x5f, 0xcb, 0x8d, 0x26, 0xc2, + 0x9f, 0x8d, 0xd7, 0x07, 0x1c, 0xe4, 0x49, 0x05, 0x16, 0xf9, 0xb4, 0x06, 0xc8, 0x4c, 0xb1, 0xc5, + 0xc2, 0xd2, 0xe7, 0xc5, 0x13, 0x97, 0x50, 0xb8, 0x61, 0x41, 0xba, 0x1c, 0x67, 0x0c, 0x82, 0x7d, + 0xe7, 0x20, 0xe3, 0xf8, 0x8a, 0x30, 0xc1, 0x83, 0x7e, 0xe7, 0x2c, 0xca, 0xc0, 0xbf, 0x73, 0x56, + 0x0d, 0xce, 0x1c, 0x8a, 0xfe, 0xa9, 0x31, 0xae, 0x49, 0x63, 0x2f, 0xbf, 0x9b, 0x30, 0xba, 0xc9, + 0x34, 0xaf, 0xe2, 0xdc, 0x16, 0x56, 0xf3, 0x72, 0xfd, 0x2d, 0x17, 0xe4, 0xf8, 0xff, 0x58, 0x40, + 0x46, 0xaf, 0xc2, 0x90, 0xe9, 0xf8, 0xe2, 0xc0, 0x7d, 0x68, 0x00, 0x85, 0x65, 0xe4, 0x6e, 0x55, + 0x5b, 0x6d, 0x60, 0x0a, 0x14, 0x39, 0x50, 0x76, 0x84, 0xf2, 0x49, 0x08, 0xc8, 0x85, 0x53, 0xc1, + 0x86, 0x4a, 0xac, 0x50, 0x75, 0x26, 0x4b, 0x70, 0x88, 0x83, 0xe2, 0x4b, 0xbc, 0xb6, 0x14, 0xc6, + 0x17, 0xaa, 0x5f, 0xfb, 0x69, 0xb8, 0xd7, 0x54, 0x65, 0xea, 0xc8, 0xd1, 0x95, 0xa9, 0x53, 0xb9, + 0x8f, 0x4f, 0x04, 0x46, 0x03, 0xc3, 0x72, 0x02, 0xae, 0x4c, 0x2b, 0x68, 0x28, 0x41, 0xc7, 0xbf, + 0x4e, 0xa1, 0x44, 0x5a, 0x2b, 0xf6, 0xd3, 0xc7, 0x02, 0x38, 0xdd, 0x58, 0xbb, 0x2c, 0x21, 0xbb, + 0x38, 0x98, 0x85, 0x37, 0x16, 0x4f, 0xeb, 0xce, 0x37, 0x16, 0xff, 0x1f, 0x0b, 0xc8, 0xe8, 0x75, + 0x28, 0xfb, 0xd2, 0xb4, 0xa5, 0x3c, 0x68, 0x1e, 0x60, 0x61, 0xd7, 0x22, 0x7c, 0xaa, 0x84, 0x41, + 0x4b, 0x08, 0x1f, 0x6d, 0xc2, 0x98, 0xc5, 0xbd, 0x80, 0x44, 0x70, 0xa5, 0x0f, 0x0d, 0x90, 0x06, + 0x8f, 0x0b, 0xd6, 0xe2, 0x07, 0x96, 0x80, 0xf5, 0x2f, 0x01, 0x7f, 0x0b, 0x11, 0xd6, 0x83, 0x5b, + 0x50, 0x96, 0xe0, 0x06, 0xf1, 0xed, 0x93, 0x89, 0x47, 0xf9, 0xd4, 0xc2, 0x34, 0xa4, 0x21, 0x6c, + 0x54, 0xcd, 0xf2, 0xd1, 0x8c, 0xd2, 0x31, 0x1c, 0xcd, 0x3f, 0xf3, 0x0d, 0x96, 0x29, 0x50, 0x46, + 0x4a, 0x18, 0x2a, 0xbe, 0xb5, 0xc2, 0x28, 0x0a, 0xb1, 0x0c, 0x81, 0x32, 0xd0, 0x82, 0x82, 0x24, + 0xc7, 0xba, 0x72, 0xb8, 0x90, 0x75, 0xe5, 0x73, 0x70, 0x4e, 0x58, 0xb3, 0xd4, 0x59, 0x52, 0xfe, + 0xa0, 0x27, 0xdc, 0x4f, 0x98, 0x9d, 0x53, 0x35, 0x5e, 0x85, 0x93, 0x6d, 0xd1, 0xef, 0x6b, 0x50, + 0x6e, 0x0a, 0x96, 0x43, 0x9c, 0xab, 0xe5, 0xc1, 0x1e, 0xcc, 0xe6, 0x25, 0x07, 0xc3, 0x99, 0xe9, + 0x97, 0x24, 0x8d, 0x90, 0xc5, 0x27, 0xa4, 0x34, 0x08, 0x47, 0x8d, 0xfe, 0x88, 0xca, 0x0b, 0x36, + 0x4b, 0x86, 0xca, 0xbc, 0xd1, 0xb9, 0x5f, 0xcc, 0xbd, 0x01, 0x67, 0xb1, 0x10, 0x41, 0xe4, 0x13, + 0xf9, 0x48, 0x28, 0x15, 0x44, 0x35, 0x27, 0x34, 0x17, 0x75, 0xf8, 0xe8, 0x1f, 0x6b, 0xf0, 0x18, + 0x77, 0x46, 0xaa, 0x52, 0x2e, 0x82, 0xe5, 0x94, 0x27, 0x51, 0x12, 0xfb, 0xc8, 0x16, 0xb4, 0x7c, + 0x6c, 0x5b, 0xd0, 0xc7, 0x0f, 0xf6, 0x2b, 0x8f, 0x55, 0x8f, 0x00, 0x1b, 0x1f, 0x69, 0x04, 0xe8, + 0x4d, 0x98, 0xb2, 0xd5, 0x88, 0x39, 0x82, 0xc0, 0x14, 0x7a, 0x8e, 0x89, 0x85, 0xde, 0xe1, 0xfa, + 0xf7, 0x58, 0x11, 0x8e, 0xa3, 0x9a, 0xdb, 0x81, 0xa9, 0xd8, 0x46, 0x3b, 0x55, 0x25, 0x89, 0x03, + 0x33, 0xc9, 0xfd, 0x70, 0xaa, 0x76, 0x51, 0x77, 0x61, 0x3c, 0xbc, 0xa8, 0xd0, 0x23, 0x0a, 0xa2, + 0x88, 0x91, 0xb8, 0x4b, 0x7a, 0x1c, 0x6b, 0x25, 0x26, 0xe0, 0x71, 0x45, 0xfc, 0x4b, 0xb4, 0x40, + 0x00, 0xd4, 0xbf, 0x2c, 0x5e, 0x59, 0xd6, 0x49, 0xbb, 0x63, 0x1b, 0x01, 0x79, 0xe7, 0xbf, 0xf1, + 0xeb, 0xff, 0x55, 0xe3, 0xf7, 0x0d, 0xbf, 0x56, 0x91, 0x01, 0x13, 0x6d, 0x1e, 0x16, 0x9a, 0x05, + 0x60, 0xd0, 0x8a, 0x87, 0x7e, 0x58, 0x89, 0xc0, 0x60, 0x15, 0x26, 0xba, 0x0f, 0xe3, 0x92, 0xb5, + 0x91, 0x1a, 0x89, 0x5b, 0x83, 0x31, 0x06, 0x21, 0x17, 0x15, 0x3e, 0x1f, 0xcb, 0x12, 0x1f, 0x47, + 0xb8, 0x74, 0x03, 0x50, 0xba, 0x0f, 0x95, 0x82, 0xa5, 0xbb, 0x83, 0x16, 0x8f, 0xb5, 0x98, 0x72, + 0x79, 0x38, 0x34, 0xfd, 0xb9, 0xfe, 0xf9, 0x12, 0x64, 0xa6, 0xe2, 0x43, 0x3a, 0x8c, 0x72, 0x0f, + 0x44, 0x99, 0x59, 0x9d, 0xb2, 0x32, 0xdc, 0x3d, 0x11, 0x8b, 0x1a, 0x74, 0x8f, 0x6b, 0x42, 0x1c, + 0x93, 0xc5, 0x38, 0x8c, 0xa8, 0x84, 0xea, 0xeb, 0xba, 0x94, 0xd5, 0x00, 0x67, 0xf7, 0x43, 0xbb, + 0x80, 0xda, 0xc6, 0x5e, 0x12, 0xda, 0x00, 0x49, 0xaf, 0x56, 0x52, 0xd0, 0x70, 0x06, 0x06, 0x7a, + 0x91, 0x1a, 0xcd, 0x26, 0xe9, 0x04, 0xc4, 0xe4, 0x53, 0x94, 0x8f, 0xbc, 0xec, 0x22, 0x5d, 0x88, + 0x57, 0xe1, 0x64, 0x5b, 0xfd, 0x1b, 0xc3, 0x70, 0x25, 0xbe, 0x88, 0xf4, 0x84, 0x4a, 0x27, 0xc1, + 0x17, 0xa4, 0x0f, 0x04, 0x5f, 0xc8, 0x27, 0x92, 0x3e, 0x10, 0xb3, 0x55, 0x8f, 0xb0, 0x2b, 0xd9, + 0xb0, 0x7d, 0xd9, 0x29, 0xe6, 0x0f, 0xf1, 0x6d, 0xf0, 0xf8, 0xcb, 0xf1, 0x6c, 0x1c, 0x3a, 0x55, + 0xcf, 0xc6, 0xb7, 0x35, 0x98, 0x8b, 0x17, 0xdf, 0xb2, 0x1c, 0xcb, 0xdf, 0x16, 0x91, 0xfa, 0x8e, + 0xef, 0x82, 0xc1, 0x12, 0x63, 0x2c, 0xe7, 0x42, 0xc4, 0x7d, 0xb0, 0xa1, 0x4f, 0x6a, 0x70, 0x35, + 0xb1, 0x2e, 0xb1, 0xb8, 0x81, 0xc7, 0xf7, 0xc6, 0x60, 0x3e, 0xda, 0xcb, 0xf9, 0x20, 0x71, 0x3f, + 0x7c, 0xfa, 0xbf, 0x28, 0xc1, 0x08, 0xb3, 0x51, 0x78, 0x67, 0x18, 0xa5, 0xb3, 0xa1, 0xe6, 0xda, + 0x69, 0xb5, 0x12, 0x76, 0x5a, 0x2f, 0x14, 0x47, 0xd1, 0xdf, 0x50, 0xeb, 0x23, 0x70, 0x99, 0x35, + 0x5b, 0x30, 0x99, 0x5a, 0xc6, 0x27, 0xe6, 0x82, 0x69, 0xb2, 0x08, 0x11, 0x87, 0xeb, 0xa2, 0x1f, + 0x81, 0xa1, 0xae, 0x67, 0x27, 0x63, 0xa6, 0x6c, 0xe0, 0x65, 0x4c, 0xcb, 0xf5, 0xb7, 0x35, 0x98, + 0x61, 0xb0, 0x95, 0xe3, 0x8b, 0x76, 0xa1, 0xec, 0x89, 0x23, 0x2c, 0xbe, 0xcd, 0x72, 0xe1, 0xa9, + 0x65, 0x90, 0x05, 0x91, 0x2c, 0x54, 0xfc, 0xc2, 0x21, 0x2e, 0xfd, 0x6b, 0xa3, 0x30, 0x9b, 0xd7, + 0x09, 0xfd, 0x82, 0x06, 0x97, 0x9b, 0x11, 0x37, 0xb7, 0xd0, 0x0d, 0xb6, 0x5d, 0xcf, 0x0a, 0x2c, + 0x61, 0xbc, 0x53, 0x50, 0xcc, 0xad, 0x2e, 0x84, 0xa3, 0x62, 0x71, 0xee, 0xaa, 0x99, 0x18, 0x70, + 0x0e, 0x66, 0xf4, 0x16, 0xc0, 0x4e, 0x14, 0x58, 0xb7, 0x54, 0x3c, 0x85, 0x07, 0x9b, 0xb6, 0x12, + 0x7c, 0x57, 0x0e, 0x8a, 0x69, 0x36, 0x95, 0x72, 0x05, 0x1d, 0x45, 0xee, 0xfb, 0xdb, 0x77, 0x49, + 0xaf, 0x63, 0x58, 0xd2, 0x46, 0xa1, 0x38, 0xf2, 0x46, 0xe3, 0x8e, 0x00, 0x15, 0x47, 0xae, 0x94, + 0x2b, 0xe8, 0xd0, 0xc7, 0x34, 0x98, 0x72, 0x55, 0x77, 0xf2, 0x41, 0x2c, 0x60, 0x33, 0xfd, 0xd2, + 0x39, 0x0b, 0x1d, 0xaf, 0x8a, 0xa3, 0xa4, 0x7b, 0xe2, 0xbc, 0x9f, 0xbc, 0xb2, 0x04, 0x51, 0x5b, + 0x19, 0x3c, 0xd3, 0xaf, 0x72, 0xff, 0x71, 0x71, 0x3c, 0x5d, 0x9d, 0x46, 0xcf, 0x06, 0x45, 0x82, + 0xa6, 0xb9, 0xe4, 0x34, 0xbd, 0x1e, 0xf3, 0x0c, 0xa5, 0x83, 0x1a, 0x2d, 0x3e, 0xa8, 0xa5, 0xf5, + 0x6a, 0x2d, 0x06, 0x2c, 0x3e, 0xa8, 0x74, 0x75, 0x1a, 0xbd, 0xfe, 0xd1, 0x12, 0x3c, 0x94, 0xb3, + 0xc7, 0xfe, 0xda, 0xf8, 0xff, 0x7f, 0x51, 0x83, 0x71, 0xb6, 0x06, 0xef, 0x10, 0x27, 0x22, 0x36, + 0xd6, 0x1c, 0x4b, 0xc6, 0x3f, 0xd0, 0xe0, 0x7c, 0x2a, 0xc2, 0xea, 0x91, 0x5c, 0x50, 0xce, 0xcc, + 0xc8, 0xee, 0x3d, 0x51, 0x34, 0xf5, 0xa1, 0xc8, 0xa1, 0x39, 0x19, 0x49, 0x5d, 0x7f, 0x19, 0xa6, + 0x62, 0x86, 0x8c, 0x61, 0xac, 0x26, 0x2d, 0x33, 0x56, 0x93, 0x1a, 0x8a, 0xa9, 0xd4, 0x2f, 0x14, + 0x53, 0xb4, 0xe5, 0xd3, 0x94, 0xed, 0xaf, 0xcd, 0x96, 0xff, 0xfa, 0x39, 0xb1, 0xe5, 0xd9, 0x8b, + 0xc3, 0x6b, 0x30, 0xca, 0x02, 0x3f, 0xc9, 0x1b, 0xf3, 0x66, 0xe1, 0x80, 0x52, 0x3e, 0x97, 0xa4, + 0xf8, 0xff, 0x58, 0x40, 0x45, 0x35, 0x98, 0x69, 0xda, 0x6e, 0xd7, 0x14, 0xc9, 0x4f, 0x57, 0x23, + 0xa1, 0x2d, 0x8c, 0x0b, 0x5a, 0x4d, 0xd4, 0xe3, 0x54, 0x0f, 0x84, 0xf9, 0x9b, 0x05, 0xbf, 0xcf, + 0x0a, 0xc5, 0x05, 0xad, 0xad, 0x36, 0x78, 0x5e, 0x8d, 0xf0, 0xad, 0xe2, 0x0d, 0x00, 0x22, 0x37, + 0xaf, 0xf4, 0xfd, 0x7c, 0xae, 0x58, 0xc4, 0xd3, 0xf0, 0x08, 0x48, 0xe6, 0x33, 0x2c, 0xf2, 0xb1, + 0x82, 0x04, 0x79, 0x30, 0xb1, 0x6d, 0x6d, 0x12, 0xcf, 0xe1, 0x7c, 0xd4, 0x48, 0x71, 0x16, 0xf1, + 0x4e, 0x04, 0x86, 0xcb, 0xf8, 0x4a, 0x01, 0x56, 0x91, 0x20, 0x8f, 0xb3, 0x23, 0x5c, 0x3d, 0x2c, + 0xae, 0x9c, 0xe7, 0x07, 0x8b, 0xbe, 0x1f, 0xcd, 0x33, 0x2a, 0xc3, 0x0a, 0x16, 0xe4, 0x00, 0x38, + 0x61, 0xc4, 0xb7, 0x41, 0x5e, 0x1c, 0xa2, 0xb8, 0x71, 0x9c, 0xf1, 0x88, 0x7e, 0x63, 0x05, 0x03, + 0x5d, 0xd7, 0x76, 0x14, 0x42, 0x50, 0xe8, 0x10, 0x5f, 0x18, 0x30, 0x8c, 0xa3, 0xd0, 0x9d, 0x44, + 0x05, 0x58, 0x45, 0x42, 0xe7, 0xd8, 0x0e, 0x03, 0xff, 0x09, 0x1d, 0x61, 0xa1, 0x39, 0x46, 0xe1, + 0x03, 0x45, 0x72, 0xb6, 0xf0, 0x37, 0x56, 0x30, 0xa0, 0xd7, 0x95, 0xa7, 0x2e, 0x28, 0xae, 0x81, + 0x3a, 0xd2, 0x33, 0xd7, 0x07, 0x22, 0x45, 0xcc, 0x04, 0x3b, 0xab, 0x57, 0x15, 0x25, 0x0c, 0x0b, + 0x88, 0x48, 0xe9, 0x47, 0x4a, 0x29, 0x13, 0x99, 0x50, 0x4f, 0xf6, 0x35, 0xa1, 0xae, 0x52, 0x0e, + 0x4d, 0x71, 0xe9, 0x61, 0x44, 0x61, 0x2a, 0x7a, 0xe1, 0x68, 0x24, 0x2b, 0x71, 0xba, 0x3d, 0x27, + 0xfa, 0xc4, 0x64, 0x7d, 0xa7, 0x55, 0xa2, 0xcf, 0xcb, 0x70, 0x58, 0x8b, 0x76, 0x61, 0xd2, 0x57, + 0xec, 0xb1, 0x45, 0x46, 0xcd, 0x01, 0xde, 0xa6, 0x84, 0x2d, 0x36, 0x0b, 0x85, 0xa5, 0x96, 0xe0, + 0x18, 0x1e, 0xf4, 0x96, 0x6a, 0xdc, 0x38, 0x53, 0xdc, 0xf9, 0x36, 0x3b, 0xd0, 0x63, 0xa4, 0x61, + 0x0b, 0xed, 0xea, 0x54, 0x9b, 0xc3, 0x6e, 0xdc, 0x8c, 0xef, 0xfc, 0x89, 0x04, 0x1b, 0x38, 0xd4, + 0xcc, 0x8f, 0x7e, 0x5a, 0xb2, 0xd7, 0x71, 0xfd, 0xae, 0x47, 0x58, 0x00, 0x5b, 0xf6, 0x79, 0x50, + 0xf4, 0x69, 0x97, 0x92, 0x95, 0x38, 0xdd, 0x1e, 0xfd, 0xb4, 0x06, 0x33, 0x3c, 0x21, 0x29, 0xbd, + 0xba, 0x5c, 0x87, 0x38, 0x81, 0xcf, 0x32, 0x6e, 0x16, 0xf4, 0x8f, 0x6d, 0x24, 0x60, 0xf1, 0x2c, + 0x4e, 0xc9, 0x52, 0x9c, 0xc2, 0x49, 0x77, 0x8e, 0x1a, 0xae, 0x80, 0x25, 0xee, 0x2c, 0xb8, 0x73, + 0xd4, 0x50, 0x08, 0x7c, 0xe7, 0xa8, 0x25, 0x38, 0x86, 0x07, 0x3d, 0x03, 0x53, 0xbe, 0xcc, 0xae, + 0xc3, 0x56, 0xf0, 0x52, 0x14, 0x4f, 0xac, 0xa1, 0x56, 0xe0, 0x78, 0x3b, 0xfd, 0xdf, 0x6a, 0x00, + 0xa1, 0xf6, 0xe0, 0x2c, 0x74, 0xe2, 0x66, 0x4c, 0xa1, 0xb2, 0x38, 0x90, 0xb6, 0x83, 0xe4, 0x6a, + 0xc6, 0xbf, 0xaa, 0xc1, 0x74, 0xd4, 0xec, 0x0c, 0x58, 0xf5, 0x66, 0x9c, 0x55, 0x7f, 0x7e, 0xb0, + 0x79, 0xe5, 0xf0, 0xeb, 0xff, 0xa7, 0xa4, 0xce, 0x8a, 0x71, 0x63, 0xbb, 0xb1, 0x37, 0x66, 0x8a, + 0xfa, 0xce, 0x20, 0x6f, 0xcc, 0xaa, 0x0b, 0x75, 0x34, 0xdf, 0x8c, 0x37, 0xe7, 0xbf, 0x15, 0xe3, + 0x85, 0x06, 0x08, 0x14, 0x10, 0x32, 0x3e, 0x12, 0x35, 0x5f, 0x80, 0xc3, 0x18, 0xa3, 0x37, 0x54, + 0x52, 0xc9, 0x5f, 0xab, 0x3f, 0x5c, 0xcc, 0x3b, 0x5d, 0x99, 0x70, 0x5f, 0x02, 0xa9, 0x7f, 0x71, + 0x0a, 0x26, 0x14, 0x45, 0x5b, 0xe2, 0xc5, 0x5c, 0x3b, 0x8b, 0x17, 0xf3, 0x00, 0x26, 0x9a, 0x61, + 0x40, 0x78, 0xb9, 0xec, 0x03, 0xe2, 0x0c, 0x49, 0x74, 0x14, 0x6a, 0xde, 0xc7, 0x2a, 0x1a, 0xca, + 0x48, 0x84, 0x7b, 0x6c, 0xe8, 0x04, 0xec, 0x18, 0xfa, 0xed, 0xab, 0xf7, 0x03, 0x48, 0x5e, 0x94, + 0x98, 0x22, 0xa2, 0x67, 0x68, 0x84, 0x5e, 0xf7, 0xef, 0x84, 0x75, 0x58, 0x69, 0x97, 0x7e, 0x81, + 0x1d, 0x39, 0xb3, 0x17, 0x58, 0xba, 0x0d, 0x6c, 0x99, 0x8f, 0x68, 0x20, 0x9b, 0x9c, 0x30, 0xab, + 0x51, 0xb4, 0x0d, 0xc2, 0x22, 0x1f, 0x2b, 0x48, 0x72, 0x0c, 0x27, 0xc6, 0x0a, 0x19, 0x4e, 0x74, + 0xe1, 0x82, 0x47, 0x02, 0xaf, 0x57, 0xed, 0x35, 0x59, 0x9a, 0x2e, 0x2f, 0x60, 0x12, 0x65, 0xb9, + 0x58, 0x84, 0x29, 0x9c, 0x06, 0x85, 0xb3, 0xe0, 0xc7, 0x98, 0xb1, 0xf1, 0xbe, 0xcc, 0xd8, 0x07, + 0x60, 0x22, 0x20, 0xcd, 0x6d, 0xc7, 0x6a, 0x1a, 0x76, 0xbd, 0x26, 0xc2, 0x5d, 0x46, 0x7c, 0x45, + 0x54, 0x85, 0xd5, 0x76, 0x68, 0x11, 0x86, 0xba, 0x96, 0x29, 0xb8, 0xd1, 0xef, 0x09, 0x55, 0xd6, + 0xf5, 0xda, 0x83, 0xfd, 0xca, 0xbb, 0x23, 0x4b, 0x84, 0x70, 0x56, 0x37, 0x3a, 0x3b, 0xad, 0x1b, + 0x41, 0xaf, 0x43, 0xfc, 0xf9, 0x8d, 0x7a, 0x0d, 0xd3, 0xce, 0x59, 0x46, 0x25, 0x93, 0xc7, 0x30, + 0x2a, 0xf9, 0xb4, 0x06, 0x17, 0x8c, 0xa4, 0xb6, 0x9d, 0xf8, 0xb3, 0x53, 0xc5, 0xa9, 0x65, 0xb6, + 0x06, 0x7f, 0xf1, 0xaa, 0x98, 0xdf, 0x85, 0x85, 0x34, 0x3a, 0x9c, 0x35, 0x06, 0xe4, 0x01, 0x6a, + 0x5b, 0xad, 0x30, 0x35, 0x90, 0xf8, 0xea, 0xd3, 0xc5, 0xf4, 0x08, 0x2b, 0x29, 0x48, 0x38, 0x03, + 0x3a, 0xba, 0x0f, 0x13, 0xcd, 0x48, 0x27, 0x2f, 0xb8, 0xea, 0xda, 0x49, 0x3c, 0x0a, 0x70, 0xc9, + 0x4b, 0x55, 0xf8, 0xab, 0x98, 0xc2, 0xd7, 0x34, 0x45, 0xe4, 0x15, 0x2f, 0x4a, 0x6c, 0xd6, 0x33, + 0xc5, 0x5f, 0xd3, 0xb2, 0x21, 0xe2, 0x3e, 0xd8, 0x58, 0x5c, 0x27, 0x3b, 0x9e, 0xc1, 0x8b, 0x25, + 0xaf, 0x2f, 0xe8, 0x0b, 0x9e, 0x48, 0x06, 0xc6, 0xb7, 0x66, 0xa2, 0x10, 0x27, 0x11, 0xea, 0x5f, + 0xd1, 0x84, 0xc2, 0xec, 0x0c, 0xad, 0x21, 0x4e, 0xfb, 0x29, 0x4d, 0xff, 0x73, 0x0d, 0x52, 0x3c, + 0x3a, 0xda, 0x84, 0x31, 0x0a, 0xa2, 0xb6, 0xda, 0x10, 0xd3, 0xfa, 0x50, 0xb1, 0xeb, 0x92, 0x81, + 0xe0, 0xda, 0x47, 0xf1, 0x03, 0x4b, 0xc0, 0x94, 0xeb, 0x77, 0x94, 0x88, 0xdb, 0x62, 0x86, 0x85, + 0xf8, 0x11, 0x35, 0x72, 0x37, 0xe7, 0xfa, 0xd5, 0x12, 0x1c, 0xc3, 0xa3, 0x2f, 0x03, 0x44, 0x72, + 0xd5, 0xc0, 0x06, 0x32, 0xdf, 0x1a, 0x81, 0x4b, 0x83, 0x3a, 0x1b, 0xb0, 0xc4, 0x51, 0x64, 0xd7, + 0x6a, 0x06, 0x0b, 0x5b, 0x01, 0xf1, 0xee, 0xdd, 0x5b, 0x59, 0xdf, 0xf6, 0x88, 0xbf, 0xed, 0xda, + 0x66, 0xc1, 0xcc, 0x55, 0xec, 0x41, 0x6d, 0x29, 0x13, 0x22, 0xce, 0xc1, 0xc4, 0x64, 0x4a, 0x91, + 0xc8, 0x1a, 0x53, 0x66, 0xb2, 0xeb, 0xf9, 0x81, 0x88, 0x6a, 0xc3, 0x65, 0xca, 0x64, 0x25, 0x4e, + 0xb7, 0x4f, 0x02, 0x59, 0xb6, 0xda, 0x16, 0xcf, 0xe0, 0xa3, 0xa5, 0x81, 0xb0, 0x4a, 0x9c, 0x6e, + 0xaf, 0x02, 0xe1, 0x5f, 0x8a, 0x9e, 0xf6, 0x91, 0x34, 0x90, 0xb0, 0x12, 0xa7, 0xdb, 0x23, 0x13, + 0x1e, 0xf6, 0x48, 0xd3, 0x6d, 0xb7, 0x89, 0x63, 0xf2, 0x9c, 0x8c, 0x86, 0xd7, 0xb2, 0x9c, 0x5b, + 0x9e, 0xc1, 0x1a, 0x32, 0x15, 0x9d, 0xc6, 0xf2, 0x50, 0x3c, 0x8c, 0xfb, 0xb4, 0xc3, 0x7d, 0xa1, + 0xa0, 0x36, 0x9c, 0xe3, 0x09, 0xa0, 0xbc, 0xba, 0x13, 0x10, 0x6f, 0xd7, 0xb0, 0x85, 0x1e, 0xae, + 0x50, 0x32, 0xea, 0x8d, 0x38, 0x28, 0x9c, 0x84, 0x8d, 0x7a, 0x94, 0xef, 0x10, 0xc3, 0x51, 0x50, + 0x96, 0x8b, 0xa7, 0x56, 0xc3, 0x69, 0x70, 0x38, 0x0b, 0x87, 0xfe, 0x69, 0x0d, 0x84, 0x25, 0x32, + 0x7a, 0x38, 0xf6, 0xd6, 0x51, 0x4e, 0xbc, 0x73, 0xc8, 0xcc, 0x13, 0xa5, 0xcc, 0xcc, 0x13, 0xef, + 0x55, 0xc2, 0x25, 0x8d, 0x47, 0xb4, 0x8f, 0x43, 0x56, 0xb2, 0xe6, 0x3c, 0x09, 0xe3, 0x84, 0x3f, + 0xa3, 0x85, 0x1c, 0x2d, 0xb3, 0xee, 0x5e, 0x92, 0x85, 0x38, 0xaa, 0xd7, 0xff, 0x58, 0x03, 0x01, + 0x81, 0xe5, 0x78, 0x3a, 0x52, 0xae, 0x9f, 0x43, 0x4d, 0x9b, 0x94, 0x1c, 0x45, 0x43, 0xb9, 0x39, + 0x8a, 0x4e, 0x29, 0x75, 0xcf, 0x6f, 0x6b, 0x70, 0x2e, 0x1e, 0xbf, 0xca, 0x47, 0xef, 0x81, 0x31, + 0x11, 0xe1, 0x52, 0x84, 0xa8, 0x63, 0x5d, 0x45, 0x88, 0x09, 0x2c, 0xeb, 0xe2, 0xea, 0xb0, 0x01, + 0x44, 0xcc, 0xec, 0x30, 0x5a, 0x87, 0x48, 0x7b, 0x1f, 0x9f, 0x81, 0x51, 0x1e, 0x1e, 0x91, 0xd2, + 0xb4, 0x0c, 0xb7, 0xcd, 0xbb, 0xc5, 0xa3, 0x30, 0x16, 0xf1, 0xb5, 0x53, 0x33, 0x11, 0x94, 0xfa, + 0x66, 0x22, 0xc0, 0x3c, 0x25, 0xda, 0x00, 0x4f, 0x1f, 0x55, 0x5c, 0x17, 0x39, 0xd6, 0x65, 0x3a, + 0xb4, 0x20, 0xf6, 0x26, 0x30, 0x5c, 0x9c, 0x73, 0xe3, 0x0b, 0xa0, 0xbc, 0x0c, 0x4c, 0xf7, 0x7d, + 0x15, 0x90, 0xf1, 0xe7, 0x46, 0x8a, 0x9b, 0x1a, 0x8a, 0x25, 0x3f, 0x42, 0xfc, 0xb9, 0xf0, 0x20, + 0x8d, 0xe6, 0x1e, 0xa4, 0x2d, 0x18, 0x13, 0x47, 0x41, 0x10, 0xc7, 0x0f, 0x0d, 0x90, 0x5b, 0x4c, + 0x09, 0x99, 0xcc, 0x0b, 0xb0, 0x04, 0x4e, 0x6f, 0xdc, 0xb6, 0xb1, 0x67, 0xb5, 0xbb, 0x6d, 0x46, + 0x11, 0x47, 0xd4, 0xa6, 0xac, 0x18, 0xcb, 0x7a, 0xd6, 0x94, 0x5b, 0x68, 0x32, 0x41, 0x4a, 0x6d, + 0xca, 0x8b, 0xb1, 0xac, 0x47, 0xaf, 0x42, 0xb9, 0x6d, 0xec, 0x35, 0xba, 0x5e, 0x8b, 0x88, 0x17, + 0x81, 0x7c, 0x1e, 0xaf, 0x1b, 0x58, 0xf6, 0x3c, 0x15, 0xff, 0x03, 0x6f, 0xbe, 0xee, 0x04, 0xf7, + 0xbc, 0x46, 0xe0, 0x85, 0x09, 0x86, 0x56, 0x04, 0x14, 0x1c, 0xc2, 0x43, 0x36, 0x4c, 0xb7, 0x8d, + 0xbd, 0x0d, 0xc7, 0xe0, 0xa1, 0x05, 0x6d, 0xfe, 0x10, 0x50, 0x04, 0x03, 0x7b, 0x16, 0x5e, 0x89, + 0xc1, 0xc2, 0x09, 0xd8, 0x19, 0x2f, 0xd0, 0x93, 0xa7, 0xf5, 0x02, 0xbd, 0x10, 0xfa, 0xdb, 0x70, + 0xb9, 0xed, 0x4a, 0xa6, 0x67, 0x7b, 0x5f, 0x5f, 0x9a, 0xd7, 0x42, 0x5f, 0x9a, 0xe9, 0xe2, 0x4f, + 0xa6, 0x7d, 0xfc, 0x68, 0xba, 0x30, 0x41, 0x39, 0x6c, 0x5e, 0x4a, 0x05, 0xab, 0xc2, 0x2a, 0xc8, + 0x5a, 0x08, 0x46, 0x49, 0x8d, 0x1b, 0x81, 0xc6, 0x2a, 0x1e, 0x74, 0x8f, 0xa7, 0xba, 0xb7, 0x49, + 0x10, 0x35, 0x61, 0x02, 0xfd, 0x0c, 0x3b, 0x3f, 0x61, 0x66, 0xfa, 0x54, 0x03, 0x9c, 0xdd, 0x2f, + 0x8a, 0x94, 0x73, 0x3e, 0x3b, 0x52, 0x0e, 0xfa, 0xb9, 0x2c, 0x3d, 0x3f, 0x62, 0x6b, 0xfa, 0x03, + 0xc5, 0x69, 0x43, 0x61, 0x6d, 0xff, 0xbf, 0xd4, 0x60, 0xb6, 0x9d, 0x93, 0x43, 0x56, 0x3c, 0x3f, + 0xac, 0x0f, 0x40, 0x1f, 0x72, 0xf3, 0xd2, 0x2e, 0x3e, 0x76, 0xb0, 0x5f, 0x39, 0x34, 0x7b, 0x2d, + 0xce, 0x1d, 0x1b, 0xf2, 0x60, 0xcc, 0xef, 0xf9, 0xcd, 0xc0, 0xf6, 0x67, 0x2f, 0x16, 0x4f, 0x55, + 0x2a, 0x28, 0x6b, 0x83, 0x43, 0xe2, 0xa4, 0x35, 0x0a, 0xd4, 0xcf, 0x4b, 0xb1, 0x44, 0x34, 0xa8, + 0x9f, 0xf6, 0x00, 0xc1, 0x41, 0xe7, 0x6e, 0xc2, 0xa4, 0x3a, 0xc8, 0x63, 0xb9, 0x87, 0xff, 0xaa, + 0x06, 0x33, 0xc9, 0x4b, 0x0b, 0x6d, 0x83, 0x4c, 0xf7, 0x2f, 0x84, 0xca, 0x85, 0xa2, 0xef, 0xe3, + 0x36, 0x11, 0x56, 0xe6, 0x9c, 0x07, 0x12, 0x45, 0x58, 0x82, 0x57, 0xed, 0x5f, 0x4a, 0x7d, 0xec, + 0x5f, 0x9e, 0x83, 0xcb, 0xd9, 0x7b, 0x99, 0x72, 0x90, 0x86, 0x6d, 0xbb, 0xf7, 0x85, 0xe4, 0x16, + 0xe5, 0xf0, 0xa2, 0x85, 0x98, 0xd7, 0xe9, 0x3f, 0x06, 0xc9, 0x50, 0xd0, 0xe8, 0x75, 0x18, 0xf7, + 0xfd, 0x6d, 0x1e, 0xe5, 0x53, 0x4c, 0xb2, 0x98, 0xc8, 0x2e, 0x43, 0x85, 0x0a, 0x97, 0x46, 0xf9, + 0x13, 0x47, 0xe0, 0x17, 0x5f, 0xf9, 0xc2, 0x37, 0xae, 0xbd, 0xeb, 0xcb, 0xdf, 0xb8, 0xf6, 0xae, + 0xaf, 0x7d, 0xe3, 0xda, 0xbb, 0x7e, 0xe2, 0xe0, 0x9a, 0xf6, 0x85, 0x83, 0x6b, 0xda, 0x97, 0x0f, + 0xae, 0x69, 0x5f, 0x3b, 0xb8, 0xa6, 0xfd, 0xa7, 0x83, 0x6b, 0xda, 0xcf, 0xff, 0xe7, 0x6b, 0xef, + 0x7a, 0xf5, 0xe9, 0x08, 0xfb, 0x0d, 0x89, 0x34, 0xfa, 0xa7, 0xb3, 0xd3, 0xba, 0x41, 0xb1, 0x4b, + 0xd7, 0x22, 0x86, 0xfd, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x84, 0x95, 0xa7, 0x15, 0x99, 0xeb, + 0x00, 0x00, } func (m *APIServerLogging) Marshal() (dAtA []byte, err error) { @@ -6937,6 +6944,23 @@ func (m *ClusterAutoscaler) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MaxEmptyBulkDelete != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.MaxEmptyBulkDelete)) + i-- + dAtA[i] = 0x60 + } + if m.NewPodScaleUpDelay != nil { + { + size, err := m.NewPodScaleUpDelay.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } if len(m.IgnoreTaints) > 0 { for iNdEx := len(m.IgnoreTaints) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.IgnoreTaints[iNdEx]) @@ -10589,6 +10613,13 @@ func (m *MachineImage) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.UpdateStrategy != nil { + i -= len(*m.UpdateStrategy) + copy(dAtA[i:], *m.UpdateStrategy) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.UpdateStrategy))) + i-- + dAtA[i] = 0x1a + } if len(m.Versions) > 0 { for iNdEx := len(m.Versions) - 1; iNdEx >= 0; iNdEx-- { { @@ -16286,6 +16317,13 @@ func (m *ClusterAutoscaler) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if m.NewPodScaleUpDelay != nil { + l = m.NewPodScaleUpDelay.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.MaxEmptyBulkDelete != nil { + n += 1 + sovGenerated(uint64(*m.MaxEmptyBulkDelete)) + } return n } @@ -17621,6 +17659,10 @@ func (m *MachineImage) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if m.UpdateStrategy != nil { + l = len(*m.UpdateStrategy) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -19872,6 +19914,8 @@ func (this *ClusterAutoscaler) String() string { `MaxNodeProvisionTime:` + strings.Replace(fmt.Sprintf("%v", this.MaxNodeProvisionTime), "Duration", "v11.Duration", 1) + `,`, `MaxGracefulTerminationSeconds:` + valueToStringGenerated(this.MaxGracefulTerminationSeconds) + `,`, `IgnoreTaints:` + fmt.Sprintf("%v", this.IgnoreTaints) + `,`, + `NewPodScaleUpDelay:` + strings.Replace(fmt.Sprintf("%v", this.NewPodScaleUpDelay), "Duration", "v11.Duration", 1) + `,`, + `MaxEmptyBulkDelete:` + valueToStringGenerated(this.MaxEmptyBulkDelete) + `,`, `}`, }, "") return s @@ -20759,6 +20803,7 @@ func (this *MachineImage) String() string { s := strings.Join([]string{`&MachineImage{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Versions:` + repeatedStringForVersions + `,`, + `UpdateStrategy:` + valueToStringGenerated(this.UpdateStrategy) + `,`, `}`, }, "") return s @@ -25738,6 +25783,62 @@ func (m *ClusterAutoscaler) Unmarshal(dAtA []byte) error { } m.IgnoreTaints = append(m.IgnoreTaints, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewPodScaleUpDelay", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.NewPodScaleUpDelay == nil { + m.NewPodScaleUpDelay = &v11.Duration{} + } + if err := m.NewPodScaleUpDelay.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxEmptyBulkDelete", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MaxEmptyBulkDelete = &v default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -36308,6 +36409,39 @@ func (m *MachineImage) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateStrategy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := MachineImageUpdateStrategy(dAtA[iNdEx:postIndex]) + m.UpdateStrategy = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.proto b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.proto index 4e71ab062..859ffa6f3 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.proto +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/generated.proto @@ -406,6 +406,14 @@ message ClusterAutoscaler { // IgnoreTaints specifies a list of taint keys to ignore in node templates when considering to scale a node group. // +optional repeated string ignoreTaints = 10; + + // NewPodScaleUpDelay specifies how long CA should ignore newly created pods before they have to be considered for scale-up. + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.Duration newPodScaleUpDelay = 11; + + // MaxEmptyBulkDelete specifies the maximum number of empty nodes that can be deleted at the same time (default: 10). + // +optional + optional int32 maxEmptyBulkDelete = 12; } // Condition holds the information about the state of a resource. @@ -545,7 +553,7 @@ message ControllerRegistrationDeployment { // +optional optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector seedSelector = 4; - // DeploymentRefs holds references to `ControllerDeployments`. Only one element is support now. + // DeploymentRefs holds references to `ControllerDeployments`. Only one element is supported currently. // +optional repeated DeploymentRef deploymentRefs = 5; } @@ -1556,6 +1564,13 @@ message MachineImage { // +patchMergeKey=version // +patchStrategy=merge repeated MachineImageVersion versions = 2; + + // UpdateStrategy is the update strategy to use for the machine image. Possible values are: + // - patch: update to the latest patch version of the current minor version. + // - minor: update to the latest minor and patch version. + // - major: always update to the overall latest version (default). + // +optional + optional string updateStrategy = 3; } // MachineImageVersion is an expirable version with list of supported container runtimes and interfaces diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/helper/helper.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/helper/helper.go index bbadb5f74..88a41cdb2 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/helper/helper.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/helper/helper.go @@ -16,11 +16,12 @@ package helper import ( "fmt" + "slices" "strconv" "strings" "time" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" corev1 "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -356,6 +357,21 @@ func ShootUsesUnmanagedDNS(shoot *gardencorev1beta1.Shoot) bool { return shoot.Spec.DNS != nil && len(shoot.Spec.DNS.Providers) > 0 && shoot.Spec.DNS.Providers[0].Type != nil && *shoot.Spec.DNS.Providers[0].Type == "unmanaged" } +// ShootNeedsForceDeletion determines whether a Shoot should be force deleted or not. +func ShootNeedsForceDeletion(shoot *gardencorev1beta1.Shoot) bool { + if shoot == nil { + return false + } + + value, ok := shoot.Annotations[v1beta1constants.AnnotationConfirmationForceDeletion] + if !ok { + return false + } + + forceDelete, _ := strconv.ParseBool(value) + return forceDelete +} + // ShootSchedulingProfile returns the scheduling profile of the given Shoot. func ShootSchedulingProfile(shoot *gardencorev1beta1.Shoot) *gardencorev1beta1.SchedulingProfile { if shoot.Spec.Kubernetes.KubeScheduler != nil { @@ -437,7 +453,8 @@ func ShootMachineImageVersionExists(constraint gardencorev1beta1.MachineImage, i return false, 0 } -func toExpirableVersions(versions []gardencorev1beta1.MachineImageVersion) []gardencorev1beta1.ExpirableVersion { +// ToExpirableVersions returns the expirable versions from the given machine image versions. +func ToExpirableVersions(versions []gardencorev1beta1.MachineImageVersion) []gardencorev1beta1.ExpirableVersion { expVersions := []gardencorev1beta1.ExpirableVersion{} for _, version := range versions { expVersions = append(expVersions, version.ExpirableVersion) @@ -445,32 +462,6 @@ func toExpirableVersions(versions []gardencorev1beta1.MachineImageVersion) []gar return expVersions } -// GetLatestQualifyingShootMachineImage determines the latest qualifying version in a machine image and returns that as a ShootMachineImage. -// A version qualifies if its classification is not preview and the version is not expired. -// Older but non-deprecated version is preferred over newer but deprecated one. -func GetLatestQualifyingShootMachineImage(image gardencorev1beta1.MachineImage, predicates ...VersionPredicate) (bool, *gardencorev1beta1.ShootMachineImage, error) { - predicates = append(predicates, FilterExpiredVersion()) - - // Try to find non-deprecated version first - qualifyingVersionFound, latestNonDeprecatedImageVersion, err := GetLatestQualifyingVersion(toExpirableVersions(image.Versions), append(predicates, FilterDeprecatedVersion())...) - if err != nil { - return false, nil, err - } - if qualifyingVersionFound { - return true, &gardencorev1beta1.ShootMachineImage{Name: image.Name, Version: &latestNonDeprecatedImageVersion.Version}, nil - } - - // It looks like there is no non-deprecated version, now look also into the deprecated versions - qualifyingVersionFound, latestImageVersion, err := GetLatestQualifyingVersion(toExpirableVersions(image.Versions), predicates...) - if err != nil { - return false, nil, err - } - if !qualifyingVersionFound { - return false, nil, nil - } - return true, &gardencorev1beta1.ShootMachineImage{Name: image.Name, Version: &latestImageVersion.Version}, nil -} - // FindMachineTypeByName tries to find the machine type details with the given name. If it cannot be found it returns nil. func FindMachineTypeByName(machines []gardencorev1beta1.MachineType, name string) *gardencorev1beta1.MachineType { for _, m := range machines { @@ -527,24 +518,6 @@ func WrapWithLastError(err error, lastError *gardencorev1beta1.LastError) error return fmt.Errorf("last error: %w: %s", err, lastError.Description) } -// IsAPIServerExposureManaged returns true, if the Object is managed by Gardener for API server exposure. -// This indicates to extensions that they should not mutate the object. -// Gardener marks the kube-apiserver Service and Deployment as managed by it when it uses SNI to expose them. -// Deprecated: This function is deprecated and will be removed after Gardener v1.80 has been released. -// TODO(rfranzke): Drop this after v1.80 has been released. -func IsAPIServerExposureManaged(obj metav1.Object) bool { - if obj == nil { - return false - } - - if v, found := obj.GetLabels()[v1beta1constants.LabelAPIServerExposure]; found && - v == v1beta1constants.LabelAPIServerExposureGardenerManaged { - return true - } - - return false -} - // FindPrimaryDNSProvider finds the primary provider among the given `providers`. // It returns the first provider if multiple candidates are found. func FindPrimaryDNSProvider(providers []gardencorev1beta1.DNSProvider) *gardencorev1beta1.DNSProvider { @@ -560,20 +533,89 @@ func FindPrimaryDNSProvider(providers []gardencorev1beta1.DNSProvider) *gardenco // VersionPredicate is a function that evaluates a condition on the given versions. type VersionPredicate func(expirableVersion gardencorev1beta1.ExpirableVersion, version *semver.Version) (bool, error) -// GetKubernetesVersionForPatchUpdate finds the latest Kubernetes patch version for its minor version in the compared -// to the given . Preview and expired versions do not qualify for the kubernetes patch update. In case it does not find a newer patch version, it returns false. Otherwise, -// true and the found version will be returned. -func GetKubernetesVersionForPatchUpdate(cloudProfile *gardencorev1beta1.CloudProfile, currentVersion string) (bool, string, error) { +// GetLatestVersionForPatchAutoUpdate finds the latest patch version for a given for the current minor version from a given slice of versions. +// The current version, preview and expired versions do not qualify. +// In case no newer patch version is found, returns false and an empty string. Otherwise, returns true and the found version. +func GetLatestVersionForPatchAutoUpdate(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { currentSemVerVersion, err := semver.NewVersion(currentVersion) if err != nil { return false, "", err } - qualifyingVersionFound, latestVersion, err := GetLatestQualifyingVersion(cloudProfile.Spec.Kubernetes.Versions, FilterDifferentMajorMinorVersion(*currentSemVerVersion), FilterSameVersion(*currentSemVerVersion), FilterExpiredVersion()) + predicates := []VersionPredicate{FilterDifferentMajorMinorVersionAndLowerPatchVersionsOfSameMinor(*currentSemVerVersion)} + + return getVersionForAutoUpdate(versions, currentSemVerVersion, predicates) +} + +// GetLatestVersionForMinorAutoUpdate finds the latest minor with the latest patch version higher than a given for the current major version from a given slice of versions. +// Returns the highest patch version for the current minor in case the current version is not the highest patch version yet. +// The current version, preview and expired versions do not qualify. +// In case no newer version is found, returns false and an empty string. Otherwise, returns true and the found version. +func GetLatestVersionForMinorAutoUpdate(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { + // always first check if there is a higher patch version available + found, version, err := GetLatestVersionForPatchAutoUpdate(versions, currentVersion) + if found { + return found, version, nil + } + if err != nil { + return false, version, err + } + + currentSemVerVersion, err := semver.NewVersion(currentVersion) if err != nil { return false, "", err } - // latest version cannot be found. Do not return an error, but allow for minor upgrade if Shoot's machine image version is expired. + + predicates := []VersionPredicate{FilterDifferentMajorVersion(*currentSemVerVersion)} + + return getVersionForAutoUpdate(versions, currentSemVerVersion, predicates) +} + +// GetOverallLatestVersionForAutoUpdate finds the overall latest version higher than a given for the current major version from a given slice of versions. +// Returns the highest patch version for the current minor in case the current version is not the highest patch version yet. +// The current, preview and expired versions do not qualify. +// In case no newer version is found, returns false and an empty string. Otherwise, returns true and the found version. +func GetOverallLatestVersionForAutoUpdate(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { + // always first check if there is a higher patch version available to update to + found, version, err := GetLatestVersionForPatchAutoUpdate(versions, currentVersion) + if found { + return found, version, nil + } + if err != nil { + return false, version, err + } + + currentSemVerVersion, err := semver.NewVersion(currentVersion) + if err != nil { + return false, "", err + } + + // if there is no higher patch version available, get the overall latest + return getVersionForAutoUpdate(versions, currentSemVerVersion, []VersionPredicate{}) +} + +// getVersionForAutoUpdate finds the latest eligible version higher than a given from a slice of versions. +// Versions <= the current version, preview and expired versions do not qualify for patch updates. +// First tries to find a non-deprecated version. +// In case no newer patch version is found, returns false and an empty string. Otherwise, returns true and the found version. +func getVersionForAutoUpdate(versions []gardencorev1beta1.ExpirableVersion, currentSemVerVersion *semver.Version, predicates []VersionPredicate) (bool, string, error) { + versionPredicates := append([]VersionPredicate{FilterExpiredVersion(), FilterSameVersion(*currentSemVerVersion), FilterLowerVersion(*currentSemVerVersion)}, predicates...) + + // Try to find non-deprecated version first + qualifyingVersionFound, latestNonDeprecatedImageVersion, err := GetLatestQualifyingVersion(versions, append(versionPredicates, FilterDeprecatedVersion())...) + if err != nil { + return false, "", err + } + if qualifyingVersionFound { + return true, latestNonDeprecatedImageVersion.Version, nil + } + + // otherwise, also consider deprecated versions + qualifyingVersionFound, latestVersion, err := GetLatestQualifyingVersion(versions, versionPredicates...) + if err != nil { + return false, "", err + } + // latest version cannot be found. Do not return an error, but allow for forceful upgrade if Shoot's version is expired. if !qualifyingVersionFound { return false, "", nil } @@ -581,24 +623,28 @@ func GetKubernetesVersionForPatchUpdate(cloudProfile *gardencorev1beta1.CloudPro return true, latestVersion.Version, nil } -// GetKubernetesVersionForMinorUpdate finds a Kubernetes version in the that qualifies for a Kubernetes minor level update given a . -// A qualifying version is a non-preview version having the minor version increased by exactly one version. -// In case the consecutive minor version has only expired versions, picks the latest expired version (will do another minor update during the next maintenance time) +// GetVersionForForcefulUpdateToConsecutiveMinor finds a version from a slice of expirable versions that qualifies for a minor level update given a . +// A qualifying version is a non-preview version having the minor version increased by exactly one version (required for Kubernetes version upgrades). +// In case the consecutive minor version has only expired versions, picks the latest expired version (will try another update during the next maintenance time). // If a version can be found, returns true and the qualifying patch version of the next minor version. -// In case it does not find a version, it returns false. -func GetKubernetesVersionForMinorUpdate(cloudProfile *gardencorev1beta1.CloudProfile, currentVersion string) (bool, string, error) { +// In case it does not find a version, it returns false and an empty string. +func GetVersionForForcefulUpdateToConsecutiveMinor(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { currentSemVerVersion, err := semver.NewVersion(currentVersion) if err != nil { return false, "", err } - qualifyingVersionFound, latestVersion, err := GetLatestQualifyingVersion(cloudProfile.Spec.Kubernetes.Versions, FilterNonConsecutiveMinorVersion(*currentSemVerVersion), FilterSameVersion(*currentSemVerVersion), FilterExpiredVersion()) + // filters out any version that does not have minor version +1 + predicates := []VersionPredicate{FilterDifferentMajorVersion(*currentSemVerVersion), FilterNonConsecutiveMinorVersion(*currentSemVerVersion)} + + qualifyingVersionFound, latestVersion, err := GetLatestQualifyingVersion(versions, append(predicates, FilterExpiredVersion())...) if err != nil { return false, "", err } + + // if no qualifying version is found, allow force update to an expired version if !qualifyingVersionFound { - // in case there are only expired versions in the consecutive minor version, pick the latest expired version - qualifyingVersionFound, latestVersion, err = GetLatestQualifyingVersion(cloudProfile.Spec.Kubernetes.Versions, FilterNonConsecutiveMinorVersion(*currentSemVerVersion), FilterSameVersion(*currentSemVerVersion)) + qualifyingVersionFound, latestVersion, err = GetLatestQualifyingVersion(versions, predicates...) if err != nil { return false, "", err } @@ -610,7 +656,78 @@ func GetKubernetesVersionForMinorUpdate(cloudProfile *gardencorev1beta1.CloudPro return true, latestVersion.Version, nil } -// GetLatestQualifyingVersion returns the latest expirable version from a set of expirable versions +// GetVersionForForcefulUpdateToNextHigherMinor finds a version from a slice of expirable versions that qualifies for a minor level update given a . +// A qualifying version is the highest non-preview version with the next higher minor version from the given slice of versions. +// In case the consecutive minor version has only expired versions, picks the latest expired version (will try another update during the next maintenance time). +// If a version can be found, returns true and the qualifying version. +// In case it does not find a version, it returns false and an empty string. +func GetVersionForForcefulUpdateToNextHigherMinor(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { + currentSemVerVersion, err := semver.NewVersion(currentVersion) + if err != nil { + return false, "", err + } + + predicates := []VersionPredicate{FilterDifferentMajorVersion(*currentSemVerVersion), FilterEqualAndSmallerMinorVersion(*currentSemVerVersion)} + + // prefer non-expired version + return getVersionForMachineImageForceUpdate(versions, func(v semver.Version) int64 { return int64(v.Minor()) }, currentSemVerVersion, predicates) +} + +// GetVersionForForcefulUpdateToNextHigherMajor finds a version from a slice of expirable versions that qualifies for a major level update given a . +// A qualifying version is a non-preview version with the next (as defined in the CloudProfile for the image) higher major version. +// In case the next major version has only expired versions, picks the latest expired version (will try another update during the next maintenance time). +// If a version can be found, returns true and the qualifying version of the next major version. +// In case it does not find a version, it returns false and an empty string. +func GetVersionForForcefulUpdateToNextHigherMajor(versions []gardencorev1beta1.ExpirableVersion, currentVersion string) (bool, string, error) { + currentSemVerVersion, err := semver.NewVersion(currentVersion) + if err != nil { + return false, "", err + } + + predicates := []VersionPredicate{FilterEqualAndSmallerMajorVersion(*currentSemVerVersion)} + + // prefer non-expired version + return getVersionForMachineImageForceUpdate(versions, func(v semver.Version) int64 { return int64(v.Major()) }, currentSemVerVersion, predicates) +} + +// getVersionForMachineImageForceUpdate finds a version from a slice of expirable versions that qualifies for an update given a . +// In contrast to determining a version for an auto-update, also allows update to an expired version in case a not-expired version cannot be determined. +// Used only for machine image updates, as finds a qualifying version from the next higher minor version, which is not necessarily consecutive (n+1). +func getVersionForMachineImageForceUpdate(versions []gardencorev1beta1.ExpirableVersion, getMajorOrMinor GetMajorOrMinor, currentSemVerVersion *semver.Version, predicates []VersionPredicate) (bool, string, error) { + foundVersion, qualifyingVersion, nextMinorOrMajorVersion, err := GetQualifyingVersionForNextHigher(versions, getMajorOrMinor, currentSemVerVersion, append(predicates, FilterExpiredVersion())...) + if err != nil { + return false, "", err + } + + skippedNextMajorMinor := false + if foundVersion { + parse, err := semver.NewVersion(qualifyingVersion.Version) + if err != nil { + return false, "", err + } + skippedNextMajorMinor = getMajorOrMinor(*parse) > nextMinorOrMajorVersion + } + + // Two options when allowing updates to expired versions + // 1) No higher non-expired qualifying version could be found at all + // 2) Found a qualifying non-expired version, but we skipped the next minor/major. + // Potentially skipped expired versions in the next minor/major that qualify. + // Prefer update to expired version in next minor/major instead of skipping over minor/major altogether. + // Example: current version: 1.1.0, qualifying version : 1.4.1, next minor: 2. We skipped over the next minor which might have qualifying expired versions. + if !foundVersion || skippedNextMajorMinor { + foundVersion, qualifyingVersion, _, err = GetQualifyingVersionForNextHigher(versions, getMajorOrMinor, currentSemVerVersion, predicates...) + if err != nil { + return false, "", err + } + if !foundVersion { + return false, "", nil + } + } + + return true, qualifyingVersion.Version, nil +} + +// GetLatestQualifyingVersion returns the latest expirable version from a set of expirable versions. // A version qualifies if its classification is not preview and the optional predicate does not filter out the version. // If the predicate returns true, the version is not considered for the latest qualifying version. func GetLatestQualifyingVersion(versions []gardencorev1beta1.ExpirableVersion, predicate ...VersionPredicate) (qualifyingVersionFound bool, latest *gardencorev1beta1.ExpirableVersion, err error) { @@ -655,9 +772,82 @@ OUTER: return true, latestVersion, nil } -// FilterDifferentMajorMinorVersion returns a VersionPredicate(closure) that evaluates whether a given version v has a different same major.minor version compared to the currentSemVerVersion -// returns true if v has a different major.minor version -func FilterDifferentMajorMinorVersion(currentSemVerVersion semver.Version) VersionPredicate { +// GetMajorOrMinor returns either the major or the minor version from a semVer version. +type GetMajorOrMinor func(v semver.Version) int64 + +// GetQualifyingVersionForNextHigher returns the latest expirable version for the next higher {minor/major} (not necessarily consecutive n+1) version from a set of expirable versions. +// A version qualifies if its classification is not preview and the optional predicate does not filter out the version. +// If the predicate returns true, the version is not considered for the latest qualifying version. +func GetQualifyingVersionForNextHigher(versions []gardencorev1beta1.ExpirableVersion, majorOrMinor GetMajorOrMinor, currentSemVerVersion *semver.Version, predicates ...VersionPredicate) (qualifyingVersionFound bool, qualifyingVersion *gardencorev1beta1.ExpirableVersion, nextMinorOrMajor int64, err error) { + // How to find the highest version with the next higher (not necessarily consecutive n+1) minor version (if the next higher minor version has no qualifying version, skip it to avoid consecutive updates) + // 1) Sort the versions in ascending order + // 2) Loop over the sorted array until the minor version changes (select all versions for the next higher minor) + // - predicates filter out version with minor/major <= current_minor/major + // 3) Then select the last version in the array (that's the highest) + + slices.SortFunc(versions, func(a, b gardencorev1beta1.ExpirableVersion) int { + return semver.MustParse(a.Version).Compare(semver.MustParse(b.Version)) + }) + + var ( + highestVersionNextHigherMinorOrMajor *semver.Version + nextMajorOrMinorVersion int64 = -1 + expirableVersionNextHigherMinorOrMajor = gardencorev1beta1.ExpirableVersion{} + ) + +OUTER: + for _, v := range versions { + parse, err := semver.NewVersion(v.Version) + if err != nil { + return false, nil, 0, err + } + + // Determine the next higher minor/major version, even though all versions from that minor/major might be filtered (e.g, all expired) + // That's required so that the caller can determine if the next minor/major version has been skipped or not. + if majorOrMinor(*parse) > majorOrMinor(*currentSemVerVersion) && (majorOrMinor(*parse) < nextMajorOrMinorVersion || nextMajorOrMinorVersion == -1) { + nextMajorOrMinorVersion = majorOrMinor(*parse) + } + + // never update to preview versions + if v.Classification != nil && *v.Classification == gardencorev1beta1.ClassificationPreview { + continue + } + + for _, p := range predicates { + if p == nil { + continue + } + + shouldFilter, err := p(v, parse) + if err != nil { + return false, nil, nextMajorOrMinorVersion, fmt.Errorf("error while evaluation predicate: %w", err) + } + if shouldFilter { + continue OUTER + } + } + + // last version is the highest version for next larger minor/major + if highestVersionNextHigherMinorOrMajor != nil && majorOrMinor(*parse) > majorOrMinor(*highestVersionNextHigherMinorOrMajor) { + break + } + highestVersionNextHigherMinorOrMajor = parse + expirableVersionNextHigherMinorOrMajor = v + } + + // unable to find qualified versions + if highestVersionNextHigherMinorOrMajor == nil { + return false, nil, nextMajorOrMinorVersion, nil + } + return true, &expirableVersionNextHigherMinorOrMajor, nextMajorOrMinorVersion, nil +} + +// FilterDifferentMajorMinorVersionAndLowerPatchVersionsOfSameMinor returns a VersionPredicate(closure) that returns true if a given version v +// - has a different major.minor version compared to the currentSemVerVersion +// - has a lower patch version (acts as >= relational operator) +// +// Uses the tilde range operator. +func FilterDifferentMajorMinorVersionAndLowerPatchVersionsOfSameMinor(currentSemVerVersion semver.Version) VersionPredicate { return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { isWithinRange, err := versionutils.CompareVersions(v.String(), "~", currentSemVerVersion.String()) if err != nil { @@ -668,15 +858,12 @@ func FilterDifferentMajorMinorVersion(currentSemVerVersion semver.Version) Versi } // FilterNonConsecutiveMinorVersion returns a VersionPredicate(closure) that evaluates whether a given version v has a consecutive minor version compared to the currentSemVerVersion -// returns true if v does not have a consecutive minor version +// - implicitly, therefore also versions cannot be smaller than the current version +// +// returns true if v does not have a consecutive minor version. func FilterNonConsecutiveMinorVersion(currentSemVerVersion semver.Version) VersionPredicate { return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { - isWithinRange, err := versionutils.CompareVersions(v.String(), "^", currentSemVerVersion.String()) - if err != nil { - return true, err - } - - if !isWithinRange { + if v.Major() != currentSemVerVersion.Major() { return true, nil } @@ -685,8 +872,32 @@ func FilterNonConsecutiveMinorVersion(currentSemVerVersion semver.Version) Versi } } -// FilterSameVersion returns a VersionPredicate(closure) that evaluates whether a given version v is equal to the currentSemVerVersion -// returns true if it is equal +// FilterDifferentMajorVersion returns a VersionPredicate(closure) that evaluates whether a given version v has the same major version compared to the currentSemVerVersion. +// Returns true if v does not have the same major version. +func FilterDifferentMajorVersion(currentSemVerVersion semver.Version) VersionPredicate { + return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { + return v.Major() != currentSemVerVersion.Major(), nil + } +} + +// FilterEqualAndSmallerMajorVersion returns a VersionPredicate(closure) that evaluates whether a given version v has a smaller major version compared to the currentSemVerVersion. +// Returns true if v has a smaller or equal major version. +func FilterEqualAndSmallerMajorVersion(currentSemVerVersion semver.Version) VersionPredicate { + return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { + return v.Major() <= currentSemVerVersion.Major(), nil + } +} + +// FilterEqualAndSmallerMinorVersion returns a VersionPredicate(closure) that evaluates whether a given version v has a smaller or equal minor version compared to the currentSemVerVersion. +// Returns true if v has a smaller or equal minor version. +func FilterEqualAndSmallerMinorVersion(currentSemVerVersion semver.Version) VersionPredicate { + return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { + return v.Minor() <= currentSemVerVersion.Minor(), nil + } +} + +// FilterSameVersion returns a VersionPredicate(closure) that evaluates whether a given version v is equal to the currentSemVerVersion. +// returns true if it is equal. func FilterSameVersion(currentSemVerVersion semver.Version) VersionPredicate { return func(_ gardencorev1beta1.ExpirableVersion, v *semver.Version) (bool, error) { return v.Equal(¤tSemVerVersion), nil diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_cloudprofile.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_cloudprofile.go index 6617a8bdb..e8071afa2 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_cloudprofile.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_cloudprofile.go @@ -113,6 +113,12 @@ type MachineImage struct { // +patchMergeKey=version // +patchStrategy=merge Versions []MachineImageVersion `json:"versions" patchStrategy:"merge" patchMergeKey:"version" protobuf:"bytes,2,rep,name=versions"` + // UpdateStrategy is the update strategy to use for the machine image. Possible values are: + // - patch: update to the latest patch version of the current minor version. + // - minor: update to the latest minor and patch version. + // - major: always update to the overall latest version (default). + // +optional + UpdateStrategy *MachineImageUpdateStrategy `json:"updateStrategy,omitempty" protobuf:"bytes,3,opt,name=updateStrategy,casttype=MachineImageUpdateStrategy"` } // MachineImageVersion is an expirable version with list of supported container runtimes and interfaces @@ -245,3 +251,17 @@ const ( // and will eventually expire. ClassificationDeprecated VersionClassification = "deprecated" ) + +// MachineImageUpdateStrategy is the update strategy to use for a machine image +type MachineImageUpdateStrategy string + +const ( + // UpdateStrategyPatch indicates that auto-updates are performed to the latest patch version of the current minor version. + // When using an expired version during the maintenance window, force updates to the latest patch of the next (not necessarily consecutive) minor when using an expired version. + UpdateStrategyPatch MachineImageUpdateStrategy = "patch" + // UpdateStrategyMinor indicates that auto-updates are performed to the latest patch and minor version of the current major version. + // When using an expired version during the maintenance window, force updates to the latest minor and patch of the next (not necessarily consecutive) major version. + UpdateStrategyMinor MachineImageUpdateStrategy = "minor" + // UpdateStrategyMajor indicates that auto-updates are performed always to the overall latest version. + UpdateStrategyMajor MachineImageUpdateStrategy = "major" +) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_common.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_common.go index b2b9e36d4..a18eced5d 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_common.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_common.go @@ -14,7 +14,9 @@ package v1beta1 -import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) // ErrorCode is a string alias. type ErrorCode string @@ -135,23 +137,23 @@ const ( ) const ( - // EventReconciling indicates that the a Reconcile operation started. + // EventReconciling indicates that the Reconcile operation started. EventReconciling = "Reconciling" - // EventReconciled indicates that the a Reconcile operation was successful. + // EventReconciled indicates that the Reconcile operation was successful. EventReconciled = "Reconciled" - // EventReconcileError indicates that the a Reconcile operation failed. + // EventReconcileError indicates that the Reconcile operation failed. EventReconcileError = "ReconcileError" - // EventDeleting indicates that the a Delete operation started. + // EventDeleting indicates that the Delete operation started. EventDeleting = "Deleting" - // EventDeleted indicates that the a Delete operation was successful. + // EventDeleted indicates that the Delete operation was successful. EventDeleted = "Deleted" - // EventDeleteError indicates that the a Delete operation failed. + // EventDeleteError indicates that the Delete operation failed. EventDeleteError = "DeleteError" - // EventPrepareMigration indicates that a Prepare Migration operation started. + // EventPrepareMigration indicates that the Prepare Migration operation started. EventPrepareMigration = "PrepareMigration" - // EventMigrationPrepared indicates that Migration preparation was successful. + // EventMigrationPrepared indicates that the Migration preparation was successful. EventMigrationPrepared = "MigrationPrepared" - // EventMigrationPreparationFailed indicates that Migration preparation failed. + // EventMigrationPreparationFailed indicates that the Migration preparation failed. EventMigrationPreparationFailed = "MigrationPreparationFailed" ) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_controllerregistration.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_controllerregistration.go index a80c13707..70e39b0d3 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_controllerregistration.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_controllerregistration.go @@ -104,7 +104,7 @@ type ControllerRegistrationDeployment struct { // An empty list means that all seeds are selected. // +optional SeedSelector *metav1.LabelSelector `json:"seedSelector,omitempty" protobuf:"bytes,4,opt,name=seedSelector"` - // DeploymentRefs holds references to `ControllerDeployments`. Only one element is support now. + // DeploymentRefs holds references to `ControllerDeployments`. Only one element is supported currently. // +optional DeploymentRefs []DeploymentRef `json:"deploymentRefs,omitempty" protobuf:"bytes,5,opt,name=deploymentRefs"` } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_shoot.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_shoot.go index a7c5f15da..ebb9c2921 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_shoot.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/types_shoot.go @@ -593,6 +593,12 @@ type ClusterAutoscaler struct { // IgnoreTaints specifies a list of taint keys to ignore in node templates when considering to scale a node group. // +optional IgnoreTaints []string `json:"ignoreTaints,omitempty" protobuf:"bytes,10,opt,name=ignoreTaints"` + // NewPodScaleUpDelay specifies how long CA should ignore newly created pods before they have to be considered for scale-up. + // +optional + NewPodScaleUpDelay *metav1.Duration `json:"newPodScaleUpDelay,omitempty" protobuf:"bytes,11,opt,name=newPodScaleUpDelay"` + // MaxEmptyBulkDelete specifies the maximum number of empty nodes that can be deleted at the same time (default: 10). + // +optional + MaxEmptyBulkDelete *int32 `json:"maxEmptyBulkDelete,omitempty" protobuf:"varint,12,opt,name=maxEmptyBulkDelete"` } // ExpanderMode is type used for Expander values @@ -1550,9 +1556,9 @@ type SSHAccess struct { var ( // DefaultWorkerMaxSurge is the default value for Worker MaxSurge. - DefaultWorkerMaxSurge = intstr.FromInt(1) + DefaultWorkerMaxSurge = intstr.FromInt32(1) // DefaultWorkerMaxUnavailable is the default value for Worker MaxUnavailable. - DefaultWorkerMaxUnavailable = intstr.FromInt(0) + DefaultWorkerMaxUnavailable = intstr.FromInt32(0) // DefaultWorkerSystemComponentsAllow is the default value for Worker AllowSystemComponents DefaultWorkerSystemComponentsAllow = true ) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.conversion.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.conversion.go index 573685ddf..ed55f8a57 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.conversion.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.conversion.go @@ -2328,6 +2328,8 @@ func autoConvert_v1beta1_ClusterAutoscaler_To_core_ClusterAutoscaler(in *Cluster out.MaxNodeProvisionTime = (*metav1.Duration)(unsafe.Pointer(in.MaxNodeProvisionTime)) out.MaxGracefulTerminationSeconds = (*int32)(unsafe.Pointer(in.MaxGracefulTerminationSeconds)) out.IgnoreTaints = *(*[]string)(unsafe.Pointer(&in.IgnoreTaints)) + out.NewPodScaleUpDelay = (*metav1.Duration)(unsafe.Pointer(in.NewPodScaleUpDelay)) + out.MaxEmptyBulkDelete = (*int32)(unsafe.Pointer(in.MaxEmptyBulkDelete)) return nil } @@ -2347,6 +2349,8 @@ func autoConvert_core_ClusterAutoscaler_To_v1beta1_ClusterAutoscaler(in *core.Cl out.MaxNodeProvisionTime = (*metav1.Duration)(unsafe.Pointer(in.MaxNodeProvisionTime)) out.MaxGracefulTerminationSeconds = (*int32)(unsafe.Pointer(in.MaxGracefulTerminationSeconds)) out.IgnoreTaints = *(*[]string)(unsafe.Pointer(&in.IgnoreTaints)) + out.NewPodScaleUpDelay = (*metav1.Duration)(unsafe.Pointer(in.NewPodScaleUpDelay)) + out.MaxEmptyBulkDelete = (*int32)(unsafe.Pointer(in.MaxEmptyBulkDelete)) return nil } @@ -4010,6 +4014,7 @@ func Convert_core_MachineControllerManagerSettings_To_v1beta1_MachineControllerM func autoConvert_v1beta1_MachineImage_To_core_MachineImage(in *MachineImage, out *core.MachineImage, s conversion.Scope) error { out.Name = in.Name out.Versions = *(*[]core.MachineImageVersion)(unsafe.Pointer(&in.Versions)) + out.UpdateStrategy = (*core.MachineImageUpdateStrategy)(unsafe.Pointer(in.UpdateStrategy)) return nil } @@ -4021,6 +4026,7 @@ func Convert_v1beta1_MachineImage_To_core_MachineImage(in *MachineImage, out *co func autoConvert_core_MachineImage_To_v1beta1_MachineImage(in *core.MachineImage, out *MachineImage, s conversion.Scope) error { out.Name = in.Name out.Versions = *(*[]MachineImageVersion)(unsafe.Pointer(&in.Versions)) + out.UpdateStrategy = (*MachineImageUpdateStrategy)(unsafe.Pointer(in.UpdateStrategy)) return nil } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.deepcopy.go index 2cc2615bf..add5f11b6 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.deepcopy.go @@ -729,6 +729,16 @@ func (in *ClusterAutoscaler) DeepCopyInto(out *ClusterAutoscaler) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NewPodScaleUpDelay != nil { + in, out := &in.NewPodScaleUpDelay, &out.NewPodScaleUpDelay + *out = new(metav1.Duration) + **out = **in + } + if in.MaxEmptyBulkDelete != nil { + in, out := &in.MaxEmptyBulkDelete, &out.MaxEmptyBulkDelete + *out = new(int32) + **out = **in + } return } @@ -2631,6 +2641,11 @@ func (in *MachineImage) DeepCopyInto(out *MachineImage) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.UpdateStrategy != nil { + in, out := &in.UpdateStrategy, &out.UpdateStrategy + *out = new(MachineImageUpdateStrategy) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.defaults.go b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.defaults.go index 752ae794d..64aeb9796 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.defaults.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/v1beta1/zz_generated.defaults.go @@ -47,6 +47,7 @@ func RegisterDefaults(scheme *runtime.Scheme) error { func SetObjectDefaults_CloudProfile(in *CloudProfile) { for i := range in.Spec.MachineImages { a := &in.Spec.MachineImages[i] + SetDefaults_MachineImage(a) for j := range a.Versions { b := &a.Versions[j] SetDefaults_MachineImageVersion(b) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/core/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/apis/core/zz_generated.deepcopy.go index f31320801..1b3a338ba 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/core/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/core/zz_generated.deepcopy.go @@ -729,6 +729,16 @@ func (in *ClusterAutoscaler) DeepCopyInto(out *ClusterAutoscaler) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NewPodScaleUpDelay != nil { + in, out := &in.NewPodScaleUpDelay, &out.NewPodScaleUpDelay + *out = new(metav1.Duration) + **out = **in + } + if in.MaxEmptyBulkDelete != nil { + in, out := &in.MaxEmptyBulkDelete, &out.MaxEmptyBulkDelete + *out = new(int32) + **out = **in + } return } @@ -2626,6 +2636,11 @@ func (in *MachineImage) DeepCopyInto(out *MachineImage) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.UpdateStrategy != nil { + in, out := &in.UpdateStrategy, &out.UpdateStrategy + *out = new(MachineImageUpdateStrategy) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/helper/filecodec.go b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/helper/filecodec.go index e085276e3..bb07d173a 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/helper/filecodec.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/helper/filecodec.go @@ -15,20 +15,15 @@ package helper import ( - "bytes" - "compress/gzip" "encoding/base64" "fmt" - "io" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" ) var validFileCodecIDs = map[extensionsv1alpha1.FileCodecID]struct{}{ - extensionsv1alpha1.PlainFileCodecID: {}, - extensionsv1alpha1.B64FileCodecID: {}, - extensionsv1alpha1.GZIPFileCodecID: {}, - extensionsv1alpha1.GZIPB64FileCodecID: {}, + extensionsv1alpha1.PlainFileCodecID: {}, + extensionsv1alpha1.B64FileCodecID: {}, } // FileCodec is a codec to en- and decode data in cloud-init scripts with.j @@ -42,8 +37,6 @@ var ( PlainFileCodec FileCodec = plainFileCodec{} // B64FileCodec is the base64 FileCodec. B64FileCodec FileCodec = b64FileCodec{} - // GZIPFileCodec is the gzip FileCodec. - GZIPFileCodec FileCodec = gzipFileCodec{} ) type plainFileCodec struct{} @@ -71,29 +64,6 @@ func (b64FileCodec) Decode(data []byte) ([]byte, error) { return dst[:n], err } -type gzipFileCodec struct{} - -func (gzipFileCodec) Encode(data []byte) ([]byte, error) { - var out bytes.Buffer - w := gzip.NewWriter(&out) - if _, err := w.Write(data); err != nil { - return nil, err - } - if err := w.Close(); err != nil { - return nil, err - } - return out.Bytes(), nil -} - -func (gzipFileCodec) Decode(data []byte) ([]byte, error) { - r, err := gzip.NewReader(bytes.NewReader(data)) - if err != nil { - return nil, err - } - defer func() { _ = r.Close() }() - return io.ReadAll(r) -} - // ParseFileCodecID tries to parse a string into a FileCodecID. func ParseFileCodecID(s string) (extensionsv1alpha1.FileCodecID, error) { id := extensionsv1alpha1.FileCodecID(s) @@ -106,7 +76,6 @@ func ParseFileCodecID(s string) (extensionsv1alpha1.FileCodecID, error) { var fileCodecIDToFileCodec = map[extensionsv1alpha1.FileCodecID]FileCodec{ extensionsv1alpha1.PlainFileCodecID: PlainFileCodec, extensionsv1alpha1.B64FileCodecID: B64FileCodec, - extensionsv1alpha1.GZIPFileCodecID: GZIPFileCodec, } // FileCodecForID retrieves the FileCodec for the given FileCodecID. diff --git a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/types_operatingsystemconfig.go b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/types_operatingsystemconfig.go index 8ec7c161f..3d98318d2 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/types_operatingsystemconfig.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/types_operatingsystemconfig.go @@ -53,7 +53,6 @@ func (o *OperatingSystemConfig) GetExtensionSpec() Spec { // GetExtensionPurpose implements Object. func (o *OperatingSystemConfigSpec) GetExtensionPurpose() *string { return (*string)(&o.Purpose) - } // GetExtensionStatus implements Object. @@ -89,6 +88,7 @@ type OperatingSystemConfigSpec struct { // are asked to use it when determining the .status.command of this resource. For example, if for CoreOS // the reload-path might be "/var/lib/config"; then the controller shall set .status.command to // "/usr/bin/coreos-cloudinit --from-file=/var/lib/config". + // TODO(rfranzke): Deprecate this field once UseGardenerNodeAgent feature gate is promoted to GA. // +optional ReloadConfigFilePath *string `json:"reloadConfigFilePath,omitempty"` // Units is a list of unit for the operating system configuration (usually, a systemd unit). @@ -109,7 +109,7 @@ type Unit struct { Name string `json:"name"` // Command is the unit's command. // +optional - Command *string `json:"command,omitempty"` + Command *UnitCommand `json:"command,omitempty"` // Enable describes whether the unit is enabled or not. // +optional Enable *bool `json:"enable,omitempty"` @@ -121,6 +121,29 @@ type Unit struct { // +patchStrategy=merge // +optional DropIns []DropIn `json:"dropIns,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + // Files is a list of files the unit depends on that should get written to the host's file system. + // If any file changes a restart of the dependent unit will be triggered. + // +patchMergeKey=path + // +patchStrategy=merge + // +optional + Files []File `json:"files,omitempty" patchStrategy:"merge" patchMergeKey:"path"` +} + +// UnitCommand is a string alias. +type UnitCommand string + +const ( + // CommandStart is the 'start' command for a unit. + CommandStart UnitCommand = "start" + // CommandRestart is the 'restart' command for a unit. + CommandRestart UnitCommand = "restart" + // CommandStop is the 'stop' command for a unit. + CommandStop UnitCommand = "stop" +) + +// UnitCommandPtr returns a pointer to the provided unit command. +func UnitCommandPtr(c UnitCommand) *UnitCommand { + return &c } // DropIn is a drop-in configuration for a systemd unit. @@ -156,6 +179,9 @@ type FileContent struct { // This for example can be used to manipulate the clear-text content before it reaches the node. // +optional TransmitUnencoded *bool `json:"transmitUnencoded,omitempty"` + // ImageRef describes a container image which contains a file. + // +optional + ImageRef *FileContentImageRef `json:"imageRef,omitempty"` } // FileContentSecretRef contains keys for referencing a file content's data from a secret in the same namespace. @@ -174,10 +200,28 @@ type FileContentInline struct { Data string `json:"data"` } +// FileContentImageRef describes a container image which contains a file +type FileContentImageRef struct { + // Image contains the container image repository with tag. + Image string `json:"image"` + // FilePathInImage contains the path in the image to the file that should be extracted. + FilePathInImage string `json:"filePathInImage"` +} + // OperatingSystemConfigStatus is the status for a OperatingSystemConfig resource. type OperatingSystemConfigStatus struct { // DefaultStatus is a structure containing common fields used by all extension resources. DefaultStatus `json:",inline"` + // ExtensionUnits is a list of additional systemd units provided by the extension. + // +patchMergeKey=name + // +patchStrategy=merge + // +optional + ExtensionUnits []Unit `json:"extensionUnits,omitempty" patchStrategy:"merge" patchMergeKey:"name"` + // ExtensionFiles is a list of additional files provided by the extension. + // +patchMergeKey=path + // +patchStrategy=merge + // +optional + ExtensionFiles []File `json:"extensionFiles,omitempty" patchStrategy:"merge" patchMergeKey:"path"` // CloudConfig is a structure for containing the generated output for the given operating system // config spec. It contains a reference to a secret as the result may contain confidential data. // +optional @@ -185,14 +229,17 @@ type OperatingSystemConfigStatus struct { // Command is the command whose execution renews/reloads the cloud config on an existing VM, e.g. // "/usr/bin/reload-cloud-config -from-file=". The is optionally provided by Gardener // in the .spec.reloadConfigFilePath field. + // TODO(rfranzke): Deprecate this field once UseGardenerNodeAgent feature gate is promoted to GA. // +optional Command *string `json:"command,omitempty"` // Units is a list of systemd unit names that are part of the generated Cloud Config and shall be // restarted when a new version has been downloaded. + // TODO(rfranzke): Deprecate this field once UseGardenerNodeAgent feature gate is promoted to GA. // +optional Units []string `json:"units,omitempty"` // Files is a list of file paths that are part of the generated Cloud Config and shall be // written to the host's file system. + // TODO(rfranzke): Deprecate this field once UseGardenerNodeAgent feature gate is promoted to GA. // +optional Files []string `json:"files,omitempty"` } @@ -249,8 +296,4 @@ const ( PlainFileCodecID FileCodecID = "" // B64FileCodecID is the base64 file codec id. B64FileCodecID FileCodecID = "b64" - // GZIPFileCodecID is the gzip file codec id. - GZIPFileCodecID FileCodecID = "gzip" - // GZIPB64FileCodecID is the gzip combined with base64 codec id. - GZIPB64FileCodecID FileCodecID = "gzip+b64" ) diff --git a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/zz_generated.deepcopy.go index 3b949bd6b..fe15d3895 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/extensions/v1alpha1/zz_generated.deepcopy.go @@ -1056,6 +1056,11 @@ func (in *FileContent) DeepCopyInto(out *FileContent) { *out = new(bool) **out = **in } + if in.ImageRef != nil { + in, out := &in.ImageRef, &out.ImageRef + *out = new(FileContentImageRef) + **out = **in + } return } @@ -1069,6 +1074,22 @@ func (in *FileContent) DeepCopy() *FileContent { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileContentImageRef) DeepCopyInto(out *FileContentImageRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileContentImageRef. +func (in *FileContentImageRef) DeepCopy() *FileContentImageRef { + if in == nil { + return nil + } + out := new(FileContentImageRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FileContentInline) DeepCopyInto(out *FileContentInline) { *out = *in @@ -1468,6 +1489,20 @@ func (in *OperatingSystemConfigSpec) DeepCopy() *OperatingSystemConfigSpec { func (in *OperatingSystemConfigStatus) DeepCopyInto(out *OperatingSystemConfigStatus) { *out = *in in.DefaultStatus.DeepCopyInto(&out.DefaultStatus) + if in.ExtensionUnits != nil { + in, out := &in.ExtensionUnits, &out.ExtensionUnits + *out = make([]Unit, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ExtensionFiles != nil { + in, out := &in.ExtensionFiles, &out.ExtensionFiles + *out = make([]File, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.CloudConfig != nil { in, out := &in.CloudConfig, &out.CloudConfig *out = new(CloudConfig) @@ -1506,7 +1541,7 @@ func (in *Unit) DeepCopyInto(out *Unit) { *out = *in if in.Command != nil { in, out := &in.Command, &out.Command - *out = new(string) + *out = new(UnitCommand) **out = **in } if in.Enable != nil { @@ -1524,6 +1559,13 @@ func (in *Unit) DeepCopyInto(out *Unit) { *out = make([]DropIn, len(*in)) copy(*out, *in) } + if in.Files != nil { + in, out := &in.Files, &out.Files + *out = make([]File, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/apis/operator/v1alpha1/types.go b/vendor/github.com/gardener/gardener/pkg/apis/operator/v1alpha1/types.go index 2fccce0ff..19b94151a 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/operator/v1alpha1/types.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/operator/v1alpha1/types.go @@ -373,7 +373,7 @@ type KubeControllerManagerConfig struct { CertificateSigningDuration *metav1.Duration `json:"certificateSigningDuration,omitempty"` } -// Gardener contains the configuration settings for the Gardener componenets. +// Gardener contains the configuration settings for the Gardener components. type Gardener struct { // ClusterIdentity is the identity of the garden cluster. This field is immutable. // +kubebuilder:validation:MinLength=1 diff --git a/vendor/github.com/gardener/gardener/pkg/apis/resources/v1alpha1/types.go b/vendor/github.com/gardener/gardener/pkg/apis/resources/v1alpha1/types.go index 65b5d79ad..7e63aaabd 100644 --- a/vendor/github.com/gardener/gardener/pkg/apis/resources/v1alpha1/types.go +++ b/vendor/github.com/gardener/gardener/pkg/apis/resources/v1alpha1/types.go @@ -52,6 +52,9 @@ const ( // It is set by the ManagedResource controller to the key of the owning ManagedResource, optionally prefixed with the // clusterID. OriginAnnotation = "resources.gardener.cloud/origin" + // FinalizeDeletionAfter is an annotation on an object part of a ManagedResource that whose value states the + // duration after which a deletion should be finalized (i.e., removal of `.metadata.finalizers[]`). + FinalizeDeletionAfter = "resources.gardener.cloud/finalize-deletion-after" // ManagedBy is a constant for a label on an object managed by a ManagedResource. // It is set by the ManagedResource controller depending on its configuration. By default it is set to "gardener". diff --git a/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go b/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go index ee5c96421..cb14e6c4e 100644 --- a/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go +++ b/vendor/github.com/gardener/gardener/pkg/chartrenderer/default.go @@ -69,29 +69,7 @@ func NewWithServerVersion(serverVersion *version.Info) Interface { } } -// DiscoverCapabilities discovers the capabilities required for chart renderers using the given -// DiscoveryInterface. -func DiscoverCapabilities(disc discovery.DiscoveryInterface) (*chartutil.Capabilities, error) { - sv, err := disc.ServerVersion() - if err != nil { - return nil, fmt.Errorf("failed to get kubernetes server version %w", err) - } - - return &chartutil.Capabilities{KubeVersion: sv}, nil -} - -// Render loads the chart from the given location and calls the Render() function -// to convert it into a ChartRelease object. -// Deprecated: Use RenderEmbeddedFS for new code! -func (r *chartRenderer) Render(chartPath, releaseName, namespace string, values interface{}) (*RenderedChart, error) { - chart, err := chartutil.Load(chartPath) - if err != nil { - return nil, fmt.Errorf("can't load chart from path %s:, %s", chartPath, err) - } - return r.renderRelease(chart, releaseName, namespace, values) -} - -// RenderArchive loads the chart from the given location and calls the Render() function +// RenderArchive loads the chart from the given location and calls the renderRelease() function // to convert it into a ChartRelease object. func (r *chartRenderer) RenderArchive(archive []byte, releaseName, namespace string, values interface{}) (*RenderedChart, error) { chart, err := chartutil.LoadArchive(bytes.NewReader(archive)) @@ -101,7 +79,7 @@ func (r *chartRenderer) RenderArchive(archive []byte, releaseName, namespace str return r.renderRelease(chart, releaseName, namespace, values) } -// RenderEmbeddedFS loads the chart from the given embed.FS and calls the Render() function +// RenderEmbeddedFS loads the chart from the given embed.FS and calls the renderRelease() function // to convert it into a ChartRelease object. func (r *chartRenderer) RenderEmbeddedFS(embeddedFS embed.FS, chartPath, releaseName, namespace string, values interface{}) (*RenderedChart, error) { chart, err := loadEmbeddedFS(embeddedFS, chartPath) diff --git a/vendor/github.com/gardener/gardener/pkg/chartrenderer/renderer.go b/vendor/github.com/gardener/gardener/pkg/chartrenderer/renderer.go index d28c905c6..c9f2fd52f 100644 --- a/vendor/github.com/gardener/gardener/pkg/chartrenderer/renderer.go +++ b/vendor/github.com/gardener/gardener/pkg/chartrenderer/renderer.go @@ -21,10 +21,7 @@ import ( ) // Interface is an interface for rendering Helm Charts from path, name, namespace and values. -// TODO(rfranzke): Drop the deprecated method after Gardener v1.80 has been released. type Interface interface { - // Deprecated: Use RenderEmbeddedFS for new code! - Render(chartPath, releaseName, namespace string, values interface{}) (*RenderedChart, error) RenderEmbeddedFS(embeddedFS embed.FS, chartPath, releaseName, namespace string, values interface{}) (*RenderedChart, error) RenderArchive(archive []byte, releaseName, namespace string, values interface{}) (*RenderedChart, error) } diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/aggregator.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/aggregator.go index 7a2669cf8..db21f977a 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/aggregator.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/aggregator.go @@ -54,32 +54,16 @@ func (c *aggregator) cacheForKind(kind schema.GroupVersionKind) cache.Cache { return cache } -func processError(err error) error { - if !IsAPIError(err) { - // Return every other, unspecified error as a `CacheError` to allow users to follow up with a proper error handling. - // For instance, a `Multinamespace` cache returns an unspecified error for unknown namespaces. - // https://github.com/kubernetes-sigs/controller-runtime/blob/b5065bd85190e92864522fcc85aa4f6a3cce4f82/pkg/cache/multi_namespace_cache.go#L132 - return NewCacheError(err) - } - return err -} - // Get retrieves an obj for the given object key from the Kubernetes Cluster. // Every non-API related error is returned as a `CacheError`. func (c *aggregator) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { - if err := c.cacheForObject(obj).Get(ctx, key, obj, opts...); err != nil { - return processError(err) - } - return nil + return c.cacheForObject(obj).Get(ctx, key, obj, opts...) } // List retrieves list of objects for a given namespace and list options. // Every non-API related error is returned as a `CacheError`. func (c *aggregator) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - if err := c.cacheForObject(list).List(ctx, list, opts...); err != nil { - return processError(err) - } - return nil + return c.cacheForObject(list).List(ctx, list, opts...) } func (c *aggregator) GetInformer(ctx context.Context, obj client.Object, opts ...cache.InformerGetOption) (cache.Informer, error) { diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/errors.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/errors.go deleted file mode 100644 index fc49d35c2..000000000 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/cache/errors.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cache - -import ( - "fmt" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" -) - -// IsAPIError checks if the given error is API related. -func IsAPIError(err error) bool { - if _, ok := err.(apierrors.APIStatus); ok { - return true - } - if meta.IsNoMatchError(err) || meta.IsAmbiguousError(err) { - return true - } - return false -} - -// CacheError is an error type indicating that an cache error occurred. -type CacheError struct { - cause error -} - -// Unwrap returns the next error in the error chain. -func (e *CacheError) Unwrap() error { - return e.cause -} - -// Error returns the error string with the underlying error. -func (e *CacheError) Error() string { - return fmt.Errorf("an underlying cache error occurred: %w", e.cause).Error() -} - -// NewCacheError returns a new instance of `CacheError`. -func NewCacheError(err error) error { - return &CacheError{err} -} diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/chartapplier.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/chartapplier.go index eafb07003..f536e8e61 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/chartapplier.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/chartapplier.go @@ -25,13 +25,8 @@ import ( // ChartApplier is an interface that describes needed methods that render and apply // Helm charts in Kubernetes clusters. -// TODO(rfranzke): Drop the deprecated methods after Gardener v1.80 has been released. type ChartApplier interface { chartrenderer.Interface - // Deprecated: Use ApplyFromEmbeddedFS for new code! - Apply(ctx context.Context, chartPath, namespace, name string, opts ...ApplyOption) error - // Deprecated: Use DeleteFromEmbeddedFS for new code! - Delete(ctx context.Context, chartPath, namespace, name string, opts ...DeleteOption) error ApplyFromEmbeddedFS(ctx context.Context, embeddedFS embed.FS, chartPath, namespace, name string, opts ...ApplyOption) error DeleteFromEmbeddedFS(ctx context.Context, embeddedFS embed.FS, chartPath, namespace, name string, opts ...DeleteOption) error } @@ -60,20 +55,7 @@ func NewChartApplierForConfig(config *rest.Config) (ChartApplier, error) { return NewChartApplier(renderer, applier), nil } -// Apply takes a path to a chart , name of the release , -// release's namespace and renders the template based value. -// The resulting manifest will be applied to the cluster the Kubernetes client has been created for. -// can be used to enchance the existing functionality. -// Deprecated: Use ApplyFromEmbeddedFS for new code! -func (c *chartApplier) Apply(ctx context.Context, chartPath, namespace, name string, opts ...ApplyOption) error { - return c.apply(ctx, nil, chartPath, namespace, name, opts...) -} - func (c *chartApplier) ApplyFromEmbeddedFS(ctx context.Context, embeddedFS embed.FS, chartPath, namespace, name string, opts ...ApplyOption) error { - return c.apply(ctx, &embeddedFS, chartPath, namespace, name, opts...) -} - -func (c *chartApplier) apply(ctx context.Context, embeddedFS *embed.FS, chartPath, namespace, name string, opts ...ApplyOption) error { applyOpts := &ApplyOptions{} for _, o := range opts { @@ -98,19 +80,7 @@ func (c *chartApplier) apply(ctx context.Context, embeddedFS *embed.FS, chartPat return c.ApplyManifest(ctx, manifestReader, applyOpts.MergeFuncs) } -// Delete takes a path to a chart , name of the release , -// release's namespace and renders the template. -// The resulting manifest will be deleted from the cluster the Kubernetes client has been created for. -// Deprecated: Use DeleteFromEmbeddedFS for new code! -func (c *chartApplier) Delete(ctx context.Context, chartPath, namespace, name string, opts ...DeleteOption) error { - return c.delete(ctx, nil, chartPath, namespace, name, opts...) -} - func (c *chartApplier) DeleteFromEmbeddedFS(ctx context.Context, embeddedFS embed.FS, chartPath, namespace, name string, opts ...DeleteOption) error { - return c.delete(ctx, &embeddedFS, chartPath, namespace, name, opts...) -} - -func (c *chartApplier) delete(ctx context.Context, embeddedFS *embed.FS, chartPath, namespace, name string, opts ...DeleteOption) error { deleteOpts := &DeleteOptions{} for _, o := range opts { @@ -139,22 +109,15 @@ func (c *chartApplier) delete(ctx context.Context, embeddedFS *embed.FS, chartPa return c.DeleteManifest(ctx, manifestReader, deleteManifestOpts...) } -func (c *chartApplier) newManifestReader(embeddedFS *embed.FS, chartPath, namespace, name string, values interface{}) (UnstructuredReader, error) { +func (c *chartApplier) newManifestReader(embeddedFS embed.FS, chartPath, namespace, name string, values interface{}) (UnstructuredReader, error) { var ( release *chartrenderer.RenderedChart err error ) - if embeddedFS != nil { - release, err = c.RenderEmbeddedFS(*embeddedFS, chartPath, name, namespace, values) - if err != nil { - return nil, err - } - } else { - release, err = c.Render(chartPath, name, namespace, values) - if err != nil { - return nil, err - } + release, err = c.RenderEmbeddedFS(embeddedFS, chartPath, name, namespace, values) + if err != nil { + return nil, err } return NewManifestReader(release.Manifest()), nil diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go index 291d4b9cf..4fb96fac2 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/client.go @@ -31,12 +31,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - logf "sigs.k8s.io/controller-runtime/pkg/log" gardencoreinstall "github.com/gardener/gardener/pkg/apis/core/install" seedmanagementinstall "github.com/gardener/gardener/pkg/apis/seedmanagement/install" settingsinstall "github.com/gardener/gardener/pkg/apis/settings/install" - kubernetescache "github.com/gardener/gardener/pkg/client/kubernetes/cache" "github.com/gardener/gardener/pkg/utils" ) @@ -380,17 +378,15 @@ func newClient(conf *Config, reader client.Reader) (client.Client, error) { var _ client.Client = &FallbackClient{} // FallbackClient holds a `client.Client` and a `client.Reader` which is meant as a fallback -// in case Get/List requests with the ordinary `client.Client` fail (e.g. because of cache errors). +// in case the kind of an object is configured in `KindToNamespaces` but the namespace isn't. type FallbackClient struct { client.Client Reader client.Reader KindToNamespaces map[string]sets.Set[string] } -var cacheError = &kubernetescache.CacheError{} - // Get retrieves an obj for a given object key from the Kubernetes Cluster. -// In case of a cache error, the underlying API reader is used to execute the request again. +// `client.Reader` is used in case the kind of an object is configured in `KindToNamespaces` but the namespace isn't. func (d *FallbackClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { gvk, err := apiutil.GVKForObject(obj, GardenScheme) if err != nil { @@ -403,27 +399,14 @@ func (d *FallbackClient) Get(ctx context.Context, key client.ObjectKey, obj clie // If there are specific namespaces for this kind in the cache and the object's namespace is not cached, // use the API reader to get the object. if ok && !namespaces.Has(obj.GetNamespace()) { - return d.Reader.Get(ctx, key, obj) + return d.Reader.Get(ctx, key, obj, opts...) } // Otherwise, try to get the object from the cache. - err = d.Client.Get(ctx, key, obj) - - // If an error occurs and it's a cache error, log it and use the API reader as a fallback. - if err != nil && errors.As(err, &cacheError) { - logf.Log.V(1).Info("Falling back to API reader because a cache error occurred", "error", err) - return d.Reader.Get(ctx, key, obj) - } - return err + return d.Client.Get(ctx, key, obj, opts...) } // List retrieves list of objects for a given namespace and list options. -// In case of a cache error, the underlying API reader is used to execute the request again. func (d *FallbackClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error { - err := d.Client.List(ctx, list, opts...) - if err != nil && errors.As(err, &cacheError) { - logf.Log.V(1).Info("Falling back to API reader because a cache error occurred", "error", err) - return d.Reader.List(ctx, list, opts...) - } - return err + return d.Client.List(ctx, list, opts...) } diff --git a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/mock/mocks_chartapplier.go b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/mock/mocks_chartapplier.go index c6d382f39..6aee4c649 100644 --- a/vendor/github.com/gardener/gardener/pkg/client/kubernetes/mock/mocks_chartapplier.go +++ b/vendor/github.com/gardener/gardener/pkg/client/kubernetes/mock/mocks_chartapplier.go @@ -37,25 +37,6 @@ func (m *MockChartApplier) EXPECT() *MockChartApplierMockRecorder { return m.recorder } -// Apply mocks base method. -func (m *MockChartApplier) Apply(arg0 context.Context, arg1, arg2, arg3 string, arg4 ...kubernetes.ApplyOption) error { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1, arg2, arg3} - for _, a := range arg4 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Apply", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// Apply indicates an expected call of Apply. -func (mr *MockChartApplierMockRecorder) Apply(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*MockChartApplier)(nil).Apply), varargs...) -} - // ApplyFromEmbeddedFS mocks base method. func (m *MockChartApplier) ApplyFromEmbeddedFS(arg0 context.Context, arg1 embed.FS, arg2, arg3, arg4 string, arg5 ...kubernetes.ApplyOption) error { m.ctrl.T.Helper() @@ -75,25 +56,6 @@ func (mr *MockChartApplierMockRecorder) ApplyFromEmbeddedFS(arg0, arg1, arg2, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyFromEmbeddedFS", reflect.TypeOf((*MockChartApplier)(nil).ApplyFromEmbeddedFS), varargs...) } -// Delete mocks base method. -func (m *MockChartApplier) Delete(arg0 context.Context, arg1, arg2, arg3 string, arg4 ...kubernetes.DeleteOption) error { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1, arg2, arg3} - for _, a := range arg4 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Delete", varargs...) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockChartApplierMockRecorder) Delete(arg0, arg1, arg2, arg3 interface{}, arg4 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1, arg2, arg3}, arg4...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockChartApplier)(nil).Delete), varargs...) -} - // DeleteFromEmbeddedFS mocks base method. func (m *MockChartApplier) DeleteFromEmbeddedFS(arg0 context.Context, arg1 embed.FS, arg2, arg3, arg4 string, arg5 ...kubernetes.DeleteOption) error { m.ctrl.T.Helper() @@ -113,21 +75,6 @@ func (mr *MockChartApplierMockRecorder) DeleteFromEmbeddedFS(arg0, arg1, arg2, a return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFromEmbeddedFS", reflect.TypeOf((*MockChartApplier)(nil).DeleteFromEmbeddedFS), varargs...) } -// Render mocks base method. -func (m *MockChartApplier) Render(arg0, arg1, arg2 string, arg3 interface{}) (*chartrenderer.RenderedChart, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Render", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*chartrenderer.RenderedChart) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Render indicates an expected call of Render. -func (mr *MockChartApplierMockRecorder) Render(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Render", reflect.TypeOf((*MockChartApplier)(nil).Render), arg0, arg1, arg2, arg3) -} - // RenderArchive mocks base method. func (m *MockChartApplier) RenderArchive(arg0 []byte, arg1, arg2 string, arg3 interface{}) (*chartrenderer.RenderedChart, error) { m.ctrl.T.Helper() diff --git a/vendor/github.com/gardener/gardener/pkg/component/deploy.go b/vendor/github.com/gardener/gardener/pkg/component/deploy.go index 38914f02a..89871494b 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/deploy.go +++ b/vendor/github.com/gardener/gardener/pkg/component/deploy.go @@ -14,7 +14,9 @@ package component -import "context" +import ( + "context" +) // OpDestroy creates a Deployer which calls Destroy instead of Deploy. func OpDestroy(d ...Deployer) Deployer { diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/components.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/components.go index 59c37bbbb..a2dcece17 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/components.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/components.go @@ -15,7 +15,7 @@ package components import ( - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/utils/imagevector" diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/component.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/component.go index a070a2ba4..e5d4022aa 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/component.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/component.go @@ -19,7 +19,7 @@ import ( _ "embed" "text/template" - "github.com/Masterminds/sprig" + "github.com/Masterminds/sprig/v3" "k8s.io/utils/pointer" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" @@ -87,7 +87,7 @@ func (containerd) Config(_ components.Context) ([]extensionsv1alpha1.Unit, []ext return append([]extensionsv1alpha1.Unit{ { Name: UnitNameMonitor, - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Containerd-monitor daemon diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/initializer.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/initializer.go index 7234b52a1..89bc82ab6 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/initializer.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/initializer.go @@ -19,7 +19,7 @@ import ( _ "embed" "text/template" - "github.com/Masterminds/sprig" + "github.com/Masterminds/sprig/v3" "k8s.io/utils/pointer" "github.com/gardener/gardener/imagevector" @@ -77,7 +77,7 @@ func (initializer) Config(ctx components.Context) ([]extensionsv1alpha1.Unit, [] return []extensionsv1alpha1.Unit{ { Name: unitNameInitializer, - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Containerd initializer diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/logrotate/logrotate.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/logrotate/logrotate.go index 5ff45a1f0..018a4530e 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/logrotate/logrotate.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/containerd/logrotate/logrotate.go @@ -45,7 +45,7 @@ WantedBy=multi-user.target`), }, { Name: prefix + "-logrotate.timer", - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Log Rotation at each 10 minutes diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/component.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/component.go index ad6f150c7..cf6690eea 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/component.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/component.go @@ -19,7 +19,7 @@ import ( _ "embed" "text/template" - "github.com/Masterminds/sprig" + "github.com/Masterminds/sprig/v3" "k8s.io/utils/pointer" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" @@ -85,7 +85,7 @@ func (component) Config(_ components.Context) ([]extensionsv1alpha1.Unit, []exte return append([]extensionsv1alpha1.Unit{ { Name: UnitNameMonitor, - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Docker-monitor daemon diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/logrotate/logrotate.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/logrotate/logrotate.go index 04d9af0d7..6234cda60 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/logrotate/logrotate.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/docker/logrotate/logrotate.go @@ -50,7 +50,7 @@ WantedBy=multi-user.target`), }, { Name: prefix + "-logrotate.timer", - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Log Rotation at each 10 minutes diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/cliflags.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/cliflags.go index 2a4f299d1..3d3c793a8 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/cliflags.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/cliflags.go @@ -19,7 +19,7 @@ import ( "slices" "time" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/component.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/component.go index 5365ca6bf..cd3f8646d 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/component.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/component.go @@ -20,8 +20,8 @@ import ( "strings" "text/template" - "github.com/Masterminds/semver" - "github.com/Masterminds/sprig" + "github.com/Masterminds/semver/v3" + "github.com/Masterminds/sprig/v3" "k8s.io/utils/pointer" "github.com/gardener/gardener/imagevector" @@ -109,7 +109,7 @@ func (component) Config(ctx components.Context) ([]extensionsv1alpha1.Unit, []ex return []extensionsv1alpha1.Unit{ { Name: UnitName, - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=kubelet daemon @@ -128,7 +128,7 @@ ExecStart=` + v1beta1constants.OperatingSystemConfigFilePathBinaries + `/kubelet }, { Name: "kubelet-monitor.service", - Command: pointer.String("start"), + Command: extensionsv1alpha1.UnitCommandPtr(extensionsv1alpha1.CommandStart), Enable: pointer.Bool(true), Content: pointer.String(`[Unit] Description=Kubelet-monitor daemon diff --git a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/config.go b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/config.go index 53609fd50..fe4ef5eec 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/config.go +++ b/vendor/github.com/gardener/gardener/pkg/component/extensions/operatingsystemconfig/original/components/kubelet/config.go @@ -17,7 +17,7 @@ package kubelet import ( "time" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/crd.go b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/crd.go index e07fb90ac..b04da536c 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/crd.go +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/crd.go @@ -19,33 +19,24 @@ import ( _ "embed" "fmt" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gardener/gardener/pkg/client/kubernetes" "github.com/gardener/gardener/pkg/component" gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" + kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" ) var ( - //go:embed templates/crd-alicloudmachineclasses.tpl.yaml - machineClassAlicloudCRD string - //go:embed templates/crd-awsmachineclasses.tpl.yaml - machineClassAWSCRD string - //go:embed templates/crd-azuremachineclasses.tpl.yaml - machineClassAzureCRD string - //go:embed templates/crd-gcpmachineclasses.tpl.yaml - machineClassGCPCRD string - //go:embed templates/crd-openstackmachineclasses.tpl.yaml - machineClassOpenStackCRD string - //go:embed templates/crd-packetmachineclasses.tpl.yaml - machineClassPacketCRD string - //go:embed templates/crd-machineclasses.tpl.yaml + //go:embed templates/crd-machine.sapcloud.io_machineclasses.yaml machineClassCRD string - //go:embed templates/crd-machinedeployments.tpl.yaml + //go:embed templates/crd-machine.sapcloud.io_machinedeployments.yaml machineDeploymentCRD string - //go:embed templates/crd-machinesets.tpl.yaml + //go:embed templates/crd-machine.sapcloud.io_machinesets.yaml machineSetCRD string - //go:embed templates/crd-machines.tpl.yaml + //go:embed templates/crd-machine.sapcloud.io_machines.yaml machineCRD string crdResources []string @@ -53,12 +44,6 @@ var ( func init() { crdResources = []string{ - machineClassAlicloudCRD, - machineClassAWSCRD, - machineClassAzureCRD, - machineClassGCPCRD, - machineClassOpenStackCRD, - machineClassPacketCRD, machineClassCRD, machineDeploymentCRD, machineSetCRD, @@ -87,7 +72,7 @@ func (c *crd) Deploy(ctx context.Context) error { } } - return nil + return c.deleteLegacyCRDs(ctx) } func (c *crd) Destroy(ctx context.Context) error { @@ -108,5 +93,27 @@ func (c *crd) Destroy(ctx context.Context) error { } } + return c.deleteLegacyCRDs(ctx) +} + +// TODO(rfranzke): Remove this code after Gardener v1.83 has been released. +func (c *crd) deleteLegacyCRDs(ctx context.Context) error { + for _, name := range []string{ + "alicloudmachineclasses.machine.sapcloud.io", + "awsmachineclasses.machine.sapcloud.io", + "azuremachineclasses.machine.sapcloud.io", + "gcpmachineclasses.machine.sapcloud.io", + "openstackmachineclasses.machine.sapcloud.io", + "packetmachineclasses.machine.sapcloud.io", + } { + obj := &apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: name}} + if err := gardenerutils.ConfirmDeletion(ctx, c.client, obj); client.IgnoreNotFound(err) != nil { + return err + } + if err := kubernetesutils.DeleteObject(ctx, c.client, obj); err != nil { + return err + } + } + return nil } diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/machine_controller_manager.go b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/machine_controller_manager.go index 9356e2519..aae3ebb7b 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/machine_controller_manager.go +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/machine_controller_manager.go @@ -19,7 +19,7 @@ import ( "fmt" "time" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" appsv1 "k8s.io/api/apps/v1" autoscalingv1 "k8s.io/api/autoscaling/v1" corev1 "k8s.io/api/core/v1" @@ -157,7 +157,7 @@ func (m *machineControllerManager) Deploy(ctx context.Context) error { service.Labels = utils.MergeStringMaps(service.Labels, getLabels()) utilruntime.Must(gardenerutils.InjectNetworkPolicyAnnotationsForScrapeTargets(service, networkingv1.NetworkPolicyPort{ - Port: utils.IntStrPtrFromInt(portMetrics), + Port: utils.IntStrPtrFromInt32(portMetrics), Protocol: utils.ProtocolPtr(corev1.ProtocolTCP), })) @@ -213,13 +213,13 @@ func (m *machineControllerManager) Deploy(ctx context.Context) error { "--safety-up=2", "--safety-down=1", "--target-kubeconfig=" + gardenerutils.PathGenericKubeconfig, - "--v=4", + "--v=3", }, LivenessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/healthz", - Port: intstr.FromInt(portMetrics), + Port: intstr.FromInt32(portMetrics), Scheme: corev1.URISchemeHTTP, }, }, @@ -259,7 +259,7 @@ func (m *machineControllerManager) Deploy(ctx context.Context) error { if _, err := controllerutils.GetAndCreateOrMergePatch(ctx, m.client, podDisruptionBudget, func() error { podDisruptionBudget.Labels = utils.MergeStringMaps(podDisruptionBudget.Labels, getLabels()) podDisruptionBudget.Spec = policyv1.PodDisruptionBudgetSpec{ - MaxUnavailable: utils.IntStrPtrFromInt(1), + MaxUnavailable: utils.IntStrPtrFromInt32(1), Selector: deployment.Spec.Selector, } return nil @@ -386,7 +386,7 @@ func (m *machineControllerManager) computeShootResourcesData(serviceAccountName { APIGroups: []string{"storage.k8s.io"}, Resources: []string{"volumeattachments"}, - Verbs: []string{"get", "list", "watch"}, + Verbs: []string{"delete", "get", "list", "watch"}, }, }, } diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/provider.go b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/provider.go index c8cd4ffed..159bfb0bc 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/provider.go +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/provider.go @@ -51,7 +51,7 @@ func ProviderSidecarContainer(namespace, providerName, image string) corev1.Cont ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/healthz", - Port: intstr.FromInt(metricsPort), + Port: intstr.FromInt32(metricsPort), Scheme: corev1.URISchemeHTTP, }, }, diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-alicloudmachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-alicloudmachineclasses.tpl.yaml deleted file mode 100644 index 77a90dd1d..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-alicloudmachineclasses.tpl.yaml +++ /dev/null @@ -1,155 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: alicloudmachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: AlicloudMachineClass - listKind: AlicloudMachineClassList - plural: alicloudmachineclasses - singular: alicloudmachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.instanceType - name: Instance Type - type: string - - jsonPath: .spec.region - name: Region - priority: 1 - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: AlicloudMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AlicloudMachineClassSpec is the specification of a AlicloudMachineClass. - properties: - IoOptimized: - type: string - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - dataDisks: - items: - properties: - category: - type: string - deleteWithInstance: - type: boolean - description: - type: string - encrypted: - type: boolean - name: - type: string - size: - type: integer - required: - - category - - deleteWithInstance - - encrypted - - name - - size - type: object - type: array - imageID: - type: string - instanceChargeType: - type: string - instanceType: - type: string - internetChargeType: - type: string - internetMaxBandwidthIn: - type: integer - internetMaxBandwidthOut: - type: integer - keyPairName: - type: string - privateIPAddress: - type: string - region: - type: string - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - securityGroupID: - type: string - spotStrategy: - type: string - systemDisk: - description: AlicloudSystemDisk describes SystemDisk for Alicloud. - properties: - category: - type: string - size: - type: integer - required: - - category - - size - type: object - tags: - additionalProperties: - type: string - type: object - vSwitchID: - type: string - zoneID: - type: string - required: - - imageID - - instanceType - - keyPairName - - region - - vSwitchID - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-awsmachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-awsmachineclasses.tpl.yaml deleted file mode 100644 index b7e37a51e..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-awsmachineclasses.tpl.yaml +++ /dev/null @@ -1,233 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: awsmachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: AWSMachineClass - listKind: AWSMachineClassList - plural: awsmachineclasses - singular: awsmachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.machineType - name: Machine Type - type: string - - jsonPath: .spec.ami - name: AMI - type: string - - jsonPath: .spec.region - name: Region - priority: 1 - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: AWSMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AWSMachineClassSpec is the specification of a AWSMachineClass. - properties: - ami: - type: string - blockDevices: - items: - properties: - deviceName: - description: The device name exposed to the machine (for example, - /dev/sdh or xvdh). - type: string - ebs: - description: Parameters used to automatically set up EBS volumes - when the machine is launched. - properties: - deleteOnTermination: - description: Indicates whether the EBS volume is deleted - on machine termination. - type: boolean - encrypted: - description: Indicates whether the EBS volume is encrypted. - Encrypted Amazon EBS volumes may only be attached to machines - that support Amazon EBS encryption. - type: boolean - iops: - description: "The number of I/O operations per second (IOPS) - that the volume supports. For io1, this represents the - number of IOPS that are provisioned for the volume. For - gp2, this represents the baseline performance of the volume - and the rate at which the volume accumulates I/O credits - for bursting. For more information about General Purpose - SSD baseline performance, I/O credits, and bursting, see - Amazon EBS Volume Types (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html) - in the Amazon Elastic Compute Cloud User Guide. \n Constraint: - Range is 100-20000 IOPS for io1 volumes and 100-10000 - IOPS for gp2 volumes. \n Condition: This parameter is - required for requests to create io1 volumes; it is not - used in requests to create gp2, st1, sc1, or standard - volumes." - format: int64 - type: integer - kmsKeyID: - description: "Identifier (key ID, key alias, ID ARN, or - alias ARN) for a customer managed CMK under which the - EBS volume is encrypted. \n This parameter is only supported - on BlockDeviceMapping objects called by RunInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html), - RequestSpotFleet (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RequestSpotFleet.html), - and RequestSpotInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RequestSpotInstances.html)." - type: string - snapshotID: - description: The ID of the snapshot. - type: string - volumeSize: - description: "The size of the volume, in GiB. \n Constraints: - 1-16384 for General Purpose SSD (gp2), 4-16384 for Provisioned - IOPS SSD (io1), 500-16384 for Throughput Optimized HDD - (st1), 500-16384 for Cold HDD (sc1), and 1-1024 for Magnetic - (standard) volumes. If you specify a snapshot, the volume - size must be equal to or larger than the snapshot size. - \n Default: If you're creating the volume from a snapshot - and don't specify a volume size, the default is the snapshot - size." - format: int64 - type: integer - volumeType: - description: "The volume type: gp2, io1, st1, sc1, or standard. - \n Default: standard" - type: string - type: object - noDevice: - description: Suppresses the specified device included in the - block device mapping of the AMI. - type: string - virtualName: - description: "The virtual device name (ephemeralN). Machine - store volumes are numbered starting from 0. An machine type - with 2 available machine store volumes can specify mappings - for ephemeral0 and ephemeral1.The number of available machine - store volumes depends on the machine type. After you connect - to the machine, you must mount the volume. \n Constraints: - For M3 machines, you must specify machine store volumes in - the block device mapping for the machine. When you launch - an M3 machine, we ignore any machine store volumes specified - in the block device mapping for the AMI." - type: string - type: object - type: array - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - ebsOptimized: - type: boolean - iam: - description: Describes an IAM machine profile. - properties: - arn: - description: The Amazon Resource Name (ARN) of the machine profile. - type: string - name: - description: The name of the machine profile. - type: string - type: object - keyName: - type: string - machineType: - type: string - monitoring: - type: boolean - networkInterfaces: - items: - description: Describes a network interface. Please also see https://docs.aws.amazon.com/goto/WebAPI/ec2-2016-11-15/MachineAWSNetworkInterfaceSpecification - properties: - associatePublicIPAddress: - description: Indicates whether to assign a public IPv4 address - to an machine you launch in a VPC. The public IP address can - only be assigned to a network interface for eth0, and can - only be assigned to a new network interface, not an existing - one. You cannot specify more than one network interface in - the request. If launching into a default subnet, the default - value is true. - type: boolean - deleteOnTermination: - description: If set to true, the interface is deleted when the - machine is terminated. You can specify true only if creating - a new network interface when launching an machine. - type: boolean - description: - description: The description of the network interface. Applies - only if creating a network interface when launching an machine. - type: string - securityGroupIDs: - description: The IDs of the security groups for the network - interface. Applies only if creating a network interface when - launching an machine. - items: - type: string - type: array - subnetID: - description: The ID of the subnet associated with the network - string. Applies only if creating a network interface when - launching an machine. - type: string - type: object - type: array - region: - type: string - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - spotPrice: - type: string - tags: - additionalProperties: - type: string - type: object - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-azuremachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-azuremachineclasses.tpl.yaml deleted file mode 100644 index a8a234255..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-azuremachineclasses.tpl.yaml +++ /dev/null @@ -1,259 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: azuremachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: AzureMachineClass - listKind: AzureMachineClassList - plural: azuremachineclasses - singular: azuremachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.properties.hardwareProfile.vmSize - name: VM Size - type: string - - jsonPath: .spec.location - name: Location - priority: 1 - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: AzureMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: AzureMachineClassSpec is the specification of a AzureMachineClass. - properties: - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - location: - type: string - properties: - description: AzureVirtualMachineProperties is describes the properties - of a Virtual Machine. - properties: - availabilitySet: - description: AzureSubResource is the Sub Resource definition. - properties: - id: - type: string - type: object - hardwareProfile: - description: AzureHardwareProfile is specifies the hardware settings - for the virtual machine. Refer github.com/Azure/azure-sdk-for-go/arm/compute/models.go - for VMSizes - properties: - vmSize: - type: string - type: object - identityID: - type: string - machineSet: - description: AzureMachineSetConfig contains the information about - the machine set - properties: - id: - type: string - kind: - type: string - required: - - id - - kind - type: object - networkProfile: - description: AzureNetworkProfile is specifies the network interfaces - of the virtual machine. - properties: - acceleratedNetworking: - type: boolean - networkInterfaces: - description: AzureNetworkInterfaceReference is describes a - network interface reference. - properties: - id: - type: string - properties: - description: AzureNetworkInterfaceReferenceProperties - is describes a network interface reference properties. - properties: - primary: - type: boolean - type: object - type: object - type: object - osProfile: - description: AzureOSProfile is specifies the operating system - settings for the virtual machine. - properties: - adminPassword: - type: string - adminUsername: - type: string - computerName: - type: string - customData: - type: string - linuxConfiguration: - description: AzureLinuxConfiguration is specifies the Linux - operating system settings on the virtual machine.

For - a list of supported Linux distributions, see [Linux on Azure-Endorsed - Distributions](https://docs.microsoft.com/azure/virtual-machines/virtual-machines-linux-endorsed-distros?toc=%2fazure%2fvirtual-machines%2flinux%2ftoc.json) -

For running non-endorsed distributions, see [Information - for Non-Endorsed Distributions](https://docs.microsoft.com/azure/virtual-machines/virtual-machines-linux-create-upload-generic?toc=%2fazure%2fvirtual-machines%2flinux%2ftoc.json). - properties: - disablePasswordAuthentication: - type: boolean - ssh: - description: AzureSSHConfiguration is SSH configuration - for Linux based VMs running on Azure - properties: - publicKeys: - description: AzureSSHPublicKey is contains information - about SSH certificate public key and the path on - the Linux VM where the public key is placed. - properties: - keyData: - type: string - path: - type: string - type: object - type: object - type: object - type: object - storageProfile: - description: AzureStorageProfile is specifies the storage settings - for the virtual machine disks. - properties: - dataDisks: - items: - properties: - caching: - type: string - diskSizeGB: - format: int32 - type: integer - lun: - format: int32 - type: integer - name: - type: string - storageAccountType: - type: string - type: object - type: array - imageReference: - description: AzureImageReference is specifies information - about the image to use. You can specify information about - platform images, marketplace images, or virtual machine - images. This element is required when you want to use a - platform image, marketplace image, or virtual machine image, - but is not used in other creation operations. - properties: - id: - type: string - urn: - description: Uniform Resource Name of the OS image to - be used , it has the format 'publisher:offer:sku:version' - type: string - type: object - osDisk: - description: AzureOSDisk is specifies information about the - operating system disk used by the virtual machine.

- For more information about disks, see [About disks and VHDs - for Azure virtual machines](https://docs.microsoft.com/azure/virtual-machines/virtual-machines-windows-about-disks-vhds?toc=%2fazure%2fvirtual-machines%2fwindows%2ftoc.json). - properties: - caching: - type: string - createOption: - type: string - diskSizeGB: - format: int32 - type: integer - managedDisk: - description: AzureManagedDiskParameters is the parameters - of a managed disk. - properties: - id: - type: string - storageAccountType: - type: string - type: object - name: - type: string - type: object - type: object - zone: - type: integer - type: object - resourceGroup: - type: string - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - subnetInfo: - description: AzureSubnetInfo is the information containing the subnet - details - properties: - subnetName: - type: string - vnetName: - type: string - vnetResourceGroup: - type: string - type: object - tags: - additionalProperties: - type: string - type: object - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-gcpmachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-gcpmachineclasses.tpl.yaml deleted file mode 100644 index 0dcc54c6e..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-gcpmachineclasses.tpl.yaml +++ /dev/null @@ -1,198 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: gcpmachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: GCPMachineClass - listKind: GCPMachineClassList - plural: gcpmachineclasses - singular: gcpmachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.machineType - name: Machine Type - type: string - - jsonPath: .spec.region - name: Region - priority: 1 - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: GCPMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: GCPMachineClassSpec is the specification of a GCPMachineClass. - properties: - canIpForward: - type: boolean - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - deletionProtection: - type: boolean - description: - type: string - disks: - items: - description: GCPDisk describes disks for GCP. - properties: - autoDelete: - type: boolean - boot: - type: boolean - image: - type: string - interface: - type: string - labels: - additionalProperties: - type: string - type: object - sizeGb: - format: int64 - type: integer - type: - type: string - required: - - autoDelete - - boot - - image - - interface - - labels - - sizeGb - - type - type: object - type: array - labels: - additionalProperties: - type: string - type: object - machineType: - type: string - metadata: - items: - description: GCPMetadata describes metadata for GCP. - properties: - key: - type: string - value: - type: string - required: - - key - - value - type: object - type: array - networkInterfaces: - items: - description: GCPNetworkInterface describes network interfaces for - GCP - properties: - disableExternalIP: - type: boolean - network: - type: string - subnetwork: - type: string - type: object - type: array - region: - type: string - scheduling: - description: GCPScheduling describes scheduling configuration for - GCP. - properties: - automaticRestart: - type: boolean - onHostMaintenance: - type: string - preemptible: - type: boolean - required: - - automaticRestart - - onHostMaintenance - - preemptible - type: object - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - serviceAccounts: - items: - description: GCPServiceAccount describes service accounts for GCP. - properties: - email: - type: string - scopes: - items: - type: string - type: array - required: - - email - - scopes - type: object - type: array - tags: - items: - type: string - type: array - zone: - type: string - required: - - canIpForward - - deletionProtection - - machineType - - region - - scheduling - - serviceAccounts - - zone - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machineclasses.yaml similarity index 70% rename from vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machineclasses.tpl.yaml rename to vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machineclasses.yaml index a7afeeb48..bdca148da 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machineclasses.tpl.yaml +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machineclasses.yaml @@ -2,10 +2,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 labels: gardener.cloud/deletion-protected: "true" + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 name: machineclasses.machine.sapcloud.io spec: group: machine.sapcloud.io @@ -18,19 +18,7 @@ spec: singular: machineclass scope: Namespaced versions: - - additionalPrinterColumns: - - description: Name of the provider which acts on the machine class object - jsonPath: .provider - name: Provider - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 + - name: v1alpha1 schema: openAPIV3Schema: description: MachineClass can be used to templatize and re-use provider configuration @@ -38,8 +26,8 @@ spec: properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string credentialsSecretRef: description: CredentialsSecretRef can optionally store the credentials @@ -48,18 +36,19 @@ spec: different user-datas are used. properties: name: - description: Name is unique within a namespace to reference a secret + description: name is unique within a namespace to reference a secret resource. type: string namespace: - description: Namespace defines the space within which the secret name + description: namespace defines the space within which the secret name must be unique. type: string type: object + x-kubernetes-map-type: atomic kind: description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: type: object @@ -106,14 +95,15 @@ spec: or userdata. properties: name: - description: Name is unique within a namespace to reference a secret + description: name is unique within a namespace to reference a secret resource. type: string namespace: - description: Namespace defines the space within which the secret name + description: namespace defines the space within which the secret name must be unique. type: string type: object + x-kubernetes-map-type: atomic required: - providerSpec type: object diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinedeployments.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinedeployments.yaml similarity index 99% rename from vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinedeployments.tpl.yaml rename to vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinedeployments.yaml index 6b70b2a41..e098b6cd2 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinedeployments.tpl.yaml +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinedeployments.yaml @@ -1,12 +1,11 @@ -# Source: https://github.com/gardener/machine-controller-manager/blob/5b9a383788ef0723ca12eb86c688cdf3b157277d/kubernetes/crds/machine.sapcloud.io_machinedeployments.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 labels: gardener.cloud/deletion-protected: "true" + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 name: machinedeployments.machine.sapcloud.io spec: group: machine.sapcloud.io diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machines.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machines.yaml similarity index 98% rename from vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machines.tpl.yaml rename to vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machines.yaml index 146cce6b1..90bb30545 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machines.tpl.yaml +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machines.yaml @@ -1,12 +1,11 @@ -# Source: https://github.com/gardener/machine-controller-manager/blob/5b9a383788ef0723ca12eb86c688cdf3b157277d/kubernetes/crds/machine.sapcloud.io_machines.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 labels: gardener.cloud/deletion-protected: "true" + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 name: machines.machine.sapcloud.io spec: group: machine.sapcloud.io diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinesets.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinesets.yaml similarity index 98% rename from vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinesets.tpl.yaml rename to vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinesets.yaml index e09d1af8a..f448b3ae4 100644 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machinesets.tpl.yaml +++ b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-machine.sapcloud.io_machinesets.yaml @@ -1,12 +1,11 @@ -# Source: https://github.com/gardener/machine-controller-manager/blob/5b9a383788ef0723ca12eb86c688cdf3b157277d/kubernetes/crds/machine.sapcloud.io_machinesets.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 labels: gardener.cloud/deletion-protected: "true" + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 name: machinesets.machine.sapcloud.io spec: group: machine.sapcloud.io diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-openstackmachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-openstackmachineclasses.tpl.yaml deleted file mode 100644 index 29d50a5fe..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-openstackmachineclasses.tpl.yaml +++ /dev/null @@ -1,139 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: openstackmachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: OpenStackMachineClass - listKind: OpenStackMachineClassList - plural: openstackmachineclasses - singular: openstackmachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.flavorName - name: Flavor - type: string - - jsonPath: .spec.imageName - name: Image - type: string - - jsonPath: .spec.region - name: Region - priority: 1 - type: string - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: OpenStackMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: OpenStackMachineClassSpec is the specification of a OpenStackMachineClass. - properties: - availabilityZone: - type: string - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - flavorName: - type: string - imageID: - type: string - imageName: - type: string - keyName: - type: string - networkID: - type: string - networks: - items: - properties: - id: - type: string - name: - type: string - podNetwork: - type: boolean - type: object - type: array - podNetworkCidr: - type: string - region: - type: string - rootDiskSize: - type: integer - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - securityGroups: - items: - type: string - type: array - serverGroupID: - type: string - subnetID: - type: string - tags: - additionalProperties: - type: string - type: object - useConfigDrive: - type: boolean - required: - - availabilityZone - - flavorName - - imageID - - imageName - - keyName - - networkID - - podNetworkCidr - - region - - securityGroups - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-packetmachineclasses.tpl.yaml b/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-packetmachineclasses.tpl.yaml deleted file mode 100644 index f3b4b1356..000000000 --- a/vendor/github.com/gardener/gardener/pkg/component/machinecontrollermanager/templates/crd-packetmachineclasses.tpl.yaml +++ /dev/null @@ -1,104 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - labels: - gardener.cloud/deletion-protected: "true" - name: packetmachineclasses.machine.sapcloud.io -spec: - group: machine.sapcloud.io - names: - kind: PacketMachineClass - listKind: PacketMachineClassList - plural: packetmachineclasses - singular: packetmachineclass - scope: Namespaced - versions: - - additionalPrinterColumns: - - description: |- - CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: PacketMachineClass TODO - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: PacketMachineClassSpec is the specification of a PacketMachineClass. - properties: - OS: - type: string - billingCycle: - type: string - credentialsSecretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - facility: - items: - type: string - type: array - machineType: - type: string - projectID: - type: string - secretRef: - description: SecretReference represents a Secret Reference. It has - enough information to retrieve secret in any namespace - properties: - name: - description: Name is unique within a namespace to reference a - secret resource. - type: string - namespace: - description: Namespace defines the space within which the secret - name must be unique. - type: string - type: object - sshKeys: - items: - type: string - type: array - tags: - items: - type: string - type: array - userdata: - type: string - required: - - OS - - billingCycle - - facility - - machineType - - projectID - type: object - type: object - served: true - storage: true - subresources: {} diff --git a/vendor/github.com/gardener/gardener/pkg/controllerutils/predicate/predicate.go b/vendor/github.com/gardener/gardener/pkg/controllerutils/predicate/predicate.go index ab8d8f808..41d2d0faf 100644 --- a/vendor/github.com/gardener/gardener/pkg/controllerutils/predicate/predicate.go +++ b/vendor/github.com/gardener/gardener/pkg/controllerutils/predicate/predicate.go @@ -160,12 +160,13 @@ func LastOperationChanged(getLastOperation func(client.Object) *gardencorev1beta // so if the oldObject doesn't have the same annotation, don't enqueue it. if v1beta1helper.HasOperationAnnotation(e.ObjectNew.GetAnnotations()) { operation := e.ObjectNew.GetAnnotations()[v1beta1constants.GardenerOperation] - if operation == v1beta1constants.GardenerOperationMigrate || operation == v1beta1constants.GardenerOperationRestore { - // if the oldObject doesn't have the same annotation skip - if e.ObjectOld.GetAnnotations()[v1beta1constants.GardenerOperation] != operation { - return false - } - } else { + + if operation != v1beta1constants.GardenerOperationMigrate && operation != v1beta1constants.GardenerOperationRestore { + return false + } + + // if the oldObject doesn't have the same annotation skip + if e.ObjectOld.GetAnnotations()[v1beta1constants.GardenerOperation] != operation { return false } } diff --git a/vendor/github.com/gardener/gardener/pkg/features/features.go b/vendor/github.com/gardener/gardener/pkg/features/features.go index 82d38477f..3a069e383 100644 --- a/vendor/github.com/gardener/gardener/pkg/features/features.go +++ b/vendor/github.com/gardener/gardener/pkg/features/features.go @@ -64,21 +64,23 @@ const ( // beta: v1.79.0 WorkerlessShoots featuregate.Feature = "WorkerlessShoots" + // ShootForceDeletion allows force deletion of Shoots. + // See https://github.com/gardener/gardener/blob/master/docs/usage/shoot_operations.md#shoot-force-deletion for more details. + // owner: @acumino @ary1992 @shafeeqes + // alpha: v1.81.0 + ShootForceDeletion featuregate.Feature = "ShootForceDeletion" + // MachineControllerManagerDeployment enables Gardener to take over the deployment of the // machine-controller-manager. If enabled, all registered provider extensions must support injecting the // provider-specific MCM provider sidecar container into the deployment via the `controlplane` webhook. // owner: @rfranzke @JensAc @mreiger // alpha: v1.73.0 + // beta: v1.81.0 + // GA: v1.82.0 + // TODO(scheererj): Do not remove this feature gate before v1.90 to give extensions enough time to adopt v1.83. + // Otherwise, extensions might end up believing they need to manage MCM again when the feature gate is removed. MachineControllerManagerDeployment featuregate.Feature = "MachineControllerManagerDeployment" - // DisableScalingClassesForShoots disables assigning a ScalingClass to Shoots based on their maximum Node count - // All Shoot kube-apiservers will get the same initial resource requests for CPU and memory instead of making this - // depend on the ScalingClass - // owner: @voelzmo, @andrerun - // alpha: v1.73.0 - // beta: v1.79.0 - DisableScalingClassesForShoots featuregate.Feature = "DisableScalingClassesForShoots" - // ContainerdRegistryHostsDir enables registry configuration in containerd based on the hosts directory pattern. // The hosts directory pattern is the new way of configuring registries/mirrors in containerd. // Ref https://github.com/containerd/containerd/blob/main/docs/hosts.md. @@ -93,6 +95,18 @@ const ( // owner: @ialidzhikov, @dimitar-kostadinov // alpha: v1.77.0 ContainerdRegistryHostsDir featuregate.Feature = "ContainerdRegistryHostsDir" + + // APIServerFastRollout enables fast rollouts for Shoot kube-apiservers on the given Seed. + // When enabled, maxSurge for Shoot kube-apiserver deployments is set to 100%. + // owner: @oliver-goetz + // beta: v1.82.0 + APIServerFastRollout featuregate.Feature = "APIServerFastRollout" + + // UseGardenerNodeAgent enables the `gardener-node-agent` instead of the `cloud-config-downloader` for shoot worker + // nodes. + // owner: @rfranzke @oliver-goetz + // alpha: v1.82.0 + UseGardenerNodeAgent featuregate.Feature = "UseGardenerNodeAgent" ) // DefaultFeatureGate is the central feature gate map used by all gardener components. @@ -127,9 +141,11 @@ var AllFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ IPv6SingleStack: {Default: false, PreRelease: featuregate.Alpha}, MutableShootSpecNetworkingNodes: {Default: false, PreRelease: featuregate.Alpha}, WorkerlessShoots: {Default: true, PreRelease: featuregate.Beta}, - MachineControllerManagerDeployment: {Default: false, PreRelease: featuregate.Alpha}, - DisableScalingClassesForShoots: {Default: true, PreRelease: featuregate.Beta}, + ShootForceDeletion: {Default: false, PreRelease: featuregate.Alpha}, + MachineControllerManagerDeployment: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, ContainerdRegistryHostsDir: {Default: false, PreRelease: featuregate.Alpha}, + APIServerFastRollout: {Default: true, PreRelease: featuregate.Beta}, + UseGardenerNodeAgent: {Default: false, PreRelease: featuregate.Alpha}, } // GetFeatures returns a feature gate map with the respective specifications. Non-existing feature gates are ignored. diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/types.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/types.go index 9d320b172..8917a0b32 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/types.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/types.go @@ -104,7 +104,6 @@ type KubeconfigValidity struct { // .spec.expirationSeconds in the created CertificateSigningRequest resource. // This value is not defaulted, meaning that the value configured via `--cluster-signing-duration` on // kube-controller-manager is used. - // Note that using this value will only have effect for garden clusters >= Kubernetes 1.22. // Note that changing this value will only have effect after the next rotation of the gardenlet's kubeconfig secret. Validity *metav1.Duration // AutoRotationJitterPercentageMin is the minimum percentage when it comes to compute a random jitter value for the @@ -492,6 +491,9 @@ type BackupCompactionController struct { // ActiveDeadlineDuration defines duration after which a running backup compaction job will be killed // Defaults to 3 hours ActiveDeadlineDuration *metav1.Duration + // MetricsScrapeWaitDuration is the duration to wait for after compaction job is completed, to allow Prometheus metrics to be scraped + // Defaults to 60 seconds + MetricsScrapeWaitDuration *metav1.Duration } // ETCDBackupLeaderElection contains configuration for the leader election for the etcd backup-restore sidecar. diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/defaults.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/defaults.go index d4ba15388..6fce6a77b 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/defaults.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/defaults.go @@ -497,4 +497,7 @@ func SetDefaults_ETCDConfig(obj *ETCDConfig) { if obj.BackupCompactionController.EventsThreshold == nil { obj.BackupCompactionController.EventsThreshold = pointer.Int64(1000000) } + if obj.BackupCompactionController.MetricsScrapeWaitDuration == nil { + obj.BackupCompactionController.MetricsScrapeWaitDuration = &metav1.Duration{Duration: 60 * time.Second} + } } diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/types.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/types.go index bb0f50cf8..1614f95a1 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/types.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/types.go @@ -126,7 +126,6 @@ type KubeconfigValidity struct { // .spec.expirationSeconds in the created CertificateSigningRequest resource. // This value is not defaulted, meaning that the value configured via `--cluster-signing-duration` on // kube-controller-manager is used. - // Note that using this value will only have effect for garden clusters >= Kubernetes 1.22. // Note that changing this value will only have effect after the next rotation of the gardenlet's kubeconfig secret. // +optional Validity *metav1.Duration `json:"validity,omitempty"` @@ -597,6 +596,10 @@ type BackupCompactionController struct { // Defaults to 3 hours // +optional ActiveDeadlineDuration *metav1.Duration `json:"activeDeadlineDuration,omitempty"` + // MetricsScrapeWaitDuration is the duration to wait for after compaction job is completed, to allow Prometheus metrics to be scraped + // Defaults to 60 seconds + // +optional + MetricsScrapeWaitDuration *metav1.Duration `json:"metricsScrapeWaitDuration,omitempty"` } // ETCDBackupLeaderElection contains configuration for the leader election for the etcd backup-restore sidecar. diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.conversion.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.conversion.go index 27677309a..179e6273a 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.conversion.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.conversion.go @@ -521,6 +521,7 @@ func autoConvert_v1alpha1_BackupCompactionController_To_config_BackupCompactionC out.EnableBackupCompaction = (*bool)(unsafe.Pointer(in.EnableBackupCompaction)) out.EventsThreshold = (*int64)(unsafe.Pointer(in.EventsThreshold)) out.ActiveDeadlineDuration = (*v1.Duration)(unsafe.Pointer(in.ActiveDeadlineDuration)) + out.MetricsScrapeWaitDuration = (*v1.Duration)(unsafe.Pointer(in.MetricsScrapeWaitDuration)) return nil } @@ -534,6 +535,7 @@ func autoConvert_config_BackupCompactionController_To_v1alpha1_BackupCompactionC out.EnableBackupCompaction = (*bool)(unsafe.Pointer(in.EnableBackupCompaction)) out.EventsThreshold = (*int64)(unsafe.Pointer(in.EventsThreshold)) out.ActiveDeadlineDuration = (*v1.Duration)(unsafe.Pointer(in.ActiveDeadlineDuration)) + out.MetricsScrapeWaitDuration = (*v1.Duration)(unsafe.Pointer(in.MetricsScrapeWaitDuration)) return nil } diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.deepcopy.go index d7dd019d7..73446340f 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/v1alpha1/zz_generated.deepcopy.go @@ -73,6 +73,11 @@ func (in *BackupCompactionController) DeepCopyInto(out *BackupCompactionControll *out = new(v1.Duration) **out = **in } + if in.MetricsScrapeWaitDuration != nil { + in, out := &in.MetricsScrapeWaitDuration, &out.MetricsScrapeWaitDuration + *out = new(v1.Duration) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/zz_generated.deepcopy.go b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/zz_generated.deepcopy.go index 0143aee43..212e7d4b5 100644 --- a/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/zz_generated.deepcopy.go +++ b/vendor/github.com/gardener/gardener/pkg/gardenlet/apis/config/zz_generated.deepcopy.go @@ -73,6 +73,11 @@ func (in *BackupCompactionController) DeepCopyInto(out *BackupCompactionControll *out = new(v1.Duration) **out = **in } + if in.MetricsScrapeWaitDuration != nil { + in, out := &in.MetricsScrapeWaitDuration, &out.MetricsScrapeWaitDuration + *out = new(v1.Duration) + **out = **in + } return } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/chart/chart.go b/vendor/github.com/gardener/gardener/pkg/utils/chart/chart.go index bde659722..a754b4b96 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/chart/chart.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/chart/chart.go @@ -44,7 +44,7 @@ type Interface interface { type Chart struct { Name string Path string - EmbeddedFS *embed.FS + EmbeddedFS embed.FS Images []string Objects []*Object SubCharts []*Chart @@ -66,7 +66,6 @@ func (c *Chart) Apply( runtimeVersion, targetVersion string, additionalValues map[string]interface{}, ) error { - // Get values with injected images values, err := c.injectImages(imageVector, runtimeVersion, targetVersion) if err != nil { @@ -74,14 +73,8 @@ func (c *Chart) Apply( } // Apply chart - if c.EmbeddedFS != nil { - if err := chartApplier.ApplyFromEmbeddedFS(ctx, *c.EmbeddedFS, c.Path, namespace, c.Name, kubernetesclient.Values(utils.MergeMaps(values, additionalValues))); err != nil { - return fmt.Errorf("could not apply embedded chart '%s' in namespace '%s': %w", c.Name, namespace, err) - } - } else { - if err := chartApplier.Apply(ctx, c.Path, namespace, c.Name, kubernetesclient.Values(utils.MergeMaps(values, additionalValues))); err != nil { - return fmt.Errorf("could not apply chart '%s' in namespace '%s': %w", c.Name, namespace, err) - } + if err := chartApplier.ApplyFromEmbeddedFS(ctx, c.EmbeddedFS, c.Path, namespace, c.Name, kubernetesclient.Values(utils.MergeMaps(values, additionalValues))); err != nil { + return fmt.Errorf("could not apply embedded chart '%s' in namespace '%s': %w", c.Name, namespace, err) } return nil @@ -95,7 +88,11 @@ func (c *Chart) Render( imageVector imagevector.ImageVector, runtimeVersion, targetVersion string, additionalValues map[string]interface{}, -) (string, []byte, error) { +) ( + string, + []byte, + error, +) { // Get values with injected images values, err := c.injectImages(imageVector, runtimeVersion, targetVersion) if err != nil { @@ -104,16 +101,9 @@ func (c *Chart) Render( // Render chart var rc *chartrenderer.RenderedChart - if c.EmbeddedFS != nil { - rc, err = chartRenderer.RenderEmbeddedFS(*c.EmbeddedFS, c.Path, c.Name, namespace, utils.MergeMaps(values, additionalValues)) - if err != nil { - return "", nil, fmt.Errorf("could not render chart '%s' in namespace '%s': %w", c.Name, namespace, err) - } - } else { - rc, err = chartRenderer.Render(c.Path, c.Name, namespace, utils.MergeMaps(values, additionalValues)) - if err != nil { - return "", nil, fmt.Errorf("could not render chart '%s' in namespace '%s': %w", c.Name, namespace, err) - } + rc, err = chartRenderer.RenderEmbeddedFS(c.EmbeddedFS, c.Path, c.Name, namespace, utils.MergeMaps(values, additionalValues)) + if err != nil { + return "", nil, fmt.Errorf("could not render chart '%s' in namespace '%s': %w", c.Name, namespace, err) } return rc.ChartName, rc.Manifest(), nil @@ -123,8 +113,10 @@ func (c *Chart) Render( func (c *Chart) injectImages( imageVector imagevector.ImageVector, runtimeVersion, targetVersion string, -) (map[string]interface{}, error) { - +) ( + map[string]interface{}, + error, +) { // Inject images values := make(map[string]interface{}) var err error diff --git a/vendor/github.com/gardener/gardener/pkg/utils/errors/unwrap.go b/vendor/github.com/gardener/gardener/pkg/utils/errors/unwrap.go index d79b43d47..f751dda45 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/errors/unwrap.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/errors/unwrap.go @@ -14,7 +14,9 @@ package errors -import "errors" +import ( + "errors" +) // Unwrap unwraps and returns the root error. Multiple wrappings via `fmt.Errorf` implementations are properly taken into account. func Unwrap(err error) error { diff --git a/vendor/github.com/gardener/gardener/pkg/utils/flow/flow.go b/vendor/github.com/gardener/gardener/pkg/utils/flow/flow.go index 935d3ab90..03d9c54bc 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/flow/flow.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/flow/flow.go @@ -79,6 +79,7 @@ type node struct { targetIDs TaskIDs required int fn TaskFn + skip bool } func (n *node) String() string { @@ -114,8 +115,9 @@ func (f *Flow) Run(ctx context.Context, opts Opts) error { } type nodeResult struct { - TaskID TaskID - Error error + TaskID TaskID + Error error + skipped bool } // Stats are the statistics of a Flow execution. @@ -125,6 +127,7 @@ type Stats struct { Succeeded TaskIDs Failed TaskIDs Running TaskIDs + Skipped TaskIDs Pending TaskIDs } @@ -142,6 +145,7 @@ func (s *Stats) Copy() *Stats { s.Succeeded.Copy(), s.Failed.Copy(), s.Running.Copy(), + s.Skipped.Copy(), s.Pending.Copy(), } } @@ -155,6 +159,7 @@ func InitialStats(flowName string, all TaskIDs) *Stats { NewTaskIDs(), NewTaskIDs(), NewTaskIDs(), + NewTaskIDs(), all.Copy(), } } @@ -162,8 +167,10 @@ func InitialStats(flowName string, all TaskIDs) *Stats { func newExecution(flow *Flow, opts Opts) *execution { all := NewTaskIDs() - for name := range flow.nodes { - all.Insert(name) + for name, task := range flow.nodes { + if !task.skip { + all.Insert(name) + } } log := logf.Log.WithName("flow").WithValues(logKeyFlow, flow.name) @@ -200,6 +207,19 @@ type execution struct { } func (e *execution) runNode(ctx context.Context, id TaskID) { + log := e.log.WithValues(logKeyTask, id) + + node := e.flow.nodes[id] + if node.skip { + log.V(1).Info("Skipped") + e.stats.Skipped.Insert(id) + go func() { + e.done <- &nodeResult{TaskID: id, Error: nil, skipped: true} + }() + + return + } + if e.errorContext != nil { e.errorContext.AddErrorID(string(id)) } @@ -207,17 +227,16 @@ func (e *execution) runNode(ctx context.Context, id TaskID) { e.stats.Running.Insert(id) go func() { start := time.Now().UTC() - - e.log.WithValues(logKeyTask, id).V(1).Info("Started") - err := e.flow.nodes[id].fn(ctx) + log.V(1).Info("Started") + err := node.fn(ctx) end := time.Now().UTC() - e.log.WithValues(logKeyTask, id).V(1).Info("Finished", "duration", end.Sub(start)) + log.V(1).Info("Finished", "duration", end.Sub(start)) if err != nil { - e.log.WithValues(logKeyTask, id).Error(err, "Error") + log.Error(err, "Error") err = fmt.Errorf("task %q failed: %w", id, err) } else { - e.log.WithValues(logKeyTask, id).Info("Succeeded") + log.Info("Succeeded") } e.done <- &nodeResult{TaskID: id, Error: err} @@ -280,19 +299,26 @@ func (e *execution) run(ctx context.Context) error { } e.reportProgress(ctx) - for e.stats.Running.Len() > 0 { + for e.stats.Running.Len() > 0 || e.stats.Skipped.Len() > 0 { result := <-e.done - if result.Error != nil { - e.taskErrors = append(e.taskErrors, errorsutils.WithID(string(result.TaskID), result.Error)) - e.updateFailure(result.TaskID) - } else { - e.updateSuccess(result.TaskID) - if e.errorContext != nil && e.errorContext.HasLastErrorWithID(string(result.TaskID)) { - e.cleanErrors(ctx, result.TaskID) - } + if result.skipped { + e.stats.Skipped.Delete(result.TaskID) if cancelErr = ctx.Err(); cancelErr == nil { e.processTriggers(ctx, result.TaskID) } + } else { + if result.Error != nil { + e.taskErrors = append(e.taskErrors, errorsutils.WithID(string(result.TaskID), result.Error)) + e.updateFailure(result.TaskID) + } else { + e.updateSuccess(result.TaskID) + if e.errorContext != nil && e.errorContext.HasLastErrorWithID(string(result.TaskID)) { + e.cleanErrors(ctx, result.TaskID) + } + if cancelErr = ctx.Err(); cancelErr == nil { + e.processTriggers(ctx, result.TaskID) + } + } } e.reportProgress(ctx) } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/flow/graph.go b/vendor/github.com/gardener/gardener/pkg/utils/flow/graph.go index 8d757dce7..8cba75c52 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/flow/graph.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/flow/graph.go @@ -23,6 +23,7 @@ import ( type Task struct { Name string Fn TaskFn + SkipIf bool Dependencies TaskIDs } @@ -30,6 +31,7 @@ type Task struct { func (t *Task) Spec() *TaskSpec { return &TaskSpec{ t.Fn, + t.SkipIf, t.Dependencies.Copy(), } } @@ -38,6 +40,7 @@ func (t *Task) Spec() *TaskSpec { // the dependencies of the Task. type TaskSpec struct { Fn TaskFn + Skip bool Dependencies TaskIDs } @@ -91,6 +94,7 @@ func (g *Graph) Compile() *Flow { node := nodes.getOrCreate(taskName) node.fn = taskSpec.Fn + node.skip = taskSpec.Skip node.required = taskSpec.Dependencies.Len() } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/flow/taskfn.go b/vendor/github.com/gardener/gardener/pkg/utils/flow/taskfn.go index 60288f052..1db945334 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/flow/taskfn.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/flow/taskfn.go @@ -35,24 +35,6 @@ type TaskFn func(ctx context.Context) error // RecoverFn is a function that can recover an error. type RecoverFn func(ctx context.Context, err error) error -// EmptyTaskFn is a TaskFn that does nothing (returns nil). -var EmptyTaskFn TaskFn = func(ctx context.Context) error { return nil } - -// SkipIf returns a TaskFn that does nothing if the condition is true, otherwise the function -// will be executed once called. -func (t TaskFn) SkipIf(condition bool) TaskFn { - if condition { - return EmptyTaskFn - } - return t -} - -// DoIf returns a TaskFn that will be executed if the condition is true when it is called. -// Otherwise, it will do nothing when called. -func (t TaskFn) DoIf(condition bool) TaskFn { - return t.SkipIf(!condition) -} - // Timeout returns a TaskFn that is bound to a context which times out. func (t TaskFn) Timeout(timeout time.Duration) TaskFn { return func(ctx context.Context) error { diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/deletion_confirmation.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/deletion_confirmation.go index 5037f54a9..4c1939f64 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/gardener/deletion_confirmation.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/deletion_confirmation.go @@ -54,7 +54,7 @@ func CheckIfDeletionIsConfirmed(obj client.Object) error { } // ConfirmDeletion adds Gardener's deletion confirmation and timestamp annotation to the given object and sends a PATCH -// request. It does not ignore `NotFound` errors while patching. +// request. func ConfirmDeletion(ctx context.Context, w client.Writer, obj client.Object) error { patch := client.MergeFrom(obj.DeepCopyObject().(client.Object)) kubernetesutils.SetMetaDataAnnotation(obj, ConfirmationDeletion, "true") diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/machines.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/machines.go new file mode 100644 index 000000000..ca2b557c3 --- /dev/null +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/machines.go @@ -0,0 +1,170 @@ +// Copyright 2023 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gardener + +import ( + "context" + "fmt" + "strings" + "time" + + machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" + retryutils "github.com/gardener/gardener/pkg/utils/retry" +) + +const ( + nameLabel = "name" + // MachineSetKind is the kind of the owner reference of a machine set + MachineSetKind = "MachineSet" + // MachineDeploymentKind is the kind of the owner reference of a machine deployment + MachineDeploymentKind = "MachineDeployment" +) + +// BuildOwnerToMachinesMap returns a map that associates `MachineSet` names to the given `machines`. +func BuildOwnerToMachinesMap(machines []machinev1alpha1.Machine) map[string][]machinev1alpha1.Machine { + ownerToMachines := make(map[string][]machinev1alpha1.Machine) + for index, machine := range machines { + if len(machine.OwnerReferences) > 0 { + for _, reference := range machine.OwnerReferences { + if reference.Kind == MachineSetKind { + ownerToMachines[reference.Name] = append(ownerToMachines[reference.Name], machines[index]) + } + } + } else if len(machine.Labels) > 0 { + if machineDeploymentName, ok := machine.Labels[nameLabel]; ok { + ownerToMachines[machineDeploymentName] = append(ownerToMachines[machineDeploymentName], machines[index]) + } + } + } + return ownerToMachines +} + +// BuildOwnerToMachineSetsMap returns a map that associates `MachineDeployment` names to the given `machineSets`. +func BuildOwnerToMachineSetsMap(machineSets []machinev1alpha1.MachineSet) map[string][]machinev1alpha1.MachineSet { + ownerToMachineSets := make(map[string][]machinev1alpha1.MachineSet) + for index, machineSet := range machineSets { + if len(machineSet.OwnerReferences) > 0 { + for _, reference := range machineSet.OwnerReferences { + if reference.Kind == MachineDeploymentKind { + ownerToMachineSets[reference.Name] = append(ownerToMachineSets[reference.Name], machineSets[index]) + } + } + } else if len(machineSet.Labels) > 0 { + if machineDeploymentName, ok := machineSet.Labels[nameLabel]; ok { + ownerToMachineSets[machineDeploymentName] = append(ownerToMachineSets[machineDeploymentName], machineSets[index]) + } + } + } + return ownerToMachineSets +} + +// WaitUntilMachineResourcesDeleted waits for a maximum of 30 minutes until all machine resources have been properly +// deleted by the machine-controller-manager. It polls the status every 5 seconds. +func WaitUntilMachineResourcesDeleted(ctx context.Context, log logr.Logger, reader client.Reader, namespace string) error { + var ( + countMachines = -1 + countMachineSets = -1 + countMachineDeployments = -1 + countMachineClasses = -1 + countMachineClassSecrets = -1 + ) + log.Info("Waiting until all machine resources have been deleted") + + return retryutils.UntilTimeout(ctx, 5*time.Second, 5*time.Minute, func(ctx context.Context) (bool, error) { + var msg string + + // Check whether all machines have been deleted. + if countMachines != 0 { + machineList := &metav1.PartialObjectMetadataList{} + machineList.SetGroupVersionKind(machinev1alpha1.SchemeGroupVersion.WithKind("MachineList")) + if err := reader.List(ctx, machineList, client.InNamespace(namespace)); err != nil { + return retryutils.SevereError(err) + } + countMachines = len(machineList.Items) + msg += fmt.Sprintf("%d machines, ", countMachines) + } + + // Check whether all machine sets have been deleted. + if countMachineSets != 0 { + machineSetList := &metav1.PartialObjectMetadataList{} + machineSetList.SetGroupVersionKind(machinev1alpha1.SchemeGroupVersion.WithKind("MachineSetList")) + if err := reader.List(ctx, machineSetList, client.InNamespace(namespace)); err != nil { + return retryutils.SevereError(err) + } + countMachineSets = len(machineSetList.Items) + msg += fmt.Sprintf("%d machine sets, ", countMachineSets) + } + + // Check whether all machine deployments have been deleted. + if countMachineDeployments != 0 { + machineDeploymentList := &machinev1alpha1.MachineDeploymentList{} + if err := reader.List(ctx, machineDeploymentList, client.InNamespace(namespace)); err != nil { + return retryutils.SevereError(err) + } + countMachineDeployments = len(machineDeploymentList.Items) + msg += fmt.Sprintf("%d machine deployments, ", countMachineDeployments) + + // Check whether an operation failed during the deletion process. + for _, existingMachineDeployment := range machineDeploymentList.Items { + for _, failedMachine := range existingMachineDeployment.Status.FailedMachines { + return retryutils.SevereError(fmt.Errorf("machine %s failed: %s", failedMachine.Name, failedMachine.LastOperation.Description)) + } + } + } + + // Check whether all machine classes have been deleted. + if countMachineClasses != 0 { + machineClassList := &metav1.PartialObjectMetadataList{} + machineClassList.SetGroupVersionKind(machinev1alpha1.SchemeGroupVersion.WithKind("MachineClassList")) + if err := reader.List(ctx, machineClassList, client.InNamespace(namespace)); err != nil { + return retryutils.SevereError(err) + } + countMachineClasses = len(machineClassList.Items) + msg += fmt.Sprintf("%d machine classes, ", countMachineClasses) + } + + // Check whether all machine class secrets have been deleted. + if countMachineClassSecrets != 0 { + count := 0 + machineClassSecretsList := &metav1.PartialObjectMetadataList{} + machineClassSecretsList.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("SecretList")) + if err := reader.List(ctx, machineClassSecretsList, client.InNamespace(namespace), client.MatchingLabels(map[string]string{v1beta1constants.GardenerPurpose: v1beta1constants.GardenPurposeMachineClass})); err != nil { + return retryutils.SevereError(err) + } + for _, machineClassSecret := range machineClassSecretsList.Items { + if len(machineClassSecret.Finalizers) != 0 { + count++ + } + } + countMachineClassSecrets = count + msg += fmt.Sprintf("%d machine class secrets, ", countMachineClassSecrets) + } + + if countMachines != 0 || countMachineSets != 0 || countMachineDeployments != 0 || countMachineClasses != 0 || countMachineClassSecrets != 0 { + log.Info("Waiting until machine resources have been deleted", + "machines", countMachines, "machineSets", countMachineSets, "machineDeployments", countMachineDeployments, + "machineClasses", countMachineClasses, "machineClassSecrets", countMachineClassSecrets) + return retryutils.MinorError(fmt.Errorf("waiting until the following machine resources have been deleted: %s", strings.TrimSuffix(msg, ", "))) + } + + return retryutils.Ok() + }) +} diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/networkpolicy.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/networkpolicy.go index 34dce4548..7edf4e956 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/gardener/networkpolicy.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/networkpolicy.go @@ -70,6 +70,6 @@ func InjectNetworkPolicyNamespaceSelectors(service *corev1.Service, selectors .. // NetworkPolicyLabel returns the network policy label for a component initiating the connection to a service with the // given name and TCP port. -func NetworkPolicyLabel(serviceName string, port int) string { +func NetworkPolicyLabel(serviceName string, port int32) string { return fmt.Sprintf("networking.resources.gardener.cloud/to-%s-tcp-%d", serviceName, port) } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/seed.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/seed.go index 769ee7c7a..eacfb23d1 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/gardener/seed.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/seed.go @@ -23,7 +23,6 @@ import ( certificatesv1 "k8s.io/api/certificates/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/util/sets" "sigs.k8s.io/controller-runtime/pkg/client" @@ -32,8 +31,6 @@ import ( v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" - operatorv1alpha1 "github.com/gardener/gardener/pkg/apis/operator/v1alpha1" - kubernetesutils "github.com/gardener/gardener/pkg/utils/kubernetes" ) const ( @@ -128,18 +125,6 @@ func GetWildcardCertificate(ctx context.Context, c client.Client) (*corev1.Secre return nil, nil } -// SeedIsGarden returns 'true' if the cluster is registered as a Garden cluster. -func SeedIsGarden(ctx context.Context, seedClient client.Reader) (bool, error) { - seedIsGarden, err := kubernetesutils.ResourcesExist(ctx, seedClient, operatorv1alpha1.SchemeGroupVersion.WithKind("GardenList")) - if err != nil { - if !meta.IsNoMatchError(err) { - return false, err - } - seedIsGarden = false - } - return seedIsGarden, nil -} - // ComputeRequiredExtensionsForSeed computes the extension kind/type combinations that are required for the // seed reconciliation flow. func ComputeRequiredExtensionsForSeed(seed *gardencorev1beta1.Seed) sets.Set[string] { diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/shoot.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shoot.go index d0a02423b..9c65e2a36 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/gardener/shoot.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shoot.go @@ -185,10 +185,6 @@ func NodeLabelsForWorkerPool(workerPool gardencorev1beta1.Worker, nodeLocalDNSEn labels[v1beta1constants.LabelWorkerPool] = workerPool.Name labels[v1beta1constants.LabelWorkerPoolDeprecated] = workerPool.Name - // worker pool image labels - labels[v1beta1constants.LabelWorkerPoolImageName] = workerPool.Machine.Image.Name - labels[v1beta1constants.LabelWorkerPoolImageVersion] = *workerPool.Machine.Image.Version - // add CRI labels selected by the RuntimeClass if workerPool.CRI != nil { labels[extensionsv1alpha1.CRINameWorkerLabel] = string(workerPool.CRI.Name) diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/machines.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/machines.go new file mode 100644 index 000000000..1ddee3624 --- /dev/null +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/machines.go @@ -0,0 +1,226 @@ +// Copyright 2023 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shootstate + +import ( + "bytes" + "cmp" + "compress/gzip" + "context" + "encoding/json" + "fmt" + "slices" + + machinev1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" +) + +// MachineDeploymentState stores the last versions of the machine sets and machines to which the machine deployment +// corresponds. +type MachineDeploymentState struct { + Replicas int32 `json:"replicas,omitempty"` + MachineSets []machinev1alpha1.MachineSet `json:"machineSets,omitempty"` + Machines []machinev1alpha1.Machine `json:"machines,omitempty"` +} + +// MachineState represent the last known state of the machines. +type MachineState struct { + MachineDeployments map[string]*MachineDeploymentState `json:"machineDeployments,omitempty"` +} + +func computeMachineState(ctx context.Context, seedClient client.Client, namespace, shootName string) (*MachineState, error) { + state := &MachineState{MachineDeployments: make(map[string]*MachineDeploymentState)} + + machineDeployments := &machinev1alpha1.MachineDeploymentList{} + if err := seedClient.List(ctx, machineDeployments, client.InNamespace(namespace)); err != nil { + return nil, err + } + + // If a provider extensions uses a version < v1.82 of the extensions library, then the Worker controller will have + // persisted the machine state to the `Worker`'s `.status.state` field and already shallow-deleted all machine + // objects before below code gets executed (i.e., before gardenlet can compute the machine state itself). + // In this case, let's get the data from the `Worker`'s `.status.state` field instead of trying to (re-)compute it + // (which will fail anyways). + // TODO(rfranzke): Remove this block after Gardener v1.86 has been released. + if len(machineDeployments.Items) == 0 { + worker := &extensionsv1alpha1.Worker{ObjectMeta: metav1.ObjectMeta{Name: shootName, Namespace: namespace}} + if err := seedClient.Get(ctx, client.ObjectKeyFromObject(worker), worker); client.IgnoreNotFound(err) != nil { + return nil, fmt.Errorf("failed reading Worker object %s: %w", client.ObjectKeyFromObject(worker), err) + } + + if worker.Status.State != nil && len(worker.Status.State.Raw) > 0 { + if err := json.Unmarshal(worker.Status.State.Raw, &state); err != nil { + return nil, fmt.Errorf("failed unmarshaling machine state from Worker's '.status.state' field: %w", err) + } + return state, nil + } + } + + machineDeploymentToMachineSets, err := getMachineDeploymentToMachineSetsMap(ctx, seedClient, namespace) + if err != nil { + return nil, err + } + + machineSetToMachines, err := getMachineSetToMachinesMap(ctx, seedClient, namespace) + if err != nil { + return nil, err + } + + var allMachines []machinev1alpha1.Machine + for _, machineDeployment := range machineDeployments.Items { + machineSets, ok := machineDeploymentToMachineSets[machineDeployment.Name] + if !ok { + continue + } + + for i, machineSet := range machineSets { + // remove irrelevant data from the machine set + machineSets[i].ObjectMeta = metav1.ObjectMeta{ + Name: machineSet.Name, + Namespace: machineSet.Namespace, + Annotations: machineSet.Annotations, + Labels: machineSet.Labels, + } + machineSets[i].Status = machinev1alpha1.MachineSetStatus{} + + // fetch machines related to the machine set/deployment + machines := append(machineSetToMachines[machineSet.Name], machineSetToMachines[machineDeployment.Name]...) + if len(machines) == 0 { + continue + } + + for j, machine := range machines { + // remove irrelevant data from the machine + machines[j].ObjectMeta = metav1.ObjectMeta{ + Name: machine.Name, + Namespace: machine.Namespace, + Annotations: machine.Annotations, + Labels: machine.Labels, + } + machines[j].Status = machinev1alpha1.MachineStatus{} + } + + allMachines = append(allMachines, machines...) + } + + state.MachineDeployments[machineDeployment.Name] = &MachineDeploymentState{ + Replicas: machineDeployment.Spec.Replicas, + MachineSets: machineSets, + Machines: allMachines, + } + } + + return state, nil +} + +func getMachineDeploymentToMachineSetsMap(ctx context.Context, c client.Client, namespace string) (map[string][]machinev1alpha1.MachineSet, error) { + existingMachineSets := &machinev1alpha1.MachineSetList{} + if err := c.List(ctx, existingMachineSets, client.InNamespace(namespace)); err != nil { + return nil, err + } + + // When we read from the cache we get unsorted results, hence, we sort to prevent unnecessary state updates from + // happening. + slices.SortFunc(existingMachineSets.Items, func(a, b machinev1alpha1.MachineSet) int { + return cmp.Compare(a.Name, b.Name) + }) + + return gardenerutils.BuildOwnerToMachineSetsMap(existingMachineSets.Items), nil +} + +func getMachineSetToMachinesMap(ctx context.Context, seedClient client.Client, namespace string) (map[string][]machinev1alpha1.Machine, error) { + existingMachines := &machinev1alpha1.MachineList{} + if err := seedClient.List(ctx, existingMachines, client.InNamespace(namespace)); err != nil { + return nil, err + } + + // We temporarily filter out machines without provider ID or node label (VMs which got created but not yet joined + // the cluster) to prevent unnecessarily persisting them in the Worker state. + // TODO: Remove this again once machine-controller-manager supports backing off creation/deletion of failed + // machines, see https://github.com/gardener/machine-controller-manager/issues/483. + var filteredMachines []machinev1alpha1.Machine + for _, machine := range existingMachines.Items { + if _, ok := machine.Labels["node"]; ok || machine.Spec.ProviderID != "" { + filteredMachines = append(filteredMachines, machine) + } + } + + // When we read from the cache we get unsorted results, hence, we sort to prevent unnecessary state updates from + // happening. + slices.SortFunc(filteredMachines, func(a, b machinev1alpha1.Machine) int { + return cmp.Compare(a.Name, b.Name) + }) + + return gardenerutils.BuildOwnerToMachinesMap(filteredMachines), nil +} + +type compressedMachineState struct { + State []byte `json:"state"` +} + +func compressMachineState(state []byte) ([]byte, error) { + if len(state) == 0 || string(state) == "{}" { + return nil, nil + } + + var stateCompressed bytes.Buffer + gzipWriter, err := gzip.NewWriterLevel(&stateCompressed, gzip.BestCompression) + if err != nil { + return nil, fmt.Errorf("failed creating gzip writer for compressing machine state data: %w", err) + } + defer gzipWriter.Close() + + if _, err := gzipWriter.Write(state); err != nil { + return nil, fmt.Errorf("failed writing machine state data for compression: %w", err) + } + + // Close ensures any unwritten data is flushed and the gzip footer is written. Without this, the `stateCompressed` + // buffer would not contain any data. Hence, we have to call it explicitly here after writing, in addition to the + // 'defer' call above. + if err := gzipWriter.Close(); err != nil { + return nil, fmt.Errorf("failed closing the gzip writer after compressing the machine state data: %w", err) + } + + return json.Marshal(&compressedMachineState{State: stateCompressed.Bytes()}) +} + +// DecompressMachineState decompresses the machine state data. +func DecompressMachineState(stateCompressed []byte) ([]byte, error) { + if len(stateCompressed) == 0 { + return nil, nil + } + + var machineState compressedMachineState + if err := json.Unmarshal(stateCompressed, &machineState); err != nil { + return nil, fmt.Errorf("failed unmarshalling JSON to compressed machine state structure: %w", err) + } + + gzipReader, err := gzip.NewReader(bytes.NewReader(machineState.State)) + if err != nil { + return nil, fmt.Errorf("failed creating gzip reader for decompressing machine state data: %w", err) + } + defer gzipReader.Close() + + var state bytes.Buffer + if _, err := state.ReadFrom(gzipReader); err != nil { + return nil, fmt.Errorf("failed reading machine state data for decompression: %w", err) + } + + return state.Bytes(), nil +} diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/shootstate.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/shootstate.go new file mode 100644 index 000000000..04ad3acc6 --- /dev/null +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/shootstate/shootstate.go @@ -0,0 +1,281 @@ +// Copyright 2023 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shootstate + +import ( + "context" + "encoding/json" + "fmt" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/clock" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/client" + + apiextensions "github.com/gardener/gardener/pkg/api/extensions" + gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" + v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" + v1beta1helper "github.com/gardener/gardener/pkg/apis/core/v1beta1/helper" + extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" + "github.com/gardener/gardener/pkg/controllerutils" + gardenerutils "github.com/gardener/gardener/pkg/utils/gardener" + unstructuredutils "github.com/gardener/gardener/pkg/utils/kubernetes/unstructured" + secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" +) + +// Deploy deploys the ShootState resource with the effective state for the given shoot into the garden +// cluster. +func Deploy(ctx context.Context, clock clock.Clock, gardenClient, seedClient client.Client, shoot *gardencorev1beta1.Shoot, overwriteSpec bool) error { + shootState := &gardencorev1beta1.ShootState{ + ObjectMeta: metav1.ObjectMeta{ + Name: shoot.Name, + Namespace: shoot.Namespace, + }, + } + + spec, err := computeSpec(ctx, seedClient, shoot.Status.TechnicalID, shoot.Name) + if err != nil { + return fmt.Errorf("failed computing spec of ShootState for shoot %s: %w", client.ObjectKeyFromObject(shoot), err) + } + + _, err = controllerutils.GetAndCreateOrStrategicMergePatch(ctx, gardenClient, shootState, func() error { + metav1.SetMetaDataAnnotation(&shootState.ObjectMeta, v1beta1constants.GardenerTimestamp, clock.Now().UTC().Format(time.RFC3339)) + + if overwriteSpec { + shootState.Spec = *spec + return nil + } + + gardenerData := v1beta1helper.GardenerResourceDataList(shootState.Spec.Gardener) + for _, data := range spec.Gardener { + gardenerData.Upsert(data.DeepCopy()) + } + shootState.Spec.Gardener = gardenerData + + extensionsData := v1beta1helper.ExtensionResourceStateList(shootState.Spec.Extensions) + for _, data := range spec.Extensions { + extensionsData.Upsert(data.DeepCopy()) + } + // Temporarily not persist the Worker state since this data is already explicitly persisted by gardenlet in `.spec.gardener[]`. + // TODO(rfranzke): Delete the next line after Gardener v1.86 has been released. + extensionsData.Delete(extensionsv1alpha1.WorkerResource, &shoot.Name, nil) + shootState.Spec.Extensions = extensionsData + + resourcesData := v1beta1helper.ResourceDataList(shootState.Spec.Resources) + for _, data := range spec.Resources { + resourcesData.Upsert(data.DeepCopy()) + } + shootState.Spec.Resources = resourcesData + + return nil + }) + return err +} + +// Delete deletes the ShootState resource for the given shoot from the garden cluster. +func Delete(ctx context.Context, gardenClient client.Client, shoot *gardencorev1beta1.Shoot) error { + shootState := &gardencorev1beta1.ShootState{ + ObjectMeta: metav1.ObjectMeta{ + Name: shoot.Name, + Namespace: shoot.Namespace, + }, + } + + if err := gardenerutils.ConfirmDeletion(ctx, gardenClient, shootState); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + return client.IgnoreNotFound(gardenClient.Delete(ctx, shootState)) +} + +func computeSpec(ctx context.Context, seedClient client.Client, seedNamespace, shootName string) (*gardencorev1beta1.ShootStateSpec, error) { + gardener, err := computeGardenerData(ctx, seedClient, seedNamespace, shootName) + if err != nil { + return nil, fmt.Errorf("failed computing Gardener data: %w", err) + } + + extensions, resources, err := computeExtensionsDataAndResources(ctx, seedClient, seedNamespace) + if err != nil { + return nil, fmt.Errorf("failed computing extensions data and resources: %w", err) + } + + return &gardencorev1beta1.ShootStateSpec{ + Gardener: gardener, + Extensions: extensions, + Resources: resources, + }, nil +} + +func computeGardenerData( + ctx context.Context, + seedClient client.Client, + seedNamespace string, + shootName string, +) ( + []gardencorev1beta1.GardenerResourceData, + error, +) { + secretsToPersist, err := computeSecretsToPersist(ctx, seedClient, seedNamespace) + if err != nil { + return nil, err + } + + machineState, err := computeMachineState(ctx, seedClient, seedNamespace, shootName) + if err != nil { + return nil, err + } + + machineStateJSON, err := json.Marshal(machineState) + if err != nil { + return nil, fmt.Errorf("failed marshalling machine state to JSON: %w", err) + } + + machineStateJSONCompressed, err := compressMachineState(machineStateJSON) + if err != nil { + return nil, fmt.Errorf("failed compressing machine state data: %w", err) + } + + return append(secretsToPersist, gardencorev1beta1.GardenerResourceData{ + Name: v1beta1constants.DataTypeMachineState, + Type: v1beta1constants.DataTypeMachineState, + Data: runtime.RawExtension{Raw: machineStateJSONCompressed}, + }), nil +} + +func computeSecretsToPersist( + ctx context.Context, + seedClient client.Client, + seedNamespace string, +) ( + []gardencorev1beta1.GardenerResourceData, + error, +) { + secretList := &corev1.SecretList{} + if err := seedClient.List(ctx, secretList, client.InNamespace(seedNamespace), client.MatchingLabels{ + secretsmanager.LabelKeyManagedBy: secretsmanager.LabelValueSecretsManager, + secretsmanager.LabelKeyPersist: secretsmanager.LabelValueTrue, + }); err != nil { + return nil, fmt.Errorf("failed listing all secrets that must be persisted: %w", err) + } + + dataList := make([]gardencorev1beta1.GardenerResourceData, 0, len(secretList.Items)) + + for _, secret := range secretList.Items { + dataJSON, err := json.Marshal(secret.Data) + if err != nil { + return nil, fmt.Errorf("failed marshalling secret data to JSON for secret %s: %w", client.ObjectKeyFromObject(&secret), err) + } + + dataList = append(dataList, gardencorev1beta1.GardenerResourceData{ + Name: secret.Name, + Labels: secret.Labels, + Type: v1beta1constants.DataTypeSecret, + Data: runtime.RawExtension{Raw: dataJSON}, + }) + } + + return dataList, nil +} + +func computeExtensionsDataAndResources( + ctx context.Context, + seedClient client.Client, + seedNamespace string, +) ( + []gardencorev1beta1.ExtensionResourceState, + []gardencorev1beta1.ResourceData, + error, +) { + var ( + dataList []gardencorev1beta1.ExtensionResourceState + resources []gardencorev1beta1.ResourceData + ) + + for _, extension := range []struct { + objKind string + newObjectListFunc func() client.ObjectList + }{ + {extensionsv1alpha1.BackupEntryResource, func() client.ObjectList { return &extensionsv1alpha1.BackupEntryList{} }}, + {extensionsv1alpha1.ContainerRuntimeResource, func() client.ObjectList { return &extensionsv1alpha1.ContainerRuntimeList{} }}, + {extensionsv1alpha1.ControlPlaneResource, func() client.ObjectList { return &extensionsv1alpha1.ControlPlaneList{} }}, + {extensionsv1alpha1.DNSRecordResource, func() client.ObjectList { return &extensionsv1alpha1.DNSRecordList{} }}, + {extensionsv1alpha1.ExtensionResource, func() client.ObjectList { return &extensionsv1alpha1.ExtensionList{} }}, + {extensionsv1alpha1.InfrastructureResource, func() client.ObjectList { return &extensionsv1alpha1.InfrastructureList{} }}, + {extensionsv1alpha1.NetworkResource, func() client.ObjectList { return &extensionsv1alpha1.NetworkList{} }}, + {extensionsv1alpha1.OperatingSystemConfigResource, func() client.ObjectList { return &extensionsv1alpha1.OperatingSystemConfigList{} }}, + // Temporarily not persist the Worker state since this data is already explicitly persisted by gardenlet in `.spec.gardener[]`. + // TODO(rfranzke): Uncomment next line after Gardener v1.86 has been released. + // {extensionsv1alpha1.WorkerResource, func() client.ObjectList { return &extensionsv1alpha1.WorkerList{} }}, + } { + objList := extension.newObjectListFunc() + if err := seedClient.List(ctx, objList, client.InNamespace(seedNamespace)); err != nil { + return nil, nil, fmt.Errorf("failed to list extension resources of kind %s: %w", extension.objKind, err) + } + + if err := meta.EachListItem(objList, func(obj runtime.Object) error { + extensionObj, err := apiextensions.Accessor(obj) + if err != nil { + return fmt.Errorf("failed accessing extension object: %w", err) + } + + if extensionObj.GetDeletionTimestamp() != nil || + (extensionObj.GetExtensionStatus().GetState() == nil && len(extensionObj.GetExtensionStatus().GetResources()) == 0) { + return nil + } + + dataList = append(dataList, gardencorev1beta1.ExtensionResourceState{ + Kind: extension.objKind, + Name: pointer.String(extensionObj.GetName()), + Purpose: extensionObj.GetExtensionSpec().GetExtensionPurpose(), + State: extensionObj.GetExtensionStatus().GetState(), + Resources: extensionObj.GetExtensionStatus().GetResources(), + }) + + for _, newResource := range extensionObj.GetExtensionStatus().GetResources() { + referencedObj, err := unstructuredutils.GetObjectByRef(ctx, seedClient, &newResource.ResourceRef, seedNamespace) + if err != nil { + return fmt.Errorf("failed reading referenced object %s: %w", client.ObjectKey{Name: newResource.ResourceRef.Name, Namespace: seedNamespace}, err) + } + if obj == nil { + return fmt.Errorf("object %v not found", newResource.ResourceRef) + } + + raw := &runtime.RawExtension{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(referencedObj, raw); err != nil { + return fmt.Errorf("failed converting referenced object %s to raw extension: %w", client.ObjectKey{Name: newResource.ResourceRef.Name, Namespace: seedNamespace}, err) + } + + resources = append(resources, gardencorev1beta1.ResourceData{ + CrossVersionObjectReference: newResource.ResourceRef, + Data: *raw, + }) + } + + return nil + }); err != nil { + return nil, nil, fmt.Errorf("failed computing extension data for kind %s: %w", extension.objKind, err) + } + } + + return dataList, resources, nil +} diff --git a/vendor/github.com/gardener/gardener/pkg/utils/gardener/topology_aware_routing.go b/vendor/github.com/gardener/gardener/pkg/utils/gardener/topology_aware_routing.go index efbc3da75..658cd529d 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/gardener/topology_aware_routing.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/gardener/topology_aware_routing.go @@ -15,7 +15,7 @@ package gardener import ( - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/vendor/github.com/gardener/gardener/pkg/utils/imagevector/imagevector_validation.go b/vendor/github.com/gardener/gardener/pkg/utils/imagevector/imagevector_validation.go index 81261f27b..2ad866e9c 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/imagevector/imagevector_validation.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/imagevector/imagevector_validation.go @@ -15,7 +15,7 @@ package imagevector import ( - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "k8s.io/apimachinery/pkg/util/validation/field" ) diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/admissionplugins.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/admissionplugins.go index 3e5bf3d16..274d400de 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/admissionplugins.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/admissionplugins.go @@ -17,18 +17,17 @@ package kubernetes import ( "fmt" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1" ) var ( - lowestSupportedKubernetesVersionMajorMinor = "1.22" + lowestSupportedKubernetesVersionMajorMinor = "1.24" lowestSupportedKubernetesVersion, _ = semver.NewVersion(lowestSupportedKubernetesVersionMajorMinor) admissionPlugins = map[string][]gardencorev1beta1.AdmissionPlugin{ - "1.22": getDefaultPlugins("1.22"), - "1.23": getDefaultPlugins("1.23"), + "1.24": getDefaultPlugins("1.24"), "1.25": getDefaultPlugins("1.25"), } ) @@ -65,22 +64,7 @@ func getAdmissionPluginsForVersionInternal(v string) []gardencorev1beta1.Admissi func getDefaultPlugins(version string) []gardencorev1beta1.AdmissionPlugin { var admissionPlugins []gardencorev1beta1.AdmissionPlugin switch version { - case "1.22": - admissionPlugins = append(admissionPlugins, []gardencorev1beta1.AdmissionPlugin{ - {Name: "Priority"}, - {Name: "NamespaceLifecycle"}, - {Name: "LimitRanger"}, - {Name: "PodSecurityPolicy"}, - {Name: "ServiceAccount"}, - {Name: "NodeRestriction"}, - {Name: "DefaultStorageClass"}, - {Name: "DefaultTolerationSeconds"}, - {Name: "ResourceQuota"}, - {Name: "StorageObjectInUseProtection"}, - {Name: "MutatingAdmissionWebhook"}, - {Name: "ValidatingAdmissionWebhook"}, - }...) - case "1.23": + case "1.24": admissionPlugins = append(admissionPlugins, []gardencorev1beta1.AdmissionPlugin{ {Name: "Priority"}, {Name: "NamespaceLifecycle"}, @@ -115,7 +99,7 @@ func getDefaultPlugins(version string) []gardencorev1beta1.AdmissionPlugin { return admissionPlugins } -func formatMajorMinor(major, minor int64) string { +func formatMajorMinor(major, minor uint64) string { return fmt.Sprintf("%d.%d", major, minor) } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/deployment.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/deployment.go index c28c363ec..00fa0b51f 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/deployment.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/deployment.go @@ -19,7 +19,7 @@ import ( "fmt" "strings" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/health/daemonset.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/health/daemonset.go index 577259707..e3f6985ed 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/health/daemonset.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/health/daemonset.go @@ -31,7 +31,7 @@ func daemonSetMaxUnavailable(daemonSet *appsv1.DaemonSet) int32 { return 0 } - maxUnavailable, err := intstr.GetValueFromIntOrPercent(rollingUpdate.MaxUnavailable, int(daemonSet.Status.DesiredNumberScheduled), false) + maxUnavailable, err := intstr.GetScaledValueFromIntOrPercent(rollingUpdate.MaxUnavailable, int(daemonSet.Status.DesiredNumberScheduled), false) if err != nil { return 0 } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/object.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/object.go index 148eab9f8..8080383d3 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/object.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/object.go @@ -23,10 +23,11 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/cache" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "github.com/gardener/gardener/pkg/resourcemanager/controller/garbagecollector/references" "github.com/gardener/gardener/pkg/utils" @@ -87,17 +88,54 @@ func DeleteObjectsFromListConditionally(ctx context.Context, c client.Client, li return flow.Parallel(fns...)(ctx) } -// ResourcesExist checks if there is at least one object of the given gvk. The kind in the gvk must be the list kind, -// for example corev1.SchemeGroupVersion.WithKind("PodList"). -func ResourcesExist(ctx context.Context, reader client.Reader, gvk schema.GroupVersionKind, listOpts ...client.ListOption) (bool, error) { - objects := &metav1.PartialObjectMetadataList{} - objects.SetGroupVersionKind(gvk) +// ResourcesExist checks if there is at least one object of the given objList. +func ResourcesExist(ctx context.Context, reader client.Reader, objList client.ObjectList, scheme *runtime.Scheme, listOpts ...client.ListOption) (bool, error) { + objects := objList + + // Use `PartialObjectMetadata` if no or metadata only field selectors are passed (informer's indexers only have access to metadata fields). + if hasNoOrMetadataOnlyFieldSelector(listOpts...) { + gvk, err := apiutil.GVKForObject(objList, scheme) + if err != nil { + return false, err + } + + objects = &metav1.PartialObjectMetadataList{} + objects.(*metav1.PartialObjectMetadataList).SetGroupVersionKind(gvk) + } if err := reader.List(ctx, objects, append(listOpts, client.Limit(1))...); err != nil { return true, err } - return len(objects.Items) > 0, nil + switch o := objects.(type) { + case *metav1.PartialObjectMetadataList: + return len(o.Items) > 0, nil + default: + items, err := meta.ExtractList(objList) + if err != nil { + return false, err + } + return len(items) > 0, err + } +} + +func hasNoOrMetadataOnlyFieldSelector(listOpts ...client.ListOption) bool { + listOptions := &client.ListOptions{} + for _, opt := range listOpts { + opt.ApplyToList(listOptions) + } + + if listOptions.FieldSelector == nil { + return true + } + + for _, req := range listOptions.FieldSelector.Requirements() { + if !strings.HasPrefix(req.Field, "metadata") && req.Field != cache.NamespaceIndex { + return false + } + } + + return true } // MakeUnique takes either a *corev1.ConfigMap or a *corev1.Secret object and makes it immutable, i.e., it sets diff --git a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/tls_cipher_suites.go b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/tls_cipher_suites.go index 692bf9a73..70ad51353 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/tls_cipher_suites.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/kubernetes/tls_cipher_suites.go @@ -14,38 +14,15 @@ package kubernetes -import ( - "github.com/Masterminds/semver" - - "github.com/gardener/gardener/pkg/utils/version" -) - -// TLSCipherSuites returns the wanted and acceptable cipher suits depending on the passed Kubernetes version. -func TLSCipherSuites(k8sVersion *semver.Version) []string { - var ( - commonSuites = []string{ - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - } - tlsV13Suites = append(commonSuites, - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - ) - ) - - if k8sVersion == nil || !version.ConstraintK8sEqual122.Check(k8sVersion) { - // For Kubernetes >= 1.23 the Cipher list was again adapted as described in - // https://github.com/gardener/gardener/issues/4823#issue-1022865330 - return append(tlsV13Suites, - "TLS_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - ) - } - - // For Kubernetes 1.22 Gardener only allows suites permissible for TLS 1.3 - // see https://github.com/gardener/gardener/issues/4300#issuecomment-885498872 - return tlsV13Suites +// TLSCipherSuites is a list of the wanted and acceptable cipher suits. +var TLSCipherSuites = []string{ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/miscellaneous.go b/vendor/github.com/gardener/gardener/pkg/utils/miscellaneous.go index 541a99e60..944848e23 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/miscellaneous.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/miscellaneous.go @@ -159,9 +159,9 @@ func TimePtrDeref(ptr *time.Time, def time.Time) time.Time { return def } -// IntStrPtrFromInt returns an intstr.IntOrString pointer to its argument. -func IntStrPtrFromInt(port int) *intstr.IntOrString { - v := intstr.FromInt(port) +// IntStrPtrFromInt32 returns an intstr.IntOrString pointer to its argument. +func IntStrPtrFromInt32(port int32) *intstr.IntOrString { + v := intstr.FromInt32(port) return &v } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/secrets/certificate.go b/vendor/github.com/gardener/gardener/pkg/utils/secrets/certificate.go index 6e6fc53bd..26d315e14 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/secrets/certificate.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/secrets/certificate.go @@ -59,7 +59,7 @@ const ( ) // CertificateSecretConfig contains the specification a to-be-generated CA, server, or client certificate. -// It always contains a 2048-bit RSA private key. +// It always contains a 3072-bit RSA private key. type CertificateSecretConfig struct { Name string @@ -116,7 +116,7 @@ func (s *CertificateSecretConfig) GenerateCertificate() (*Certificate, error) { // If no cert type is given then we only return a certificate object that contains the CA. if s.CertType != "" { - privateKey, err := GenerateKey(rand.Reader, 2048) + privateKey, err := GenerateKey(rand.Reader, 3072) if err != nil { return nil, err } diff --git a/vendor/github.com/gardener/gardener/pkg/utils/secrets/manager/generate.go b/vendor/github.com/gardener/gardener/pkg/utils/secrets/manager/generate.go index 60c111556..282baa693 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/secrets/manager/generate.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/secrets/manager/generate.go @@ -35,7 +35,7 @@ import ( func (m *manager) Generate(ctx context.Context, config secretsutils.ConfigInterface, opts ...GenerateOption) (*corev1.Secret, error) { options := &GenerateOptions{} if err := options.ApplyOptions(m, config, opts); err != nil { - return nil, err + return nil, fmt.Errorf("failed applying generate options for config %s: %w", config.GetName(), err) } var bundleFor *string @@ -54,46 +54,46 @@ func (m *manager) Generate(ctx context.Context, config secretsutils.ConfigInterf bundleFor, ) if err != nil { - return nil, err + return nil, fmt.Errorf("failed computing object metadata for config %s: %w", config.GetName(), err) } desiredLabels := utils.MergeStringMaps(objectMeta.Labels) // copy labels map - secret := &corev1.Secret{} - if err := m.client.Get(ctx, kubernetesutils.Key(objectMeta.Namespace, objectMeta.Name), secret); err != nil { + secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: objectMeta.Name, Namespace: objectMeta.Namespace}} + if err := m.client.Get(ctx, client.ObjectKeyFromObject(secret), secret); err != nil { if !apierrors.IsNotFound(err) { - return nil, err + return nil, fmt.Errorf("failed reading secret %s for config %s: %w", client.ObjectKeyFromObject(secret), config.GetName(), err) } secret, err = m.generateAndCreate(ctx, config, objectMeta) if err != nil { - return nil, err + return nil, fmt.Errorf("failed generating and creating new secret %s for config %s: %w", client.ObjectKey{Name: objectMeta.Name, Namespace: objectMeta.Namespace}, config.GetName(), err) } } if err := m.maintainLifetimeLabels(config, secret, desiredLabels, options.Validity); err != nil { - return nil, err + return nil, fmt.Errorf("failed maintaining lifetime labels on secret %s for config %s: %w", client.ObjectKeyFromObject(secret), config.GetName(), err) } if !options.isBundleSecret { if err := m.addToStore(config.GetName(), secret, current); err != nil { - return nil, err + return nil, fmt.Errorf("failed adding current secret %s for config %s to internal store: %w", client.ObjectKeyFromObject(secret), config.GetName(), err) } if ignore, err := m.shouldIgnoreOldSecrets(desiredLabels[LabelKeyIssuedAtTime], options); err != nil { - return nil, err + return nil, fmt.Errorf("failed checking whether old secrets should be ignored for config %s: %w", config.GetName(), err) } else if !ignore { if err := m.storeOldSecrets(ctx, config.GetName(), secret.Name); err != nil { - return nil, err + return nil, fmt.Errorf("failed adding old secrets for config %s to internal store: %w", config.GetName(), err) } } if err := m.generateBundleSecret(ctx, config); err != nil { - return nil, err + return nil, fmt.Errorf("failed generating bundle secret for config %s: %w", config.GetName(), err) } } if err := m.reconcileSecret(ctx, secret, desiredLabels); err != nil { - return nil, err + return nil, fmt.Errorf("failed reconciling existing secret %s for config %s: %w", client.ObjectKeyFromObject(secret), config.GetName(), err) } return secret, nil @@ -107,22 +107,22 @@ func (m *manager) generateAndCreate(ctx context.Context, config secretsutils.Con data, err := config.Generate() if err != nil { - return nil, err + return nil, fmt.Errorf("failed generating data: %w", err) } dataMap, err := m.keepExistingSecretsIfNeeded(ctx, config.GetName(), data.SecretData()) if err != nil { - return nil, err + return nil, fmt.Errorf("failed taking over data from existing secret when needed: %w", err) } secret := Secret(objectMeta, dataMap) if err := m.client.Create(ctx, secret); err != nil { if !apierrors.IsAlreadyExists(err) { - return nil, err + return nil, fmt.Errorf("failed creating new secret: %w", err) } if err := m.client.Get(ctx, client.ObjectKeyFromObject(secret), secret); err != nil { - return nil, err + return nil, fmt.Errorf("failed reading existing secret: %w", err) } } @@ -271,12 +271,12 @@ func (m *manager) maintainLifetimeLabels( if secret.Labels[LabelKeyValidUntilTime] != "" { issuedAtTime, err := strconv.ParseInt(issuedAt, 10, 64) if err != nil { - return err + return fmt.Errorf("failed converting %s to int64: %w", issuedAt, err) } existingValidUntilTime, err := strconv.ParseInt(secret.Labels[LabelKeyValidUntilTime], 10, 64) if err != nil { - return err + return fmt.Errorf("failed converting %s from label %s to int64: %w", secret.Labels[LabelKeyValidUntilTime], LabelKeyValidUntilTime, err) } if oldValidity := time.Duration(existingValidUntilTime - issuedAtTime); oldValidity != validity { @@ -305,7 +305,7 @@ func (m *manager) maintainLifetimeLabels( certificate, err := utils.DecodeCertificate(secret.Data[dataKeyCertificate]) if err != nil { - return fmt.Errorf("error decoding certificate when trying to maintain lifetime labels: %w", err) + return fmt.Errorf("error decoding certificate from data key %s: %w", dataKeyCertificate, err) } desiredLabels[LabelKeyIssuedAtTime] = unixTime(certificate.NotBefore) diff --git a/vendor/github.com/gardener/gardener/pkg/utils/secrets/vpn_tlsauth.go b/vendor/github.com/gardener/gardener/pkg/utils/secrets/vpn_tlsauth.go index 2d879ae9c..9674b2229 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/secrets/vpn_tlsauth.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/secrets/vpn_tlsauth.go @@ -71,7 +71,6 @@ func (v *VPNTLSAuth) SecretData() map[string][]byte { // generateVPNKey generates PSK for OpenVPN similar as generated by `openvpn --genkey` command. func generateVPNKey() ([]byte, error) { - allowedCharacters := "0123456789abcdef" keyString, err := utils.GenerateRandomStringFromCharset(512, allowedCharacters) if err != nil { diff --git a/vendor/github.com/gardener/gardener/pkg/utils/validation/kubernetesversion/version.go b/vendor/github.com/gardener/gardener/pkg/utils/validation/kubernetesversion/version.go index ad06a911f..9f9537fdf 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/validation/kubernetesversion/version.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/validation/kubernetesversion/version.go @@ -23,8 +23,6 @@ import ( // SupportedVersions is the list of supported Kubernetes versions for all runtime and target clusters, i.e. all gardens, // seeds, and shoots. var SupportedVersions = []string{ - "1.22", - "1.23", "1.24", "1.25", "1.26", diff --git a/vendor/github.com/gardener/gardener/pkg/utils/version/version.go b/vendor/github.com/gardener/gardener/pkg/utils/version/version.go index 0184ec1ea..5ba29768b 100644 --- a/vendor/github.com/gardener/gardener/pkg/utils/version/version.go +++ b/vendor/github.com/gardener/gardener/pkg/utils/version/version.go @@ -18,23 +18,13 @@ import ( "fmt" "strings" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" utilruntime "k8s.io/apimachinery/pkg/util/runtime" ) var ( - // ConstraintK8sEqual122 is a version constraint for versions == 1.22. - ConstraintK8sEqual122 *semver.Constraints - // ConstraintK8sEqual123 is a version constraint for versions == 1.23. - ConstraintK8sEqual123 *semver.Constraints - // ConstraintK8sGreaterEqual123 is a version constraint for versions >= 1.23. - ConstraintK8sGreaterEqual123 *semver.Constraints - // ConstraintK8sLess123 is a version constraint for versions < 1.23. - ConstraintK8sLess123 *semver.Constraints // ConstraintK8sEqual124 is a version constraint for versions == 1.24. ConstraintK8sEqual124 *semver.Constraints - // ConstraintK8sLess124 is a version constraint for versions < 1.24. - ConstraintK8sLess124 *semver.Constraints // ConstraintK8sGreaterEqual125 is a version constraint for versions >= 1.25. ConstraintK8sGreaterEqual125 *semver.Constraints // ConstraintK8sLess125 is a version constraint for versions < 1.25. @@ -53,18 +43,8 @@ var ( func init() { var err error - ConstraintK8sEqual122, err = semver.NewConstraint("~ 1.22.x-0") - utilruntime.Must(err) - ConstraintK8sEqual123, err = semver.NewConstraint("~ 1.23.x-0") - utilruntime.Must(err) - ConstraintK8sGreaterEqual123, err = semver.NewConstraint(">= 1.23-0") - utilruntime.Must(err) - ConstraintK8sLess123, err = semver.NewConstraint("< 1.23-0") - utilruntime.Must(err) ConstraintK8sEqual124, err = semver.NewConstraint("~ 1.24.x-0") utilruntime.Must(err) - ConstraintK8sLess124, err = semver.NewConstraint("< 1.24-0") - utilruntime.Must(err) ConstraintK8sGreaterEqual125, err = semver.NewConstraint(">= 1.25-0") utilruntime.Must(err) ConstraintK8sLess125, err = semver.NewConstraint("< 1.25-0") diff --git a/vendor/github.com/shopspring/decimal/.gitignore b/vendor/github.com/shopspring/decimal/.gitignore new file mode 100644 index 000000000..8a43ce9d7 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/.gitignore @@ -0,0 +1,6 @@ +.git +*.swp + +# IntelliJ +.idea/ +*.iml diff --git a/vendor/github.com/shopspring/decimal/.travis.yml b/vendor/github.com/shopspring/decimal/.travis.yml new file mode 100644 index 000000000..55d42b289 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/.travis.yml @@ -0,0 +1,13 @@ +language: go + +go: + - 1.7.x + - 1.12.x + - 1.13.x + - tip + +install: + - go build . + +script: + - go test -v diff --git a/vendor/github.com/shopspring/decimal/CHANGELOG.md b/vendor/github.com/shopspring/decimal/CHANGELOG.md new file mode 100644 index 000000000..01ba02feb --- /dev/null +++ b/vendor/github.com/shopspring/decimal/CHANGELOG.md @@ -0,0 +1,19 @@ +## Decimal v1.2.0 + +#### BREAKING +- Drop support for Go version older than 1.7 [#172](https://github.com/shopspring/decimal/pull/172) + +#### FEATURES +- Add NewFromInt and NewFromInt32 initializers [#72](https://github.com/shopspring/decimal/pull/72) +- Add support for Go modules [#157](https://github.com/shopspring/decimal/pull/157) +- Add BigInt, BigFloat helper methods [#171](https://github.com/shopspring/decimal/pull/171) + +#### ENHANCEMENTS +- Memory usage optimization [#160](https://github.com/shopspring/decimal/pull/160) +- Updated travis CI golang versions [#156](https://github.com/shopspring/decimal/pull/156) +- Update documentation [#173](https://github.com/shopspring/decimal/pull/173) +- Improve code quality [#174](https://github.com/shopspring/decimal/pull/174) + +#### BUGFIXES +- Revert remove insignificant digits [#159](https://github.com/shopspring/decimal/pull/159) +- Remove 15 interval for RoundCash [#166](https://github.com/shopspring/decimal/pull/166) diff --git a/vendor/github.com/shopspring/decimal/LICENSE b/vendor/github.com/shopspring/decimal/LICENSE new file mode 100644 index 000000000..ad2148aaf --- /dev/null +++ b/vendor/github.com/shopspring/decimal/LICENSE @@ -0,0 +1,45 @@ +The MIT License (MIT) + +Copyright (c) 2015 Spring, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +- Based on https://github.com/oguzbilgic/fpd, which has the following license: +""" +The MIT License (MIT) + +Copyright (c) 2013 Oguz Bilgic + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +""" diff --git a/vendor/github.com/shopspring/decimal/README.md b/vendor/github.com/shopspring/decimal/README.md new file mode 100644 index 000000000..b70f90159 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/README.md @@ -0,0 +1,130 @@ +# decimal + +[![Build Status](https://travis-ci.org/shopspring/decimal.png?branch=master)](https://travis-ci.org/shopspring/decimal) [![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal) [![Go Report Card](https://goreportcard.com/badge/github.com/shopspring/decimal)](https://goreportcard.com/report/github.com/shopspring/decimal) + +Arbitrary-precision fixed-point decimal numbers in go. + +_Note:_ Decimal library can "only" represent numbers with a maximum of 2^31 digits after the decimal point. + +## Features + + * The zero-value is 0, and is safe to use without initialization + * Addition, subtraction, multiplication with no loss of precision + * Division with specified precision + * Database/sql serialization/deserialization + * JSON and XML serialization/deserialization + +## Install + +Run `go get github.com/shopspring/decimal` + +## Requirements + +Decimal library requires Go version `>=1.7` + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/shopspring/decimal" +) + +func main() { + price, err := decimal.NewFromString("136.02") + if err != nil { + panic(err) + } + + quantity := decimal.NewFromInt(3) + + fee, _ := decimal.NewFromString(".035") + taxRate, _ := decimal.NewFromString(".08875") + + subtotal := price.Mul(quantity) + + preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1))) + + total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1))) + + fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06 + fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421 + fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375 + fmt.Println("Total:", total) // Total: 459.824961375 + fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875 +} +``` + +## Documentation + +http://godoc.org/github.com/shopspring/decimal + +## Production Usage + +* [Spring](https://shopspring.com/), since August 14, 2014. +* If you are using this in production, please let us know! + +## FAQ + +#### Why don't you just use float64? + +Because float64 (or any binary floating point type, actually) can't represent +numbers such as `0.1` exactly. + +Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that +it prints out `10`, but it actually prints `9.999999999999831`. Over time, +these small errors can really add up! + +#### Why don't you just use big.Rat? + +big.Rat is fine for representing rational numbers, but Decimal is better for +representing money. Why? Here's a (contrived) example: + +Let's say you use big.Rat, and you have two numbers, x and y, both +representing 1/3, and you have `z = 1 - x - y = 1/3`. If you print each one +out, the string output has to stop somewhere (let's say it stops at 3 decimal +digits, for simplicity), so you'll get 0.333, 0.333, and 0.333. But where did +the other 0.001 go? + +Here's the above example as code: http://play.golang.org/p/lCZZs0w9KE + +With Decimal, the strings being printed out represent the number exactly. So, +if you have `x = y = 1/3` (with precision 3), they will actually be equal to +0.333, and when you do `z = 1 - x - y`, `z` will be equal to .334. No money is +unaccounted for! + +You still have to be careful. If you want to split a number `N` 3 ways, you +can't just send `N/3` to three different people. You have to pick one to send +`N - (2/3*N)` to. That person will receive the fraction of a penny remainder. + +But, it is much easier to be careful with Decimal than with big.Rat. + +#### Why isn't the API similar to big.Int's? + +big.Int's API is built to reduce the number of memory allocations for maximal +performance. This makes sense for its use-case, but the trade-off is that the +API is awkward and easy to misuse. + +For example, to add two big.Ints, you do: `z := new(big.Int).Add(x, y)`. A +developer unfamiliar with this API might try to do `z := a.Add(a, b)`. This +modifies `a` and sets `z` as an alias for `a`, which they might not expect. It +also modifies any other aliases to `a`. + +Here's an example of the subtle bugs you can introduce with big.Int's API: +https://play.golang.org/p/x2R_78pa8r + +In contrast, it's difficult to make such mistakes with decimal. Decimals +behave like other go numbers types: even though `a = b` will not deep copy +`b` into `a`, it is impossible to modify a Decimal, since all Decimal methods +return new Decimals and do not modify the originals. The downside is that +this causes extra allocations, so Decimal is less performant. My assumption +is that if you're using Decimals, you probably care more about correctness +than performance. + +## License + +The MIT License (MIT) + +This is a heavily modified fork of [fpd.Decimal](https://github.com/oguzbilgic/fpd), which was also released under the MIT License. diff --git a/vendor/github.com/shopspring/decimal/decimal-go.go b/vendor/github.com/shopspring/decimal/decimal-go.go new file mode 100644 index 000000000..9958d6902 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/decimal-go.go @@ -0,0 +1,415 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package decimal + +type decimal struct { + d [800]byte // digits, big-endian representation + nd int // number of digits used + dp int // decimal point + neg bool // negative flag + trunc bool // discarded nonzero digits beyond d[:nd] +} + +func (a *decimal) String() string { + n := 10 + a.nd + if a.dp > 0 { + n += a.dp + } + if a.dp < 0 { + n += -a.dp + } + + buf := make([]byte, n) + w := 0 + switch { + case a.nd == 0: + return "0" + + case a.dp <= 0: + // zeros fill space between decimal point and digits + buf[w] = '0' + w++ + buf[w] = '.' + w++ + w += digitZero(buf[w : w+-a.dp]) + w += copy(buf[w:], a.d[0:a.nd]) + + case a.dp < a.nd: + // decimal point in middle of digits + w += copy(buf[w:], a.d[0:a.dp]) + buf[w] = '.' + w++ + w += copy(buf[w:], a.d[a.dp:a.nd]) + + default: + // zeros fill space between digits and decimal point + w += copy(buf[w:], a.d[0:a.nd]) + w += digitZero(buf[w : w+a.dp-a.nd]) + } + return string(buf[0:w]) +} + +func digitZero(dst []byte) int { + for i := range dst { + dst[i] = '0' + } + return len(dst) +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [24]byte + + // Write reversed decimal in buf. + n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0 + for n--; n >= 0; n-- { + a.d[a.nd] = buf[n] + a.nd++ + } + a.dp = a.nd + trim(a) +} + +// Maximum shift that we can do in one pass without overflow. +// A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63) +const maxShift = uintSize - 4 + +// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. +func rightShift(a *decimal, k uint) { + r := 0 // read pointer + w := 0 // write pointer + + // Pick up enough leading digits to cover first shift. + var n uint + for ; n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + return + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := uint(a.d[r]) + n = n*10 + c - '0' + } + a.dp -= r - 1 + + var mask uint = (1 << k) - 1 + + // Pick up a digit, put down a digit. + for ; r < a.nd; r++ { + c := uint(a.d[r]) + dig := n >> k + n &= mask + a.d[w] = byte(dig + '0') + w++ + n = n*10 + c - '0' + } + + // Put down extra digits. + for n > 0 { + dig := n >> k + n &= mask + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } + n = n * 10 + } + + a.nd = w + trim(a) +} + +// Cheat sheet for left shift: table indexed by shift count giving +// number of new digits that will be introduced by that shift. +// +// For example, leftcheats[4] = {2, "625"}. That means that +// if we are shifting by 4 (multiplying by 16), it will add 2 digits +// when the string prefix is "625" through "999", and one fewer digit +// if the string prefix is "000" through "624". +// +// Credit for this trick goes to Ken. + +type leftCheat struct { + delta int // number of new digits + cutoff string // minus one digit if original < a. +} + +var leftcheats = []leftCheat{ + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. + /* + seq 60 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\t{ 0, \"\" }," } + { + log2 = log(2)/log(10) + printf("\t{ %d, \"%s\" },\t// * %d\n", + int(log2*NR+1), $0, 2**NR) + }' + */ + {0, ""}, + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 + {9, "37252902984619140625"}, // * 268435456 + {9, "186264514923095703125"}, // * 536870912 + {10, "931322574615478515625"}, // * 1073741824 + {10, "4656612873077392578125"}, // * 2147483648 + {10, "23283064365386962890625"}, // * 4294967296 + {10, "116415321826934814453125"}, // * 8589934592 + {11, "582076609134674072265625"}, // * 17179869184 + {11, "2910383045673370361328125"}, // * 34359738368 + {11, "14551915228366851806640625"}, // * 68719476736 + {12, "72759576141834259033203125"}, // * 137438953472 + {12, "363797880709171295166015625"}, // * 274877906944 + {12, "1818989403545856475830078125"}, // * 549755813888 + {13, "9094947017729282379150390625"}, // * 1099511627776 + {13, "45474735088646411895751953125"}, // * 2199023255552 + {13, "227373675443232059478759765625"}, // * 4398046511104 + {13, "1136868377216160297393798828125"}, // * 8796093022208 + {14, "5684341886080801486968994140625"}, // * 17592186044416 + {14, "28421709430404007434844970703125"}, // * 35184372088832 + {14, "142108547152020037174224853515625"}, // * 70368744177664 + {15, "710542735760100185871124267578125"}, // * 140737488355328 + {15, "3552713678800500929355621337890625"}, // * 281474976710656 + {15, "17763568394002504646778106689453125"}, // * 562949953421312 + {16, "88817841970012523233890533447265625"}, // * 1125899906842624 + {16, "444089209850062616169452667236328125"}, // * 2251799813685248 + {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 + {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 + {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 + {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 + {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 + {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 + {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 + {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 + {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 +} + +// Is the leading prefix of b lexicographically less than s? +func prefixIsLessThan(b []byte, s string) bool { + for i := 0; i < len(s); i++ { + if i >= len(b) { + return true + } + if b[i] != s[i] { + return b[i] < s[i] + } + } + return false +} + +// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. +func leftShift(a *decimal, k uint) { + delta := leftcheats[k].delta + if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { + delta-- + } + + r := a.nd // read index + w := a.nd + delta // write index + + // Pick up a digit, put down a digit. + var n uint + for r--; r >= 0; r-- { + n += (uint(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } + a.dp += delta + trim(a) +} + +// Binary shift left (k > 0) or right (k < 0). +func (a *decimal) Shift(k int) { + switch { + case a.nd == 0: + // nothing to do: a == 0 + case k > 0: + for k > maxShift { + leftShift(a, maxShift) + k -= maxShift + } + leftShift(a, uint(k)) + case k < 0: + for k < -maxShift { + rightShift(a, maxShift) + k += maxShift + } + rightShift(a, uint(-k)) + } +} + +// If we chop a at nd digits, should we round up? +func shouldRoundUp(a *decimal, nd int) bool { + if nd < 0 || nd >= a.nd { + return false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + return true + } + return nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + return a.d[nd] >= '5' +} + +// Round a to nd digits (or fewer). +// If nd is zero, it means we're rounding +// just to the left of the digits, as in +// 0.09 -> 0.1. +func (a *decimal) Round(nd int) { + if nd < 0 || nd >= a.nd { + return + } + if shouldRoundUp(a, nd) { + a.RoundUp(nd) + } else { + a.RoundDown(nd) + } +} + +// Round a down to nd digits (or fewer). +func (a *decimal) RoundDown(nd int) { + if nd < 0 || nd >= a.nd { + return + } + a.nd = nd + trim(a) +} + +// Round a up to nd digits (or fewer). +func (a *decimal) RoundUp(nd int) { + if nd < 0 || nd >= a.nd { + return + } + + // round up + for i := nd - 1; i >= 0; i-- { + c := a.d[i] + if c < '9' { // can stop after this digit + a.d[i]++ + a.nd = i + 1 + return + } + } + + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + a.d[0] = '1' + a.nd = 1 + a.dp++ +} + +// Extract integer part, rounded appropriately. +// No guarantees about overflow. +func (a *decimal) RoundedInteger() uint64 { + if a.dp > 20 { + return 0xFFFFFFFFFFFFFFFF + } + var i int + n := uint64(0) + for i = 0; i < a.dp && i < a.nd; i++ { + n = n*10 + uint64(a.d[i]-'0') + } + for ; i < a.dp; i++ { + n *= 10 + } + if shouldRoundUp(a, a.dp) { + n++ + } + return n +} diff --git a/vendor/github.com/shopspring/decimal/decimal.go b/vendor/github.com/shopspring/decimal/decimal.go new file mode 100644 index 000000000..801c1a045 --- /dev/null +++ b/vendor/github.com/shopspring/decimal/decimal.go @@ -0,0 +1,1477 @@ +// Package decimal implements an arbitrary precision fixed-point decimal. +// +// The zero-value of a Decimal is 0, as you would expect. +// +// The best way to create a new Decimal is to use decimal.NewFromString, ex: +// +// n, err := decimal.NewFromString("-123.4567") +// n.String() // output: "-123.4567" +// +// To use Decimal as part of a struct: +// +// type Struct struct { +// Number Decimal +// } +// +// Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point. +package decimal + +import ( + "database/sql/driver" + "encoding/binary" + "fmt" + "math" + "math/big" + "strconv" + "strings" +) + +// DivisionPrecision is the number of decimal places in the result when it +// doesn't divide exactly. +// +// Example: +// +// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d1.String() // output: "0.6666666666666667" +// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)) +// d2.String() // output: "0.0000666666666667" +// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)) +// d3.String() // output: "6666.6666666666666667" +// decimal.DivisionPrecision = 3 +// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d4.String() // output: "0.667" +// +var DivisionPrecision = 16 + +// MarshalJSONWithoutQuotes should be set to true if you want the decimal to +// be JSON marshaled as a number, instead of as a string. +// WARNING: this is dangerous for decimals with many digits, since many JSON +// unmarshallers (ex: Javascript's) will unmarshal JSON numbers to IEEE 754 +// double-precision floating point numbers, which means you can potentially +// silently lose precision. +var MarshalJSONWithoutQuotes = false + +// Zero constant, to make computations faster. +// Zero should never be compared with == or != directly, please use decimal.Equal or decimal.Cmp instead. +var Zero = New(0, 1) + +var zeroInt = big.NewInt(0) +var oneInt = big.NewInt(1) +var twoInt = big.NewInt(2) +var fourInt = big.NewInt(4) +var fiveInt = big.NewInt(5) +var tenInt = big.NewInt(10) +var twentyInt = big.NewInt(20) + +// Decimal represents a fixed-point decimal. It is immutable. +// number = value * 10 ^ exp +type Decimal struct { + value *big.Int + + // NOTE(vadim): this must be an int32, because we cast it to float64 during + // calculations. If exp is 64 bit, we might lose precision. + // If we cared about being able to represent every possible decimal, we + // could make exp a *big.Int but it would hurt performance and numbers + // like that are unrealistic. + exp int32 +} + +// New returns a new fixed-point decimal, value * 10 ^ exp. +func New(value int64, exp int32) Decimal { + return Decimal{ + value: big.NewInt(value), + exp: exp, + } +} + +// NewFromInt converts a int64 to Decimal. +// +// Example: +// +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" +func NewFromInt(value int64) Decimal { + return Decimal{ + value: big.NewInt(value), + exp: 0, + } +} + +// NewFromInt32 converts a int32 to Decimal. +// +// Example: +// +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" +func NewFromInt32(value int32) Decimal { + return Decimal{ + value: big.NewInt(int64(value)), + exp: 0, + } +} + +// NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp +func NewFromBigInt(value *big.Int, exp int32) Decimal { + return Decimal{ + value: big.NewInt(0).Set(value), + exp: exp, + } +} + +// NewFromString returns a new Decimal from a string representation. +// Trailing zeroes are not trimmed. +// +// Example: +// +// d, err := NewFromString("-123.45") +// d2, err := NewFromString(".0001") +// d3, err := NewFromString("1.47000") +// +func NewFromString(value string) (Decimal, error) { + originalInput := value + var intString string + var exp int64 + + // Check if number is using scientific notation + eIndex := strings.IndexAny(value, "Ee") + if eIndex != -1 { + expInt, err := strconv.ParseInt(value[eIndex+1:], 10, 32) + if err != nil { + if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange { + return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", value) + } + return Decimal{}, fmt.Errorf("can't convert %s to decimal: exponent is not numeric", value) + } + value = value[:eIndex] + exp = expInt + } + + parts := strings.Split(value, ".") + if len(parts) == 1 { + // There is no decimal point, we can just parse the original string as + // an int + intString = value + } else if len(parts) == 2 { + intString = parts[0] + parts[1] + expInt := -len(parts[1]) + exp += int64(expInt) + } else { + return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value) + } + + dValue := new(big.Int) + _, ok := dValue.SetString(intString, 10) + if !ok { + return Decimal{}, fmt.Errorf("can't convert %s to decimal", value) + } + + if exp < math.MinInt32 || exp > math.MaxInt32 { + // NOTE(vadim): I doubt a string could realistically be this long + return Decimal{}, fmt.Errorf("can't convert %s to decimal: fractional part too long", originalInput) + } + + return Decimal{ + value: dValue, + exp: int32(exp), + }, nil +} + +// RequireFromString returns a new Decimal from a string representation +// or panics if NewFromString would have returned an error. +// +// Example: +// +// d := RequireFromString("-123.45") +// d2 := RequireFromString(".0001") +// +func RequireFromString(value string) Decimal { + dec, err := NewFromString(value) + if err != nil { + panic(err) + } + return dec +} + +// NewFromFloat converts a float64 to Decimal. +// +// The converted number will contain the number of significant digits that can be +// represented in a float with reliable roundtrip. +// This is typically 15 digits, but may be more in some cases. +// See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. +// +// For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. +// +// NOTE: this will panic on NaN, +/-inf +func NewFromFloat(value float64) Decimal { + if value == 0 { + return New(0, 0) + } + return newFromFloat(value, math.Float64bits(value), &float64info) +} + +// NewFromFloat32 converts a float32 to Decimal. +// +// The converted number will contain the number of significant digits that can be +// represented in a float with reliable roundtrip. +// This is typically 6-8 digits depending on the input. +// See https://www.exploringbinary.com/decimal-precision-of-binary-floating-point-numbers/ for more information. +// +// For slightly faster conversion, use NewFromFloatWithExponent where you can specify the precision in absolute terms. +// +// NOTE: this will panic on NaN, +/-inf +func NewFromFloat32(value float32) Decimal { + if value == 0 { + return New(0, 0) + } + // XOR is workaround for https://github.com/golang/go/issues/26285 + a := math.Float32bits(value) ^ 0x80808080 + return newFromFloat(float64(value), uint64(a)^0x80808080, &float32info) +} + +func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal { + if math.IsNaN(val) || math.IsInf(val, 0) { + panic(fmt.Sprintf("Cannot create a Decimal from %v", val)) + } + exp := int(bits>>flt.mantbits) & (1<>(flt.expbits+flt.mantbits) != 0 + + roundShortest(&d, mant, exp, flt) + // If less than 19 digits, we can do calculation in an int64. + if d.nd < 19 { + tmp := int64(0) + m := int64(1) + for i := d.nd - 1; i >= 0; i-- { + tmp += m * int64(d.d[i]-'0') + m *= 10 + } + if d.neg { + tmp *= -1 + } + return Decimal{value: big.NewInt(tmp), exp: int32(d.dp) - int32(d.nd)} + } + dValue := new(big.Int) + dValue, ok := dValue.SetString(string(d.d[:d.nd]), 10) + if ok { + return Decimal{value: dValue, exp: int32(d.dp) - int32(d.nd)} + } + + return NewFromFloatWithExponent(val, int32(d.dp)-int32(d.nd)) +} + +// NewFromFloatWithExponent converts a float64 to Decimal, with an arbitrary +// number of fractional digits. +// +// Example: +// +// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" +// +func NewFromFloatWithExponent(value float64, exp int32) Decimal { + if math.IsNaN(value) || math.IsInf(value, 0) { + panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) + } + + bits := math.Float64bits(value) + mant := bits & (1<<52 - 1) + exp2 := int32((bits >> 52) & (1<<11 - 1)) + sign := bits >> 63 + + if exp2 == 0 { + // specials + if mant == 0 { + return Decimal{} + } + // subnormal + exp2++ + } else { + // normal + mant |= 1 << 52 + } + + exp2 -= 1023 + 52 + + // normalizing base-2 values + for mant&1 == 0 { + mant = mant >> 1 + exp2++ + } + + // maximum number of fractional base-10 digits to represent 2^N exactly cannot be more than -N if N<0 + if exp < 0 && exp < exp2 { + if exp2 < 0 { + exp = exp2 + } else { + exp = 0 + } + } + + // representing 10^M * 2^N as 5^M * 2^(M+N) + exp2 -= exp + + temp := big.NewInt(1) + dMant := big.NewInt(int64(mant)) + + // applying 5^M + if exp > 0 { + temp = temp.SetInt64(int64(exp)) + temp = temp.Exp(fiveInt, temp, nil) + } else if exp < 0 { + temp = temp.SetInt64(-int64(exp)) + temp = temp.Exp(fiveInt, temp, nil) + dMant = dMant.Mul(dMant, temp) + temp = temp.SetUint64(1) + } + + // applying 2^(M+N) + if exp2 > 0 { + dMant = dMant.Lsh(dMant, uint(exp2)) + } else if exp2 < 0 { + temp = temp.Lsh(temp, uint(-exp2)) + } + + // rounding and downscaling + if exp > 0 || exp2 < 0 { + halfDown := new(big.Int).Rsh(temp, 1) + dMant = dMant.Add(dMant, halfDown) + dMant = dMant.Quo(dMant, temp) + } + + if sign == 1 { + dMant = dMant.Neg(dMant) + } + + return Decimal{ + value: dMant, + exp: exp, + } +} + +// rescale returns a rescaled version of the decimal. Returned +// decimal may be less precise if the given exponent is bigger +// than the initial exponent of the Decimal. +// NOTE: this will truncate, NOT round +// +// Example: +// +// d := New(12345, -4) +// d2 := d.rescale(-1) +// d3 := d2.rescale(-4) +// println(d1) +// println(d2) +// println(d3) +// +// Output: +// +// 1.2345 +// 1.2 +// 1.2000 +// +func (d Decimal) rescale(exp int32) Decimal { + d.ensureInitialized() + + if d.exp == exp { + return Decimal{ + new(big.Int).Set(d.value), + d.exp, + } + } + + // NOTE(vadim): must convert exps to float64 before - to prevent overflow + diff := math.Abs(float64(exp) - float64(d.exp)) + value := new(big.Int).Set(d.value) + + expScale := new(big.Int).Exp(tenInt, big.NewInt(int64(diff)), nil) + if exp > d.exp { + value = value.Quo(value, expScale) + } else if exp < d.exp { + value = value.Mul(value, expScale) + } + + return Decimal{ + value: value, + exp: exp, + } +} + +// Abs returns the absolute value of the decimal. +func (d Decimal) Abs() Decimal { + d.ensureInitialized() + d2Value := new(big.Int).Abs(d.value) + return Decimal{ + value: d2Value, + exp: d.exp, + } +} + +// Add returns d + d2. +func (d Decimal) Add(d2 Decimal) Decimal { + rd, rd2 := RescalePair(d, d2) + + d3Value := new(big.Int).Add(rd.value, rd2.value) + return Decimal{ + value: d3Value, + exp: rd.exp, + } +} + +// Sub returns d - d2. +func (d Decimal) Sub(d2 Decimal) Decimal { + rd, rd2 := RescalePair(d, d2) + + d3Value := new(big.Int).Sub(rd.value, rd2.value) + return Decimal{ + value: d3Value, + exp: rd.exp, + } +} + +// Neg returns -d. +func (d Decimal) Neg() Decimal { + d.ensureInitialized() + val := new(big.Int).Neg(d.value) + return Decimal{ + value: val, + exp: d.exp, + } +} + +// Mul returns d * d2. +func (d Decimal) Mul(d2 Decimal) Decimal { + d.ensureInitialized() + d2.ensureInitialized() + + expInt64 := int64(d.exp) + int64(d2.exp) + if expInt64 > math.MaxInt32 || expInt64 < math.MinInt32 { + // NOTE(vadim): better to panic than give incorrect results, as + // Decimals are usually used for money + panic(fmt.Sprintf("exponent %v overflows an int32!", expInt64)) + } + + d3Value := new(big.Int).Mul(d.value, d2.value) + return Decimal{ + value: d3Value, + exp: int32(expInt64), + } +} + +// Shift shifts the decimal in base 10. +// It shifts left when shift is positive and right if shift is negative. +// In simpler terms, the given value for shift is added to the exponent +// of the decimal. +func (d Decimal) Shift(shift int32) Decimal { + d.ensureInitialized() + return Decimal{ + value: new(big.Int).Set(d.value), + exp: d.exp + shift, + } +} + +// Div returns d / d2. If it doesn't divide exactly, the result will have +// DivisionPrecision digits after the decimal point. +func (d Decimal) Div(d2 Decimal) Decimal { + return d.DivRound(d2, int32(DivisionPrecision)) +} + +// QuoRem does divsion with remainder +// d.QuoRem(d2,precision) returns quotient q and remainder r such that +// d = d2 * q + r, q an integer multiple of 10^(-precision) +// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 +// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 +// Note that precision<0 is allowed as input. +func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { + d.ensureInitialized() + d2.ensureInitialized() + if d2.value.Sign() == 0 { + panic("decimal division by 0") + } + scale := -precision + e := int64(d.exp - d2.exp - scale) + if e > math.MaxInt32 || e < math.MinInt32 { + panic("overflow in decimal QuoRem") + } + var aa, bb, expo big.Int + var scalerest int32 + // d = a 10^ea + // d2 = b 10^eb + if e < 0 { + aa = *d.value + expo.SetInt64(-e) + bb.Exp(tenInt, &expo, nil) + bb.Mul(d2.value, &bb) + scalerest = d.exp + // now aa = a + // bb = b 10^(scale + eb - ea) + } else { + expo.SetInt64(e) + aa.Exp(tenInt, &expo, nil) + aa.Mul(d.value, &aa) + bb = *d2.value + scalerest = scale + d2.exp + // now aa = a ^ (ea - eb - scale) + // bb = b + } + var q, r big.Int + q.QuoRem(&aa, &bb, &r) + dq := Decimal{value: &q, exp: scale} + dr := Decimal{value: &r, exp: scalerest} + return dq, dr +} + +// DivRound divides and rounds to a given precision +// i.e. to an integer multiple of 10^(-precision) +// for a positive quotient digit 5 is rounded up, away from 0 +// if the quotient is negative then digit 5 is rounded down, away from 0 +// Note that precision<0 is allowed as input. +func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { + // QuoRem already checks initialization + q, r := d.QuoRem(d2, precision) + // the actual rounding decision is based on comparing r*10^precision and d2/2 + // instead compare 2 r 10 ^precision and d2 + var rv2 big.Int + rv2.Abs(r.value) + rv2.Lsh(&rv2, 1) + // now rv2 = abs(r.value) * 2 + r2 := Decimal{value: &rv2, exp: r.exp + precision} + // r2 is now 2 * r * 10 ^ precision + var c = r2.Cmp(d2.Abs()) + + if c < 0 { + return q + } + + if d.value.Sign()*d2.value.Sign() < 0 { + return q.Sub(New(1, -precision)) + } + + return q.Add(New(1, -precision)) +} + +// Mod returns d % d2. +func (d Decimal) Mod(d2 Decimal) Decimal { + quo := d.Div(d2).Truncate(0) + return d.Sub(d2.Mul(quo)) +} + +// Pow returns d to the power d2 +func (d Decimal) Pow(d2 Decimal) Decimal { + var temp Decimal + if d2.IntPart() == 0 { + return NewFromFloat(1) + } + temp = d.Pow(d2.Div(NewFromFloat(2))) + if d2.IntPart()%2 == 0 { + return temp.Mul(temp) + } + if d2.IntPart() > 0 { + return temp.Mul(temp).Mul(d) + } + return temp.Mul(temp).Div(d) +} + +// Cmp compares the numbers represented by d and d2 and returns: +// +// -1 if d < d2 +// 0 if d == d2 +// +1 if d > d2 +// +func (d Decimal) Cmp(d2 Decimal) int { + d.ensureInitialized() + d2.ensureInitialized() + + if d.exp == d2.exp { + return d.value.Cmp(d2.value) + } + + rd, rd2 := RescalePair(d, d2) + + return rd.value.Cmp(rd2.value) +} + +// Equal returns whether the numbers represented by d and d2 are equal. +func (d Decimal) Equal(d2 Decimal) bool { + return d.Cmp(d2) == 0 +} + +// Equals is deprecated, please use Equal method instead +func (d Decimal) Equals(d2 Decimal) bool { + return d.Equal(d2) +} + +// GreaterThan (GT) returns true when d is greater than d2. +func (d Decimal) GreaterThan(d2 Decimal) bool { + return d.Cmp(d2) == 1 +} + +// GreaterThanOrEqual (GTE) returns true when d is greater than or equal to d2. +func (d Decimal) GreaterThanOrEqual(d2 Decimal) bool { + cmp := d.Cmp(d2) + return cmp == 1 || cmp == 0 +} + +// LessThan (LT) returns true when d is less than d2. +func (d Decimal) LessThan(d2 Decimal) bool { + return d.Cmp(d2) == -1 +} + +// LessThanOrEqual (LTE) returns true when d is less than or equal to d2. +func (d Decimal) LessThanOrEqual(d2 Decimal) bool { + cmp := d.Cmp(d2) + return cmp == -1 || cmp == 0 +} + +// Sign returns: +// +// -1 if d < 0 +// 0 if d == 0 +// +1 if d > 0 +// +func (d Decimal) Sign() int { + if d.value == nil { + return 0 + } + return d.value.Sign() +} + +// IsPositive return +// +// true if d > 0 +// false if d == 0 +// false if d < 0 +func (d Decimal) IsPositive() bool { + return d.Sign() == 1 +} + +// IsNegative return +// +// true if d < 0 +// false if d == 0 +// false if d > 0 +func (d Decimal) IsNegative() bool { + return d.Sign() == -1 +} + +// IsZero return +// +// true if d == 0 +// false if d > 0 +// false if d < 0 +func (d Decimal) IsZero() bool { + return d.Sign() == 0 +} + +// Exponent returns the exponent, or scale component of the decimal. +func (d Decimal) Exponent() int32 { + return d.exp +} + +// Coefficient returns the coefficient of the decimal. It is scaled by 10^Exponent() +func (d Decimal) Coefficient() *big.Int { + d.ensureInitialized() + // we copy the coefficient so that mutating the result does not mutate the + // Decimal. + return big.NewInt(0).Set(d.value) +} + +// IntPart returns the integer component of the decimal. +func (d Decimal) IntPart() int64 { + scaledD := d.rescale(0) + return scaledD.value.Int64() +} + +// BigInt returns integer component of the decimal as a BigInt. +func (d Decimal) BigInt() *big.Int { + scaledD := d.rescale(0) + i := &big.Int{} + i.SetString(scaledD.String(), 10) + return i +} + +// BigFloat returns decimal as BigFloat. +// Be aware that casting decimal to BigFloat might cause a loss of precision. +func (d Decimal) BigFloat() *big.Float { + f := &big.Float{} + f.SetString(d.String()) + return f +} + +// Rat returns a rational number representation of the decimal. +func (d Decimal) Rat() *big.Rat { + d.ensureInitialized() + if d.exp <= 0 { + // NOTE(vadim): must negate after casting to prevent int32 overflow + denom := new(big.Int).Exp(tenInt, big.NewInt(-int64(d.exp)), nil) + return new(big.Rat).SetFrac(d.value, denom) + } + + mul := new(big.Int).Exp(tenInt, big.NewInt(int64(d.exp)), nil) + num := new(big.Int).Mul(d.value, mul) + return new(big.Rat).SetFrac(num, oneInt) +} + +// Float64 returns the nearest float64 value for d and a bool indicating +// whether f represents d exactly. +// For more details, see the documentation for big.Rat.Float64 +func (d Decimal) Float64() (f float64, exact bool) { + return d.Rat().Float64() +} + +// String returns the string representation of the decimal +// with the fixed point. +// +// Example: +// +// d := New(-12345, -3) +// println(d.String()) +// +// Output: +// +// -12.345 +// +func (d Decimal) String() string { + return d.string(true) +} + +// StringFixed returns a rounded fixed-point string with places digits after +// the decimal point. +// +// Example: +// +// NewFromFloat(0).StringFixed(2) // output: "0.00" +// NewFromFloat(0).StringFixed(0) // output: "0" +// NewFromFloat(5.45).StringFixed(0) // output: "5" +// NewFromFloat(5.45).StringFixed(1) // output: "5.5" +// NewFromFloat(5.45).StringFixed(2) // output: "5.45" +// NewFromFloat(5.45).StringFixed(3) // output: "5.450" +// NewFromFloat(545).StringFixed(-1) // output: "550" +// +func (d Decimal) StringFixed(places int32) string { + rounded := d.Round(places) + return rounded.string(false) +} + +// StringFixedBank returns a banker rounded fixed-point string with places digits +// after the decimal point. +// +// Example: +// +// NewFromFloat(0).StringFixedBank(2) // output: "0.00" +// NewFromFloat(0).StringFixedBank(0) // output: "0" +// NewFromFloat(5.45).StringFixedBank(0) // output: "5" +// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4" +// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" +// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" +// NewFromFloat(545).StringFixedBank(-1) // output: "540" +// +func (d Decimal) StringFixedBank(places int32) string { + rounded := d.RoundBank(places) + return rounded.string(false) +} + +// StringFixedCash returns a Swedish/Cash rounded fixed-point string. For +// more details see the documentation at function RoundCash. +func (d Decimal) StringFixedCash(interval uint8) string { + rounded := d.RoundCash(interval) + return rounded.string(false) +} + +// Round rounds the decimal to places decimal places. +// If places < 0, it will round the integer part to the nearest 10^(-places). +// +// Example: +// +// NewFromFloat(5.45).Round(1).String() // output: "5.5" +// NewFromFloat(545).Round(-1).String() // output: "550" +// +func (d Decimal) Round(places int32) Decimal { + // truncate to places + 1 + ret := d.rescale(-places - 1) + + // add sign(d) * 0.5 + if ret.value.Sign() < 0 { + ret.value.Sub(ret.value, fiveInt) + } else { + ret.value.Add(ret.value, fiveInt) + } + + // floor for positive numbers, ceil for negative numbers + _, m := ret.value.DivMod(ret.value, tenInt, new(big.Int)) + ret.exp++ + if ret.value.Sign() < 0 && m.Cmp(zeroInt) != 0 { + ret.value.Add(ret.value, oneInt) + } + + return ret +} + +// RoundBank rounds the decimal to places decimal places. +// If the final digit to round is equidistant from the nearest two integers the +// rounded value is taken as the even number +// +// If places < 0, it will round the integer part to the nearest 10^(-places). +// +// Examples: +// +// NewFromFloat(5.45).Round(1).String() // output: "5.4" +// NewFromFloat(545).Round(-1).String() // output: "540" +// NewFromFloat(5.46).Round(1).String() // output: "5.5" +// NewFromFloat(546).Round(-1).String() // output: "550" +// NewFromFloat(5.55).Round(1).String() // output: "5.6" +// NewFromFloat(555).Round(-1).String() // output: "560" +// +func (d Decimal) RoundBank(places int32) Decimal { + + round := d.Round(places) + remainder := d.Sub(round).Abs() + + half := New(5, -places-1) + if remainder.Cmp(half) == 0 && round.value.Bit(0) != 0 { + if round.value.Sign() < 0 { + round.value.Add(round.value, oneInt) + } else { + round.value.Sub(round.value, oneInt) + } + } + + return round +} + +// RoundCash aka Cash/Penny/öre rounding rounds decimal to a specific +// interval. The amount payable for a cash transaction is rounded to the nearest +// multiple of the minimum currency unit available. The following intervals are +// available: 5, 10, 25, 50 and 100; any other number throws a panic. +// 5: 5 cent rounding 3.43 => 3.45 +// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) +// 25: 25 cent rounding 3.41 => 3.50 +// 50: 50 cent rounding 3.75 => 4.00 +// 100: 100 cent rounding 3.50 => 4.00 +// For more details: https://en.wikipedia.org/wiki/Cash_rounding +func (d Decimal) RoundCash(interval uint8) Decimal { + var iVal *big.Int + switch interval { + case 5: + iVal = twentyInt + case 10: + iVal = tenInt + case 25: + iVal = fourInt + case 50: + iVal = twoInt + case 100: + iVal = oneInt + default: + panic(fmt.Sprintf("Decimal does not support this Cash rounding interval `%d`. Supported: 5, 10, 25, 50, 100", interval)) + } + dVal := Decimal{ + value: iVal, + } + + // TODO: optimize those calculations to reduce the high allocations (~29 allocs). + return d.Mul(dVal).Round(0).Div(dVal).Truncate(2) +} + +// Floor returns the nearest integer value less than or equal to d. +func (d Decimal) Floor() Decimal { + d.ensureInitialized() + + if d.exp >= 0 { + return d + } + + exp := big.NewInt(10) + + // NOTE(vadim): must negate after casting to prevent int32 overflow + exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) + + z := new(big.Int).Div(d.value, exp) + return Decimal{value: z, exp: 0} +} + +// Ceil returns the nearest integer value greater than or equal to d. +func (d Decimal) Ceil() Decimal { + d.ensureInitialized() + + if d.exp >= 0 { + return d + } + + exp := big.NewInt(10) + + // NOTE(vadim): must negate after casting to prevent int32 overflow + exp.Exp(exp, big.NewInt(-int64(d.exp)), nil) + + z, m := new(big.Int).DivMod(d.value, exp, new(big.Int)) + if m.Cmp(zeroInt) != 0 { + z.Add(z, oneInt) + } + return Decimal{value: z, exp: 0} +} + +// Truncate truncates off digits from the number, without rounding. +// +// NOTE: precision is the last digit that will not be truncated (must be >= 0). +// +// Example: +// +// decimal.NewFromString("123.456").Truncate(2).String() // "123.45" +// +func (d Decimal) Truncate(precision int32) Decimal { + d.ensureInitialized() + if precision >= 0 && -precision > d.exp { + return d.rescale(-precision) + } + return d +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error { + if string(decimalBytes) == "null" { + return nil + } + + str, err := unquoteIfQuoted(decimalBytes) + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", decimalBytes, err) + } + + decimal, err := NewFromString(str) + *d = decimal + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", str, err) + } + return nil +} + +// MarshalJSON implements the json.Marshaler interface. +func (d Decimal) MarshalJSON() ([]byte, error) { + var str string + if MarshalJSONWithoutQuotes { + str = d.String() + } else { + str = "\"" + d.String() + "\"" + } + return []byte(str), nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. As a string representation +// is already used when encoding to text, this method stores that string as []byte +func (d *Decimal) UnmarshalBinary(data []byte) error { + // Extract the exponent + d.exp = int32(binary.BigEndian.Uint32(data[:4])) + + // Extract the value + d.value = new(big.Int) + return d.value.GobDecode(data[4:]) +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (d Decimal) MarshalBinary() (data []byte, err error) { + // Write the exponent first since it's a fixed size + v1 := make([]byte, 4) + binary.BigEndian.PutUint32(v1, uint32(d.exp)) + + // Add the value + var v2 []byte + if v2, err = d.value.GobEncode(); err != nil { + return + } + + // Return the byte array + data = append(v1, v2...) + return +} + +// Scan implements the sql.Scanner interface for database deserialization. +func (d *Decimal) Scan(value interface{}) error { + // first try to see if the data is stored in database as a Numeric datatype + switch v := value.(type) { + + case float32: + *d = NewFromFloat(float64(v)) + return nil + + case float64: + // numeric in sqlite3 sends us float64 + *d = NewFromFloat(v) + return nil + + case int64: + // at least in sqlite3 when the value is 0 in db, the data is sent + // to us as an int64 instead of a float64 ... + *d = New(v, 0) + return nil + + default: + // default is trying to interpret value stored as string + str, err := unquoteIfQuoted(v) + if err != nil { + return err + } + *d, err = NewFromString(str) + return err + } +} + +// Value implements the driver.Valuer interface for database serialization. +func (d Decimal) Value() (driver.Value, error) { + return d.String(), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for XML +// deserialization. +func (d *Decimal) UnmarshalText(text []byte) error { + str := string(text) + + dec, err := NewFromString(str) + *d = dec + if err != nil { + return fmt.Errorf("error decoding string '%s': %s", str, err) + } + + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface for XML +// serialization. +func (d Decimal) MarshalText() (text []byte, err error) { + return []byte(d.String()), nil +} + +// GobEncode implements the gob.GobEncoder interface for gob serialization. +func (d Decimal) GobEncode() ([]byte, error) { + return d.MarshalBinary() +} + +// GobDecode implements the gob.GobDecoder interface for gob serialization. +func (d *Decimal) GobDecode(data []byte) error { + return d.UnmarshalBinary(data) +} + +// StringScaled first scales the decimal then calls .String() on it. +// NOTE: buggy, unintuitive, and DEPRECATED! Use StringFixed instead. +func (d Decimal) StringScaled(exp int32) string { + return d.rescale(exp).String() +} + +func (d Decimal) string(trimTrailingZeros bool) string { + if d.exp >= 0 { + return d.rescale(0).value.String() + } + + abs := new(big.Int).Abs(d.value) + str := abs.String() + + var intPart, fractionalPart string + + // NOTE(vadim): this cast to int will cause bugs if d.exp == INT_MIN + // and you are on a 32-bit machine. Won't fix this super-edge case. + dExpInt := int(d.exp) + if len(str) > -dExpInt { + intPart = str[:len(str)+dExpInt] + fractionalPart = str[len(str)+dExpInt:] + } else { + intPart = "0" + + num0s := -dExpInt - len(str) + fractionalPart = strings.Repeat("0", num0s) + str + } + + if trimTrailingZeros { + i := len(fractionalPart) - 1 + for ; i >= 0; i-- { + if fractionalPart[i] != '0' { + break + } + } + fractionalPart = fractionalPart[:i+1] + } + + number := intPart + if len(fractionalPart) > 0 { + number += "." + fractionalPart + } + + if d.value.Sign() < 0 { + return "-" + number + } + + return number +} + +func (d *Decimal) ensureInitialized() { + if d.value == nil { + d.value = new(big.Int) + } +} + +// Min returns the smallest Decimal that was passed in the arguments. +// +// To call this function with an array, you must do: +// +// Min(arr[0], arr[1:]...) +// +// This makes it harder to accidentally call Min with 0 arguments. +func Min(first Decimal, rest ...Decimal) Decimal { + ans := first + for _, item := range rest { + if item.Cmp(ans) < 0 { + ans = item + } + } + return ans +} + +// Max returns the largest Decimal that was passed in the arguments. +// +// To call this function with an array, you must do: +// +// Max(arr[0], arr[1:]...) +// +// This makes it harder to accidentally call Max with 0 arguments. +func Max(first Decimal, rest ...Decimal) Decimal { + ans := first + for _, item := range rest { + if item.Cmp(ans) > 0 { + ans = item + } + } + return ans +} + +// Sum returns the combined total of the provided first and rest Decimals +func Sum(first Decimal, rest ...Decimal) Decimal { + total := first + for _, item := range rest { + total = total.Add(item) + } + + return total +} + +// Avg returns the average value of the provided first and rest Decimals +func Avg(first Decimal, rest ...Decimal) Decimal { + count := New(int64(len(rest)+1), 0) + sum := Sum(first, rest...) + return sum.Div(count) +} + +// RescalePair rescales two decimals to common exponential value (minimal exp of both decimals) +func RescalePair(d1 Decimal, d2 Decimal) (Decimal, Decimal) { + d1.ensureInitialized() + d2.ensureInitialized() + + if d1.exp == d2.exp { + return d1, d2 + } + + baseScale := min(d1.exp, d2.exp) + if baseScale != d1.exp { + return d1.rescale(baseScale), d2 + } + return d1, d2.rescale(baseScale) +} + +func min(x, y int32) int32 { + if x >= y { + return y + } + return x +} + +func unquoteIfQuoted(value interface{}) (string, error) { + var bytes []byte + + switch v := value.(type) { + case string: + bytes = []byte(v) + case []byte: + bytes = v + default: + return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", + value, value) + } + + // If the amount is quoted, strip the quotes + if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' { + bytes = bytes[1 : len(bytes)-1] + } + return string(bytes), nil +} + +// NullDecimal represents a nullable decimal with compatibility for +// scanning null values from the database. +type NullDecimal struct { + Decimal Decimal + Valid bool +} + +// Scan implements the sql.Scanner interface for database deserialization. +func (d *NullDecimal) Scan(value interface{}) error { + if value == nil { + d.Valid = false + return nil + } + d.Valid = true + return d.Decimal.Scan(value) +} + +// Value implements the driver.Valuer interface for database serialization. +func (d NullDecimal) Value() (driver.Value, error) { + if !d.Valid { + return nil, nil + } + return d.Decimal.Value() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (d *NullDecimal) UnmarshalJSON(decimalBytes []byte) error { + if string(decimalBytes) == "null" { + d.Valid = false + return nil + } + d.Valid = true + return d.Decimal.UnmarshalJSON(decimalBytes) +} + +// MarshalJSON implements the json.Marshaler interface. +func (d NullDecimal) MarshalJSON() ([]byte, error) { + if !d.Valid { + return []byte("null"), nil + } + return d.Decimal.MarshalJSON() +} + +// Trig functions + +// Atan returns the arctangent, in radians, of x. +func (d Decimal) Atan() Decimal { + if d.Equal(NewFromFloat(0.0)) { + return d + } + if d.GreaterThan(NewFromFloat(0.0)) { + return d.satan() + } + return d.Neg().satan().Neg() +} + +func (d Decimal) xatan() Decimal { + P0 := NewFromFloat(-8.750608600031904122785e-01) + P1 := NewFromFloat(-1.615753718733365076637e+01) + P2 := NewFromFloat(-7.500855792314704667340e+01) + P3 := NewFromFloat(-1.228866684490136173410e+02) + P4 := NewFromFloat(-6.485021904942025371773e+01) + Q0 := NewFromFloat(2.485846490142306297962e+01) + Q1 := NewFromFloat(1.650270098316988542046e+02) + Q2 := NewFromFloat(4.328810604912902668951e+02) + Q3 := NewFromFloat(4.853903996359136964868e+02) + Q4 := NewFromFloat(1.945506571482613964425e+02) + z := d.Mul(d) + b1 := P0.Mul(z).Add(P1).Mul(z).Add(P2).Mul(z).Add(P3).Mul(z).Add(P4).Mul(z) + b2 := z.Add(Q0).Mul(z).Add(Q1).Mul(z).Add(Q2).Mul(z).Add(Q3).Mul(z).Add(Q4) + z = b1.Div(b2) + z = d.Mul(z).Add(d) + return z +} + +// satan reduces its argument (known to be positive) +// to the range [0, 0.66] and calls xatan. +func (d Decimal) satan() Decimal { + Morebits := NewFromFloat(6.123233995736765886130e-17) // pi/2 = PIO2 + Morebits + Tan3pio8 := NewFromFloat(2.41421356237309504880) // tan(3*pi/8) + pi := NewFromFloat(3.14159265358979323846264338327950288419716939937510582097494459) + + if d.LessThanOrEqual(NewFromFloat(0.66)) { + return d.xatan() + } + if d.GreaterThan(Tan3pio8) { + return pi.Div(NewFromFloat(2.0)).Sub(NewFromFloat(1.0).Div(d).xatan()).Add(Morebits) + } + return pi.Div(NewFromFloat(4.0)).Add((d.Sub(NewFromFloat(1.0)).Div(d.Add(NewFromFloat(1.0)))).xatan()).Add(NewFromFloat(0.5).Mul(Morebits)) +} + +// sin coefficients +var _sin = [...]Decimal{ + NewFromFloat(1.58962301576546568060e-10), // 0x3de5d8fd1fd19ccd + NewFromFloat(-2.50507477628578072866e-8), // 0xbe5ae5e5a9291f5d + NewFromFloat(2.75573136213857245213e-6), // 0x3ec71de3567d48a1 + NewFromFloat(-1.98412698295895385996e-4), // 0xbf2a01a019bfdf03 + NewFromFloat(8.33333333332211858878e-3), // 0x3f8111111110f7d0 + NewFromFloat(-1.66666666666666307295e-1), // 0xbfc5555555555548 +} + +// Sin returns the sine of the radian argument x. +func (d Decimal) Sin() Decimal { + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + if d.Equal(NewFromFloat(0.0)) { + return d + } + // make argument positive but save the sign + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + sign = true + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + // reflect in x axis + if j > 3 { + sign = !sign + j -= 4 + } + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if j == 1 || j == 2 { + w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) + y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) + } else { + y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) + } + if sign { + y = y.Neg() + } + return y +} + +// cos coefficients +var _cos = [...]Decimal{ + NewFromFloat(-1.13585365213876817300e-11), // 0xbda8fa49a0861a9b + NewFromFloat(2.08757008419747316778e-9), // 0x3e21ee9d7b4e3f05 + NewFromFloat(-2.75573141792967388112e-7), // 0xbe927e4f7eac4bc6 + NewFromFloat(2.48015872888517045348e-5), // 0x3efa01a019c844f5 + NewFromFloat(-1.38888888888730564116e-3), // 0xbf56c16c16c14f91 + NewFromFloat(4.16666666666665929218e-2), // 0x3fa555555555554b +} + +// Cos returns the cosine of the radian argument x. +func (d Decimal) Cos() Decimal { + + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + // make argument positive + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + j &= 7 // octant modulo 2Pi radians (360 degrees) + // reflect in x axis + if j > 3 { + sign = !sign + j -= 4 + } + if j > 1 { + sign = !sign + } + + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if j == 1 || j == 2 { + y = z.Add(z.Mul(zz).Mul(_sin[0].Mul(zz).Add(_sin[1]).Mul(zz).Add(_sin[2]).Mul(zz).Add(_sin[3]).Mul(zz).Add(_sin[4]).Mul(zz).Add(_sin[5]))) + } else { + w := zz.Mul(zz).Mul(_cos[0].Mul(zz).Add(_cos[1]).Mul(zz).Add(_cos[2]).Mul(zz).Add(_cos[3]).Mul(zz).Add(_cos[4]).Mul(zz).Add(_cos[5])) + y = NewFromFloat(1.0).Sub(NewFromFloat(0.5).Mul(zz)).Add(w) + } + if sign { + y = y.Neg() + } + return y +} + +var _tanP = [...]Decimal{ + NewFromFloat(-1.30936939181383777646e+4), // 0xc0c992d8d24f3f38 + NewFromFloat(1.15351664838587416140e+6), // 0x413199eca5fc9ddd + NewFromFloat(-1.79565251976484877988e+7), // 0xc1711fead3299176 +} +var _tanQ = [...]Decimal{ + NewFromFloat(1.00000000000000000000e+0), + NewFromFloat(1.36812963470692954678e+4), //0x40cab8a5eeb36572 + NewFromFloat(-1.32089234440210967447e+6), //0xc13427bc582abc96 + NewFromFloat(2.50083801823357915839e+7), //0x4177d98fc2ead8ef + NewFromFloat(-5.38695755929454629881e+7), //0xc189afe03cbe5a31 +} + +// Tan returns the tangent of the radian argument x. +func (d Decimal) Tan() Decimal { + + PI4A := NewFromFloat(7.85398125648498535156e-1) // 0x3fe921fb40000000, Pi/4 split into three parts + PI4B := NewFromFloat(3.77489470793079817668e-8) // 0x3e64442d00000000, + PI4C := NewFromFloat(2.69515142907905952645e-15) // 0x3ce8469898cc5170, + M4PI := NewFromFloat(1.273239544735162542821171882678754627704620361328125) // 4/pi + + if d.Equal(NewFromFloat(0.0)) { + return d + } + + // make argument positive but save the sign + sign := false + if d.LessThan(NewFromFloat(0.0)) { + d = d.Neg() + sign = true + } + + j := d.Mul(M4PI).IntPart() // integer part of x/(Pi/4), as integer for tests on the phase angle + y := NewFromFloat(float64(j)) // integer part of x/(Pi/4), as float + + // map zeros to origin + if j&1 == 1 { + j++ + y = y.Add(NewFromFloat(1.0)) + } + + z := d.Sub(y.Mul(PI4A)).Sub(y.Mul(PI4B)).Sub(y.Mul(PI4C)) // Extended precision modular arithmetic + zz := z.Mul(z) + + if zz.GreaterThan(NewFromFloat(1e-14)) { + w := zz.Mul(_tanP[0].Mul(zz).Add(_tanP[1]).Mul(zz).Add(_tanP[2])) + x := zz.Add(_tanQ[1]).Mul(zz).Add(_tanQ[2]).Mul(zz).Add(_tanQ[3]).Mul(zz).Add(_tanQ[4]) + y = z.Add(z.Mul(w.Div(x))) + } else { + y = z + } + if j&2 == 2 { + y = NewFromFloat(-1.0).Div(y) + } + if sign { + y = y.Neg() + } + return y +} diff --git a/vendor/github.com/shopspring/decimal/rounding.go b/vendor/github.com/shopspring/decimal/rounding.go new file mode 100644 index 000000000..8008f55cb --- /dev/null +++ b/vendor/github.com/shopspring/decimal/rounding.go @@ -0,0 +1,119 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package decimal + +type floatInfo struct { + mantbits uint + expbits uint + bias int +} + +var float32info = floatInfo{23, 8, -127} +var float64info = floatInfo{52, 11, -1023} + +// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely reconstructed. +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + return + } + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // We may see at once that the number is already shortest. + // + // Suppose d is not denormal, so that 2^exp <= d < 10^dp. + // The closest shorter number is at least 10^(dp-nd) away. + // The lower/upper bounds computed below are at distance + // at most 2^(exp-mantbits). + // + // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), + // or equivalently log2(10)*(dp-nd) > exp-mantbits. + // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). + minexp := flt.bias + 1 // minimum possible exponent + if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { + // The number is already shortest. + return + } + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. + upper := new(decimal) + upper.Assign(mant*2 + 1) + upper.Shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. + var mantlo uint64 + var explo int + if mant > 1<. +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +// Package cast provides easy and safe casting in Go. +package cast + +import "time" + +// ToBool casts an interface to a bool type. +func ToBool(i interface{}) bool { + v, _ := ToBoolE(i) + return v +} + +// ToTime casts an interface to a time.Time type. +func ToTime(i interface{}) time.Time { + v, _ := ToTimeE(i) + return v +} + +func ToTimeInDefaultLocation(i interface{}, location *time.Location) time.Time { + v, _ := ToTimeInDefaultLocationE(i, location) + return v +} + +// ToDuration casts an interface to a time.Duration type. +func ToDuration(i interface{}) time.Duration { + v, _ := ToDurationE(i) + return v +} + +// ToFloat64 casts an interface to a float64 type. +func ToFloat64(i interface{}) float64 { + v, _ := ToFloat64E(i) + return v +} + +// ToFloat32 casts an interface to a float32 type. +func ToFloat32(i interface{}) float32 { + v, _ := ToFloat32E(i) + return v +} + +// ToInt64 casts an interface to an int64 type. +func ToInt64(i interface{}) int64 { + v, _ := ToInt64E(i) + return v +} + +// ToInt32 casts an interface to an int32 type. +func ToInt32(i interface{}) int32 { + v, _ := ToInt32E(i) + return v +} + +// ToInt16 casts an interface to an int16 type. +func ToInt16(i interface{}) int16 { + v, _ := ToInt16E(i) + return v +} + +// ToInt8 casts an interface to an int8 type. +func ToInt8(i interface{}) int8 { + v, _ := ToInt8E(i) + return v +} + +// ToInt casts an interface to an int type. +func ToInt(i interface{}) int { + v, _ := ToIntE(i) + return v +} + +// ToUint casts an interface to a uint type. +func ToUint(i interface{}) uint { + v, _ := ToUintE(i) + return v +} + +// ToUint64 casts an interface to a uint64 type. +func ToUint64(i interface{}) uint64 { + v, _ := ToUint64E(i) + return v +} + +// ToUint32 casts an interface to a uint32 type. +func ToUint32(i interface{}) uint32 { + v, _ := ToUint32E(i) + return v +} + +// ToUint16 casts an interface to a uint16 type. +func ToUint16(i interface{}) uint16 { + v, _ := ToUint16E(i) + return v +} + +// ToUint8 casts an interface to a uint8 type. +func ToUint8(i interface{}) uint8 { + v, _ := ToUint8E(i) + return v +} + +// ToString casts an interface to a string type. +func ToString(i interface{}) string { + v, _ := ToStringE(i) + return v +} + +// ToStringMapString casts an interface to a map[string]string type. +func ToStringMapString(i interface{}) map[string]string { + v, _ := ToStringMapStringE(i) + return v +} + +// ToStringMapStringSlice casts an interface to a map[string][]string type. +func ToStringMapStringSlice(i interface{}) map[string][]string { + v, _ := ToStringMapStringSliceE(i) + return v +} + +// ToStringMapBool casts an interface to a map[string]bool type. +func ToStringMapBool(i interface{}) map[string]bool { + v, _ := ToStringMapBoolE(i) + return v +} + +// ToStringMapInt casts an interface to a map[string]int type. +func ToStringMapInt(i interface{}) map[string]int { + v, _ := ToStringMapIntE(i) + return v +} + +// ToStringMapInt64 casts an interface to a map[string]int64 type. +func ToStringMapInt64(i interface{}) map[string]int64 { + v, _ := ToStringMapInt64E(i) + return v +} + +// ToStringMap casts an interface to a map[string]interface{} type. +func ToStringMap(i interface{}) map[string]interface{} { + v, _ := ToStringMapE(i) + return v +} + +// ToSlice casts an interface to a []interface{} type. +func ToSlice(i interface{}) []interface{} { + v, _ := ToSliceE(i) + return v +} + +// ToBoolSlice casts an interface to a []bool type. +func ToBoolSlice(i interface{}) []bool { + v, _ := ToBoolSliceE(i) + return v +} + +// ToStringSlice casts an interface to a []string type. +func ToStringSlice(i interface{}) []string { + v, _ := ToStringSliceE(i) + return v +} + +// ToIntSlice casts an interface to a []int type. +func ToIntSlice(i interface{}) []int { + v, _ := ToIntSliceE(i) + return v +} + +// ToDurationSlice casts an interface to a []time.Duration type. +func ToDurationSlice(i interface{}) []time.Duration { + v, _ := ToDurationSliceE(i) + return v +} diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go new file mode 100644 index 000000000..d49bbf83e --- /dev/null +++ b/vendor/github.com/spf13/cast/caste.go @@ -0,0 +1,1498 @@ +// Copyright © 2014 Steve Francia . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package cast + +import ( + "encoding/json" + "errors" + "fmt" + "html/template" + "reflect" + "strconv" + "strings" + "time" +) + +var errNegativeNotAllowed = errors.New("unable to cast negative value") + +// ToTimeE casts an interface to a time.Time type. +func ToTimeE(i interface{}) (tim time.Time, err error) { + return ToTimeInDefaultLocationE(i, time.UTC) +} + +// ToTimeInDefaultLocationE casts an empty interface to time.Time, +// interpreting inputs without a timezone to be in the given location, +// or the local timezone if nil. +func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time.Time, err error) { + i = indirect(i) + + switch v := i.(type) { + case time.Time: + return v, nil + case string: + return StringToDateInDefaultLocation(v, location) + case json.Number: + s, err1 := ToInt64E(v) + if err1 != nil { + return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i) + } + return time.Unix(s, 0), nil + case int: + return time.Unix(int64(v), 0), nil + case int64: + return time.Unix(v, 0), nil + case int32: + return time.Unix(int64(v), 0), nil + case uint: + return time.Unix(int64(v), 0), nil + case uint64: + return time.Unix(int64(v), 0), nil + case uint32: + return time.Unix(int64(v), 0), nil + default: + return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i) + } +} + +// ToDurationE casts an interface to a time.Duration type. +func ToDurationE(i interface{}) (d time.Duration, err error) { + i = indirect(i) + + switch s := i.(type) { + case time.Duration: + return s, nil + case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8: + d = time.Duration(ToInt64(s)) + return + case float32, float64: + d = time.Duration(ToFloat64(s)) + return + case string: + if strings.ContainsAny(s, "nsuµmh") { + d, err = time.ParseDuration(s) + } else { + d, err = time.ParseDuration(s + "ns") + } + return + case json.Number: + var v float64 + v, err = s.Float64() + d = time.Duration(v) + return + default: + err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i) + return + } +} + +// ToBoolE casts an interface to a bool type. +func ToBoolE(i interface{}) (bool, error) { + i = indirect(i) + + switch b := i.(type) { + case bool: + return b, nil + case nil: + return false, nil + case int: + return b != 0, nil + case int64: + return b != 0, nil + case int32: + return b != 0, nil + case int16: + return b != 0, nil + case int8: + return b != 0, nil + case uint: + return b != 0, nil + case uint64: + return b != 0, nil + case uint32: + return b != 0, nil + case uint16: + return b != 0, nil + case uint8: + return b != 0, nil + case float64: + return b != 0, nil + case float32: + return b != 0, nil + case time.Duration: + return b != 0, nil + case string: + return strconv.ParseBool(i.(string)) + case json.Number: + v, err := ToInt64E(b) + if err == nil { + return v != 0, nil + } + return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) + default: + return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i) + } +} + +// ToFloat64E casts an interface to a float64 type. +func ToFloat64E(i interface{}) (float64, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return float64(intv), nil + } + + switch s := i.(type) { + case float64: + return s, nil + case float32: + return float64(s), nil + case int64: + return float64(s), nil + case int32: + return float64(s), nil + case int16: + return float64(s), nil + case int8: + return float64(s), nil + case uint: + return float64(s), nil + case uint64: + return float64(s), nil + case uint32: + return float64(s), nil + case uint16: + return float64(s), nil + case uint8: + return float64(s), nil + case string: + v, err := strconv.ParseFloat(s, 64) + if err == nil { + return v, nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) + case json.Number: + v, err := s.Float64() + if err == nil { + return v, nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i) + } +} + +// ToFloat32E casts an interface to a float32 type. +func ToFloat32E(i interface{}) (float32, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return float32(intv), nil + } + + switch s := i.(type) { + case float64: + return float32(s), nil + case float32: + return s, nil + case int64: + return float32(s), nil + case int32: + return float32(s), nil + case int16: + return float32(s), nil + case int8: + return float32(s), nil + case uint: + return float32(s), nil + case uint64: + return float32(s), nil + case uint32: + return float32(s), nil + case uint16: + return float32(s), nil + case uint8: + return float32(s), nil + case string: + v, err := strconv.ParseFloat(s, 32) + if err == nil { + return float32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) + case json.Number: + v, err := s.Float64() + if err == nil { + return float32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i) + } +} + +// ToInt64E casts an interface to an int64 type. +func ToInt64E(i interface{}) (int64, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return int64(intv), nil + } + + switch s := i.(type) { + case int64: + return s, nil + case int32: + return int64(s), nil + case int16: + return int64(s), nil + case int8: + return int64(s), nil + case uint: + return int64(s), nil + case uint64: + return int64(s), nil + case uint32: + return int64(s), nil + case uint16: + return int64(s), nil + case uint8: + return int64(s), nil + case float64: + return int64(s), nil + case float32: + return int64(s), nil + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + return v, nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) + case json.Number: + return ToInt64E(string(s)) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) + } +} + +// ToInt32E casts an interface to an int32 type. +func ToInt32E(i interface{}) (int32, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return int32(intv), nil + } + + switch s := i.(type) { + case int64: + return int32(s), nil + case int32: + return s, nil + case int16: + return int32(s), nil + case int8: + return int32(s), nil + case uint: + return int32(s), nil + case uint64: + return int32(s), nil + case uint32: + return int32(s), nil + case uint16: + return int32(s), nil + case uint8: + return int32(s), nil + case float64: + return int32(s), nil + case float32: + return int32(s), nil + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + return int32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) + case json.Number: + return ToInt32E(string(s)) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i) + } +} + +// ToInt16E casts an interface to an int16 type. +func ToInt16E(i interface{}) (int16, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return int16(intv), nil + } + + switch s := i.(type) { + case int64: + return int16(s), nil + case int32: + return int16(s), nil + case int16: + return s, nil + case int8: + return int16(s), nil + case uint: + return int16(s), nil + case uint64: + return int16(s), nil + case uint32: + return int16(s), nil + case uint16: + return int16(s), nil + case uint8: + return int16(s), nil + case float64: + return int16(s), nil + case float32: + return int16(s), nil + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + return int16(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) + case json.Number: + return ToInt16E(string(s)) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i) + } +} + +// ToInt8E casts an interface to an int8 type. +func ToInt8E(i interface{}) (int8, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return int8(intv), nil + } + + switch s := i.(type) { + case int64: + return int8(s), nil + case int32: + return int8(s), nil + case int16: + return int8(s), nil + case int8: + return s, nil + case uint: + return int8(s), nil + case uint64: + return int8(s), nil + case uint32: + return int8(s), nil + case uint16: + return int8(s), nil + case uint8: + return int8(s), nil + case float64: + return int8(s), nil + case float32: + return int8(s), nil + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + return int8(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) + case json.Number: + return ToInt8E(string(s)) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i) + } +} + +// ToIntE casts an interface to an int type. +func ToIntE(i interface{}) (int, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + return intv, nil + } + + switch s := i.(type) { + case int64: + return int(s), nil + case int32: + return int(s), nil + case int16: + return int(s), nil + case int8: + return int(s), nil + case uint: + return int(s), nil + case uint64: + return int(s), nil + case uint32: + return int(s), nil + case uint16: + return int(s), nil + case uint8: + return int(s), nil + case float64: + return int(s), nil + case float32: + return int(s), nil + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + return int(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i) + case json.Number: + return ToIntE(string(s)) + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i) + } +} + +// ToUintE casts an interface to a uint type. +func ToUintE(i interface{}) (uint, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + if intv < 0 { + return 0, errNegativeNotAllowed + } + return uint(intv), nil + } + + switch s := i.(type) { + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to uint", i, i) + case json.Number: + return ToUintE(string(s)) + case int64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case int32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case int16: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case int8: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case uint: + return s, nil + case uint64: + return uint(s), nil + case uint32: + return uint(s), nil + case uint16: + return uint(s), nil + case uint8: + return uint(s), nil + case float64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case float32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint(s), nil + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to uint", i, i) + } +} + +// ToUint64E casts an interface to a uint64 type. +func ToUint64E(i interface{}) (uint64, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + if intv < 0 { + return 0, errNegativeNotAllowed + } + return uint64(intv), nil + } + + switch s := i.(type) { + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint64(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i) + case json.Number: + return ToUint64E(string(s)) + case int64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case int32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case int16: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case int8: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case uint: + return uint64(s), nil + case uint64: + return s, nil + case uint32: + return uint64(s), nil + case uint16: + return uint64(s), nil + case uint8: + return uint64(s), nil + case float32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case float64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint64(s), nil + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i) + } +} + +// ToUint32E casts an interface to a uint32 type. +func ToUint32E(i interface{}) (uint32, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + if intv < 0 { + return 0, errNegativeNotAllowed + } + return uint32(intv), nil + } + + switch s := i.(type) { + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint32(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to uint32", i, i) + case json.Number: + return ToUint32E(string(s)) + case int64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case int32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case int16: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case int8: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case uint: + return uint32(s), nil + case uint64: + return uint32(s), nil + case uint32: + return s, nil + case uint16: + return uint32(s), nil + case uint8: + return uint32(s), nil + case float64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case float32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint32(s), nil + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to uint32", i, i) + } +} + +// ToUint16E casts an interface to a uint16 type. +func ToUint16E(i interface{}) (uint16, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + if intv < 0 { + return 0, errNegativeNotAllowed + } + return uint16(intv), nil + } + + switch s := i.(type) { + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint16(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to uint16", i, i) + case json.Number: + return ToUint16E(string(s)) + case int64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case int32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case int16: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case int8: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case uint: + return uint16(s), nil + case uint64: + return uint16(s), nil + case uint32: + return uint16(s), nil + case uint16: + return s, nil + case uint8: + return uint16(s), nil + case float64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case float32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint16(s), nil + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to uint16", i, i) + } +} + +// ToUint8E casts an interface to a uint type. +func ToUint8E(i interface{}) (uint8, error) { + i = indirect(i) + + intv, ok := toInt(i) + if ok { + if intv < 0 { + return 0, errNegativeNotAllowed + } + return uint8(intv), nil + } + + switch s := i.(type) { + case string: + v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0) + if err == nil { + if v < 0 { + return 0, errNegativeNotAllowed + } + return uint8(v), nil + } + return 0, fmt.Errorf("unable to cast %#v of type %T to uint8", i, i) + case json.Number: + return ToUint8E(string(s)) + case int64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case int32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case int16: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case int8: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case uint: + return uint8(s), nil + case uint64: + return uint8(s), nil + case uint32: + return uint8(s), nil + case uint16: + return uint8(s), nil + case uint8: + return s, nil + case float64: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case float32: + if s < 0 { + return 0, errNegativeNotAllowed + } + return uint8(s), nil + case bool: + if s { + return 1, nil + } + return 0, nil + case nil: + return 0, nil + default: + return 0, fmt.Errorf("unable to cast %#v of type %T to uint8", i, i) + } +} + +// From html/template/content.go +// Copyright 2011 The Go Authors. All rights reserved. +// indirect returns the value, after dereferencing as many times +// as necessary to reach the base type (or nil). +func indirect(a interface{}) interface{} { + if a == nil { + return nil + } + if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { + // Avoid creating a reflect.Value if it's not a pointer. + return a + } + v := reflect.ValueOf(a) + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v.Interface() +} + +// From html/template/content.go +// Copyright 2011 The Go Authors. All rights reserved. +// indirectToStringerOrError returns the value, after dereferencing as many times +// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer +// or error, +func indirectToStringerOrError(a interface{}) interface{} { + if a == nil { + return nil + } + + var errorType = reflect.TypeOf((*error)(nil)).Elem() + var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() + + v := reflect.ValueOf(a) + for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v.Interface() +} + +// ToStringE casts an interface to a string type. +func ToStringE(i interface{}) (string, error) { + i = indirectToStringerOrError(i) + + switch s := i.(type) { + case string: + return s, nil + case bool: + return strconv.FormatBool(s), nil + case float64: + return strconv.FormatFloat(s, 'f', -1, 64), nil + case float32: + return strconv.FormatFloat(float64(s), 'f', -1, 32), nil + case int: + return strconv.Itoa(s), nil + case int64: + return strconv.FormatInt(s, 10), nil + case int32: + return strconv.Itoa(int(s)), nil + case int16: + return strconv.FormatInt(int64(s), 10), nil + case int8: + return strconv.FormatInt(int64(s), 10), nil + case uint: + return strconv.FormatUint(uint64(s), 10), nil + case uint64: + return strconv.FormatUint(uint64(s), 10), nil + case uint32: + return strconv.FormatUint(uint64(s), 10), nil + case uint16: + return strconv.FormatUint(uint64(s), 10), nil + case uint8: + return strconv.FormatUint(uint64(s), 10), nil + case json.Number: + return s.String(), nil + case []byte: + return string(s), nil + case template.HTML: + return string(s), nil + case template.URL: + return string(s), nil + case template.JS: + return string(s), nil + case template.CSS: + return string(s), nil + case template.HTMLAttr: + return string(s), nil + case nil: + return "", nil + case fmt.Stringer: + return s.String(), nil + case error: + return s.Error(), nil + default: + return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i) + } +} + +// ToStringMapStringE casts an interface to a map[string]string type. +func ToStringMapStringE(i interface{}) (map[string]string, error) { + var m = map[string]string{} + + switch v := i.(type) { + case map[string]string: + return v, nil + case map[string]interface{}: + for k, val := range v { + m[ToString(k)] = ToString(val) + } + return m, nil + case map[interface{}]string: + for k, val := range v { + m[ToString(k)] = ToString(val) + } + return m, nil + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = ToString(val) + } + return m, nil + case string: + err := jsonStringToObject(v, &m) + return m, err + default: + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]string", i, i) + } +} + +// ToStringMapStringSliceE casts an interface to a map[string][]string type. +func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) { + var m = map[string][]string{} + + switch v := i.(type) { + case map[string][]string: + return v, nil + case map[string][]interface{}: + for k, val := range v { + m[ToString(k)] = ToStringSlice(val) + } + return m, nil + case map[string]string: + for k, val := range v { + m[ToString(k)] = []string{val} + } + case map[string]interface{}: + for k, val := range v { + switch vt := val.(type) { + case []interface{}: + m[ToString(k)] = ToStringSlice(vt) + case []string: + m[ToString(k)] = vt + default: + m[ToString(k)] = []string{ToString(val)} + } + } + return m, nil + case map[interface{}][]string: + for k, val := range v { + m[ToString(k)] = ToStringSlice(val) + } + return m, nil + case map[interface{}]string: + for k, val := range v { + m[ToString(k)] = ToStringSlice(val) + } + return m, nil + case map[interface{}][]interface{}: + for k, val := range v { + m[ToString(k)] = ToStringSlice(val) + } + return m, nil + case map[interface{}]interface{}: + for k, val := range v { + key, err := ToStringE(k) + if err != nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) + } + value, err := ToStringSliceE(val) + if err != nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) + } + m[key] = value + } + case string: + err := jsonStringToObject(v, &m) + return m, err + default: + return m, fmt.Errorf("unable to cast %#v of type %T to map[string][]string", i, i) + } + return m, nil +} + +// ToStringMapBoolE casts an interface to a map[string]bool type. +func ToStringMapBoolE(i interface{}) (map[string]bool, error) { + var m = map[string]bool{} + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = ToBool(val) + } + return m, nil + case map[string]interface{}: + for k, val := range v { + m[ToString(k)] = ToBool(val) + } + return m, nil + case map[string]bool: + return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err + default: + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]bool", i, i) + } +} + +// ToStringMapE casts an interface to a map[string]interface{} type. +func ToStringMapE(i interface{}) (map[string]interface{}, error) { + var m = map[string]interface{}{} + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = val + } + return m, nil + case map[string]interface{}: + return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err + default: + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]interface{}", i, i) + } +} + +// ToStringMapIntE casts an interface to a map[string]int{} type. +func ToStringMapIntE(i interface{}) (map[string]int, error) { + var m = map[string]int{} + if i == nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) + } + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = ToInt(val) + } + return m, nil + case map[string]interface{}: + for k, val := range v { + m[k] = ToInt(val) + } + return m, nil + case map[string]int: + return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err + } + + if reflect.TypeOf(i).Kind() != reflect.Map { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) + } + + mVal := reflect.ValueOf(m) + v := reflect.ValueOf(i) + for _, keyVal := range v.MapKeys() { + val, err := ToIntE(v.MapIndex(keyVal).Interface()) + if err != nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i) + } + mVal.SetMapIndex(keyVal, reflect.ValueOf(val)) + } + return m, nil +} + +// ToStringMapInt64E casts an interface to a map[string]int64{} type. +func ToStringMapInt64E(i interface{}) (map[string]int64, error) { + var m = map[string]int64{} + if i == nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) + } + + switch v := i.(type) { + case map[interface{}]interface{}: + for k, val := range v { + m[ToString(k)] = ToInt64(val) + } + return m, nil + case map[string]interface{}: + for k, val := range v { + m[k] = ToInt64(val) + } + return m, nil + case map[string]int64: + return v, nil + case string: + err := jsonStringToObject(v, &m) + return m, err + } + + if reflect.TypeOf(i).Kind() != reflect.Map { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) + } + mVal := reflect.ValueOf(m) + v := reflect.ValueOf(i) + for _, keyVal := range v.MapKeys() { + val, err := ToInt64E(v.MapIndex(keyVal).Interface()) + if err != nil { + return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i) + } + mVal.SetMapIndex(keyVal, reflect.ValueOf(val)) + } + return m, nil +} + +// ToSliceE casts an interface to a []interface{} type. +func ToSliceE(i interface{}) ([]interface{}, error) { + var s []interface{} + + switch v := i.(type) { + case []interface{}: + return append(s, v...), nil + case []map[string]interface{}: + for _, u := range v { + s = append(s, u) + } + return s, nil + default: + return s, fmt.Errorf("unable to cast %#v of type %T to []interface{}", i, i) + } +} + +// ToBoolSliceE casts an interface to a []bool type. +func ToBoolSliceE(i interface{}) ([]bool, error) { + if i == nil { + return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) + } + + switch v := i.(type) { + case []bool: + return v, nil + } + + kind := reflect.TypeOf(i).Kind() + switch kind { + case reflect.Slice, reflect.Array: + s := reflect.ValueOf(i) + a := make([]bool, s.Len()) + for j := 0; j < s.Len(); j++ { + val, err := ToBoolE(s.Index(j).Interface()) + if err != nil { + return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) + } + a[j] = val + } + return a, nil + default: + return []bool{}, fmt.Errorf("unable to cast %#v of type %T to []bool", i, i) + } +} + +// ToStringSliceE casts an interface to a []string type. +func ToStringSliceE(i interface{}) ([]string, error) { + var a []string + + switch v := i.(type) { + case []interface{}: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []string: + return v, nil + case []int8: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []int: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []int32: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []int64: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []float32: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case []float64: + for _, u := range v { + a = append(a, ToString(u)) + } + return a, nil + case string: + return strings.Fields(v), nil + case []error: + for _, err := range i.([]error) { + a = append(a, err.Error()) + } + return a, nil + case interface{}: + str, err := ToStringE(v) + if err != nil { + return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) + } + return []string{str}, nil + default: + return a, fmt.Errorf("unable to cast %#v of type %T to []string", i, i) + } +} + +// ToIntSliceE casts an interface to a []int type. +func ToIntSliceE(i interface{}) ([]int, error) { + if i == nil { + return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) + } + + switch v := i.(type) { + case []int: + return v, nil + } + + kind := reflect.TypeOf(i).Kind() + switch kind { + case reflect.Slice, reflect.Array: + s := reflect.ValueOf(i) + a := make([]int, s.Len()) + for j := 0; j < s.Len(); j++ { + val, err := ToIntE(s.Index(j).Interface()) + if err != nil { + return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) + } + a[j] = val + } + return a, nil + default: + return []int{}, fmt.Errorf("unable to cast %#v of type %T to []int", i, i) + } +} + +// ToDurationSliceE casts an interface to a []time.Duration type. +func ToDurationSliceE(i interface{}) ([]time.Duration, error) { + if i == nil { + return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) + } + + switch v := i.(type) { + case []time.Duration: + return v, nil + } + + kind := reflect.TypeOf(i).Kind() + switch kind { + case reflect.Slice, reflect.Array: + s := reflect.ValueOf(i) + a := make([]time.Duration, s.Len()) + for j := 0; j < s.Len(); j++ { + val, err := ToDurationE(s.Index(j).Interface()) + if err != nil { + return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) + } + a[j] = val + } + return a, nil + default: + return []time.Duration{}, fmt.Errorf("unable to cast %#v of type %T to []time.Duration", i, i) + } +} + +// StringToDate attempts to parse a string into a time.Time type using a +// predefined list of formats. If no suitable format is found, an error is +// returned. +func StringToDate(s string) (time.Time, error) { + return parseDateWith(s, time.UTC, timeFormats) +} + +// StringToDateInDefaultLocation casts an empty interface to a time.Time, +// interpreting inputs without a timezone to be in the given location, +// or the local timezone if nil. +func StringToDateInDefaultLocation(s string, location *time.Location) (time.Time, error) { + return parseDateWith(s, location, timeFormats) +} + +type timeFormatType int + +const ( + timeFormatNoTimezone timeFormatType = iota + timeFormatNamedTimezone + timeFormatNumericTimezone + timeFormatNumericAndNamedTimezone + timeFormatTimeOnly +) + +type timeFormat struct { + format string + typ timeFormatType +} + +func (f timeFormat) hasTimezone() bool { + // We don't include the formats with only named timezones, see + // https://github.com/golang/go/issues/19694#issuecomment-289103522 + return f.typ >= timeFormatNumericTimezone && f.typ <= timeFormatNumericAndNamedTimezone +} + +var ( + timeFormats = []timeFormat{ + // Keep common formats at the top. + {"2006-01-02", timeFormatNoTimezone}, + {time.RFC3339, timeFormatNumericTimezone}, + {"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone + {time.RFC1123Z, timeFormatNumericTimezone}, + {time.RFC1123, timeFormatNamedTimezone}, + {time.RFC822Z, timeFormatNumericTimezone}, + {time.RFC822, timeFormatNamedTimezone}, + {time.RFC850, timeFormatNamedTimezone}, + {"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String() + {"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon + {"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon + {"2006-01-02 15:04:05", timeFormatNoTimezone}, + {time.ANSIC, timeFormatNoTimezone}, + {time.UnixDate, timeFormatNamedTimezone}, + {time.RubyDate, timeFormatNumericTimezone}, + {"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone}, + {"02 Jan 2006", timeFormatNoTimezone}, + {"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone}, + {"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone}, + {time.Kitchen, timeFormatTimeOnly}, + {time.Stamp, timeFormatTimeOnly}, + {time.StampMilli, timeFormatTimeOnly}, + {time.StampMicro, timeFormatTimeOnly}, + {time.StampNano, timeFormatTimeOnly}, + } +) + +func parseDateWith(s string, location *time.Location, formats []timeFormat) (d time.Time, e error) { + + for _, format := range formats { + if d, e = time.Parse(format.format, s); e == nil { + + // Some time formats have a zone name, but no offset, so it gets + // put in that zone name (not the default one passed in to us), but + // without that zone's offset. So set the location manually. + if format.typ <= timeFormatNamedTimezone { + if location == nil { + location = time.Local + } + year, month, day := d.Date() + hour, min, sec := d.Clock() + d = time.Date(year, month, day, hour, min, sec, d.Nanosecond(), location) + } + + return + } + } + return d, fmt.Errorf("unable to parse date: %s", s) +} + +// jsonStringToObject attempts to unmarshall a string as JSON into +// the object passed as pointer. +func jsonStringToObject(s string, v interface{}) error { + data := []byte(s) + return json.Unmarshal(data, v) +} + +// toInt returns the int value of v if v or v's underlying type +// is an int. +// Note that this will return false for int64 etc. types. +func toInt(v interface{}) (int, bool) { + switch v := v.(type) { + case int: + return v, true + case time.Weekday: + return int(v), true + case time.Month: + return int(v), true + default: + return 0, false + } +} + +func trimZeroDecimal(s string) string { + var foundZero bool + for i := len(s); i > 0; i-- { + switch s[i-1] { + case '.': + if foundZero { + return s[:i-1] + } + case '0': + foundZero = true + default: + return s + } + } + return s +} diff --git a/vendor/github.com/spf13/cast/timeformattype_string.go b/vendor/github.com/spf13/cast/timeformattype_string.go new file mode 100644 index 000000000..1524fc82c --- /dev/null +++ b/vendor/github.com/spf13/cast/timeformattype_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type timeFormatType"; DO NOT EDIT. + +package cast + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[timeFormatNoTimezone-0] + _ = x[timeFormatNamedTimezone-1] + _ = x[timeFormatNumericTimezone-2] + _ = x[timeFormatNumericAndNamedTimezone-3] + _ = x[timeFormatTimeOnly-4] +} + +const _timeFormatType_name = "timeFormatNoTimezonetimeFormatNamedTimezonetimeFormatNumericTimezonetimeFormatNumericAndNamedTimezonetimeFormatTimeOnly" + +var _timeFormatType_index = [...]uint8{0, 20, 43, 68, 101, 119} + +func (i timeFormatType) String() string { + if i < 0 || i >= timeFormatType(len(_timeFormatType_index)-1) { + return "timeFormatType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _timeFormatType_name[_timeFormatType_index[i]:_timeFormatType_index[i+1]] +} diff --git a/vendor/golang.org/x/crypto/bcrypt/base64.go b/vendor/golang.org/x/crypto/bcrypt/base64.go new file mode 100644 index 000000000..fc3116090 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/base64.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bcrypt + +import "encoding/base64" + +const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var bcEncoding = base64.NewEncoding(alphabet) + +func base64Encode(src []byte) []byte { + n := bcEncoding.EncodedLen(len(src)) + dst := make([]byte, n) + bcEncoding.Encode(dst, src) + for dst[n-1] == '=' { + n-- + } + return dst[:n] +} + +func base64Decode(src []byte) ([]byte, error) { + numOfEquals := 4 - (len(src) % 4) + for i := 0; i < numOfEquals; i++ { + src = append(src, '=') + } + + dst := make([]byte, bcEncoding.DecodedLen(len(src))) + n, err := bcEncoding.Decode(dst, src) + if err != nil { + return nil, err + } + return dst[:n], nil +} diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go new file mode 100644 index 000000000..5577c0f93 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go @@ -0,0 +1,304 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing +// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf +package bcrypt // import "golang.org/x/crypto/bcrypt" + +// The code is a port of Provos and Mazières's C implementation. +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "io" + "strconv" + + "golang.org/x/crypto/blowfish" +) + +const ( + MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword + MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword + DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword +) + +// The error returned from CompareHashAndPassword when a password and hash do +// not match. +var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") + +// The error returned from CompareHashAndPassword when a hash is too short to +// be a bcrypt hash. +var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") + +// The error returned from CompareHashAndPassword when a hash was created with +// a bcrypt algorithm newer than this implementation. +type HashVersionTooNewError byte + +func (hv HashVersionTooNewError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) +} + +// The error returned from CompareHashAndPassword when a hash starts with something other than '$' +type InvalidHashPrefixError byte + +func (ih InvalidHashPrefixError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) +} + +type InvalidCostError int + +func (ic InvalidCostError) Error() string { + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost) +} + +const ( + majorVersion = '2' + minorVersion = 'a' + maxSaltSize = 16 + maxCryptedHashSize = 23 + encodedSaltSize = 22 + encodedHashSize = 31 + minHashSize = 59 +) + +// magicCipherData is an IV for the 64 Blowfish encryption calls in +// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. +var magicCipherData = []byte{ + 0x4f, 0x72, 0x70, 0x68, + 0x65, 0x61, 0x6e, 0x42, + 0x65, 0x68, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, + 0x6f, 0x75, 0x62, 0x74, +} + +type hashed struct { + hash []byte + salt []byte + cost int // allowed range is MinCost to MaxCost + major byte + minor byte +} + +// ErrPasswordTooLong is returned when the password passed to +// GenerateFromPassword is too long (i.e. > 72 bytes). +var ErrPasswordTooLong = errors.New("bcrypt: password length exceeds 72 bytes") + +// GenerateFromPassword returns the bcrypt hash of the password at the given +// cost. If the cost given is less than MinCost, the cost will be set to +// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, +// to compare the returned hashed password with its cleartext version. +// GenerateFromPassword does not accept passwords longer than 72 bytes, which +// is the longest password bcrypt will operate on. +func GenerateFromPassword(password []byte, cost int) ([]byte, error) { + if len(password) > 72 { + return nil, ErrPasswordTooLong + } + p, err := newFromPassword(password, cost) + if err != nil { + return nil, err + } + return p.Hash(), nil +} + +// CompareHashAndPassword compares a bcrypt hashed password with its possible +// plaintext equivalent. Returns nil on success, or an error on failure. +func CompareHashAndPassword(hashedPassword, password []byte) error { + p, err := newFromHash(hashedPassword) + if err != nil { + return err + } + + otherHash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return err + } + + otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} + if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { + return nil + } + + return ErrMismatchedHashAndPassword +} + +// Cost returns the hashing cost used to create the given hashed +// password. When, in the future, the hashing cost of a password system needs +// to be increased in order to adjust for greater computational power, this +// function allows one to establish which passwords need to be updated. +func Cost(hashedPassword []byte) (int, error) { + p, err := newFromHash(hashedPassword) + if err != nil { + return 0, err + } + return p.cost, nil +} + +func newFromPassword(password []byte, cost int) (*hashed, error) { + if cost < MinCost { + cost = DefaultCost + } + p := new(hashed) + p.major = majorVersion + p.minor = minorVersion + + err := checkCost(cost) + if err != nil { + return nil, err + } + p.cost = cost + + unencodedSalt := make([]byte, maxSaltSize) + _, err = io.ReadFull(rand.Reader, unencodedSalt) + if err != nil { + return nil, err + } + + p.salt = base64Encode(unencodedSalt) + hash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return nil, err + } + p.hash = hash + return p, err +} + +func newFromHash(hashedSecret []byte) (*hashed, error) { + if len(hashedSecret) < minHashSize { + return nil, ErrHashTooShort + } + p := new(hashed) + n, err := p.decodeVersion(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + n, err = p.decodeCost(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + + // The "+2" is here because we'll have to append at most 2 '=' to the salt + // when base64 decoding it in expensiveBlowfishSetup(). + p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) + copy(p.salt, hashedSecret[:encodedSaltSize]) + + hashedSecret = hashedSecret[encodedSaltSize:] + p.hash = make([]byte, len(hashedSecret)) + copy(p.hash, hashedSecret) + + return p, nil +} + +func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { + cipherData := make([]byte, len(magicCipherData)) + copy(cipherData, magicCipherData) + + c, err := expensiveBlowfishSetup(password, uint32(cost), salt) + if err != nil { + return nil, err + } + + for i := 0; i < 24; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) + } + } + + // Bug compatibility with C bcrypt implementations. We only encode 23 of + // the 24 bytes encrypted. + hsh := base64Encode(cipherData[:maxCryptedHashSize]) + return hsh, nil +} + +func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { + csalt, err := base64Decode(salt) + if err != nil { + return nil, err + } + + // Bug compatibility with C bcrypt implementations. They use the trailing + // NULL in the key string during expansion. + // We copy the key to prevent changing the underlying array. + ckey := append(key[:len(key):len(key)], 0) + + c, err := blowfish.NewSaltedCipher(ckey, csalt) + if err != nil { + return nil, err + } + + var i, rounds uint64 + rounds = 1 << cost + for i = 0; i < rounds; i++ { + blowfish.ExpandKey(ckey, c) + blowfish.ExpandKey(csalt, c) + } + + return c, nil +} + +func (p *hashed) Hash() []byte { + arr := make([]byte, 60) + arr[0] = '$' + arr[1] = p.major + n := 2 + if p.minor != 0 { + arr[2] = p.minor + n = 3 + } + arr[n] = '$' + n++ + copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) + n += 2 + arr[n] = '$' + n++ + copy(arr[n:], p.salt) + n += encodedSaltSize + copy(arr[n:], p.hash) + n += encodedHashSize + return arr[:n] +} + +func (p *hashed) decodeVersion(sbytes []byte) (int, error) { + if sbytes[0] != '$' { + return -1, InvalidHashPrefixError(sbytes[0]) + } + if sbytes[1] > majorVersion { + return -1, HashVersionTooNewError(sbytes[1]) + } + p.major = sbytes[1] + n := 3 + if sbytes[2] != '$' { + p.minor = sbytes[2] + n++ + } + return n, nil +} + +// sbytes should begin where decodeVersion left off. +func (p *hashed) decodeCost(sbytes []byte) (int, error) { + cost, err := strconv.Atoi(string(sbytes[0:2])) + if err != nil { + return -1, err + } + err = checkCost(cost) + if err != nil { + return -1, err + } + p.cost = cost + return 3, nil +} + +func (p *hashed) String() string { + return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) +} + +func checkCost(cost int) error { + if cost < MinCost || cost > MaxCost { + return InvalidCostError(cost) + } + return nil +} diff --git a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go index d738725ca..3674914f7 100644 --- a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go +++ b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go @@ -126,14 +126,17 @@ type rudimentaryErrorBackoff struct { // OnError will block if it is called more often than the embedded period time. // This will prevent overly tight hot error loops. func (r *rudimentaryErrorBackoff) OnError(error) { + now := time.Now() // start the timer before acquiring the lock r.lastErrorTimeLock.Lock() - defer r.lastErrorTimeLock.Unlock() - d := time.Since(r.lastErrorTime) - if d < r.minPeriod { - // If the time moves backwards for any reason, do nothing - time.Sleep(r.minPeriod - d) - } + d := now.Sub(r.lastErrorTime) r.lastErrorTime = time.Now() + r.lastErrorTimeLock.Unlock() + + // Do not sleep with the lock held because that causes all callers of HandleError to block. + // We only want the current goroutine to block. + // A negative or zero duration causes time.Sleep to return immediately. + // If the time moves backwards for any reason, do nothing. + time.Sleep(r.minPeriod - d) } // GetCaller returns the caller of the function that calls it. diff --git a/vendor/modules.txt b/vendor/modules.txt index 38c018bf4..35d28f82e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -8,9 +8,15 @@ github.com/Masterminds/goutils # github.com/Masterminds/semver v1.5.0 ## explicit github.com/Masterminds/semver +# github.com/Masterminds/semver/v3 v3.2.1 +## explicit; go 1.18 +github.com/Masterminds/semver/v3 # github.com/Masterminds/sprig v2.22.0+incompatible ## explicit github.com/Masterminds/sprig +# github.com/Masterminds/sprig/v3 v3.2.2 +## explicit; go 1.13 +github.com/Masterminds/sprig/v3 # github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 ## explicit; go 1.15 github.com/ahmetb/gen-crd-api-reference-docs @@ -36,7 +42,7 @@ github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/emicklei/go-restful/v3 v3.10.1 +# github.com/emicklei/go-restful/v3 v3.11.0 ## explicit; go 1.13 github.com/emicklei/go-restful/v3 github.com/emicklei/go-restful/v3/log @@ -63,10 +69,10 @@ github.com/fluent/fluent-operator/v2/pkg/utils # github.com/fsnotify/fsnotify v1.6.0 ## explicit; go 1.16 github.com/fsnotify/fsnotify -# github.com/gardener/etcd-druid v0.19.2 +# github.com/gardener/etcd-druid v0.20.1 ## explicit; go 1.20 github.com/gardener/etcd-druid/api/v1alpha1 -# github.com/gardener/gardener v1.80.0 +# github.com/gardener/gardener v1.83.3 ## explicit; go 1.21 github.com/gardener/gardener/.github github.com/gardener/gardener/.github/ISSUE_TEMPLATE @@ -156,6 +162,7 @@ github.com/gardener/gardener/pkg/utils/context github.com/gardener/gardener/pkg/utils/errors github.com/gardener/gardener/pkg/utils/flow github.com/gardener/gardener/pkg/utils/gardener +github.com/gardener/gardener/pkg/utils/gardener/shootstate github.com/gardener/gardener/pkg/utils/imagevector github.com/gardener/gardener/pkg/utils/kubernetes github.com/gardener/gardener/pkg/utils/kubernetes/health @@ -413,11 +420,17 @@ github.com/prometheus/procfs/internal/util # github.com/russross/blackfriday/v2 v2.1.0 ## explicit github.com/russross/blackfriday/v2 +# github.com/shopspring/decimal v1.2.0 +## explicit; go 1.13 +github.com/shopspring/decimal # github.com/spf13/afero v1.9.5 ## explicit; go 1.16 github.com/spf13/afero github.com/spf13/afero/internal/common github.com/spf13/afero/mem +# github.com/spf13/cast v1.5.1 +## explicit; go 1.18 +github.com/spf13/cast # github.com/spf13/cobra v1.8.0 ## explicit; go 1.15 github.com/spf13/cobra @@ -445,6 +458,7 @@ go.uber.org/zap/internal/stacktrace go.uber.org/zap/zapcore # golang.org/x/crypto v0.18.0 ## explicit; go 1.18 +golang.org/x/crypto/bcrypt golang.org/x/crypto/blowfish golang.org/x/crypto/chacha20 golang.org/x/crypto/curve25519 @@ -617,7 +631,7 @@ istio.io/api/type/v1beta1 ## explicit; go 1.18 istio.io/client-go/pkg/apis/networking/v1alpha3 istio.io/client-go/pkg/apis/networking/v1beta1 -# k8s.io/api v0.28.2 +# k8s.io/api v0.28.3 ## explicit; go 1.20 k8s.io/api/admission/v1 k8s.io/api/admission/v1beta1 @@ -673,13 +687,13 @@ k8s.io/api/scheduling/v1beta1 k8s.io/api/storage/v1 k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1beta1 -# k8s.io/apiextensions-apiserver v0.28.2 +# k8s.io/apiextensions-apiserver v0.28.3 ## explicit; go 1.20 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1 k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme -# k8s.io/apimachinery v0.28.2 +# k8s.io/apimachinery v0.28.3 ## explicit; go 1.20 k8s.io/apimachinery/pkg/api/equality k8s.io/apimachinery/pkg/api/errors @@ -737,14 +751,14 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.28.2 +# k8s.io/apiserver v0.28.3 ## explicit; go 1.20 k8s.io/apiserver/pkg/util/feature # k8s.io/autoscaler/vertical-pod-autoscaler v0.14.0 ## explicit; go 1.19 k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1 k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1beta2 -# k8s.io/client-go v0.28.2 +# k8s.io/client-go v0.28.3 ## explicit; go 1.20 k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1 @@ -886,7 +900,7 @@ k8s.io/client-go/util/flowcontrol k8s.io/client-go/util/homedir k8s.io/client-go/util/keyutil k8s.io/client-go/util/workqueue -# k8s.io/code-generator v0.28.2 +# k8s.io/code-generator v0.28.3 ## explicit; go 1.20 k8s.io/code-generator k8s.io/code-generator/cmd/applyconfiguration-gen @@ -925,7 +939,7 @@ k8s.io/code-generator/cmd/set-gen k8s.io/code-generator/pkg/namer k8s.io/code-generator/pkg/util k8s.io/code-generator/third_party/forked/golang/reflect -# k8s.io/component-base v0.28.2 +# k8s.io/component-base v0.28.3 ## explicit; go 1.20 k8s.io/component-base/cli/flag k8s.io/component-base/config @@ -977,7 +991,7 @@ k8s.io/klog/v2/internal/clock k8s.io/klog/v2/internal/dbg k8s.io/klog/v2/internal/serialize k8s.io/klog/v2/internal/severity -# k8s.io/kube-aggregator v0.28.2 +# k8s.io/kube-aggregator v0.28.3 ## explicit; go 1.20 k8s.io/kube-aggregator/pkg/apis/apiregistration k8s.io/kube-aggregator/pkg/apis/apiregistration/v1 @@ -1002,11 +1016,11 @@ k8s.io/kube-openapi/pkg/spec3 k8s.io/kube-openapi/pkg/util/proto k8s.io/kube-openapi/pkg/util/sets k8s.io/kube-openapi/pkg/validation/spec -# k8s.io/kubelet v0.28.2 +# k8s.io/kubelet v0.28.3 ## explicit; go 1.20 k8s.io/kubelet/config/v1beta1 k8s.io/kubelet/pkg/apis -# k8s.io/metrics v0.28.2 +# k8s.io/metrics v0.28.3 ## explicit; go 1.20 k8s.io/metrics/pkg/apis/metrics k8s.io/metrics/pkg/apis/metrics/v1beta1 @@ -1022,7 +1036,7 @@ k8s.io/utils/pointer k8s.io/utils/ptr k8s.io/utils/strings/slices k8s.io/utils/trace -# sigs.k8s.io/controller-runtime v0.16.2 +# sigs.k8s.io/controller-runtime v0.16.3 ## explicit; go 1.20 sigs.k8s.io/controller-runtime/pkg/cache sigs.k8s.io/controller-runtime/pkg/cache/internal @@ -1064,7 +1078,7 @@ sigs.k8s.io/controller-runtime/pkg/source sigs.k8s.io/controller-runtime/pkg/webhook sigs.k8s.io/controller-runtime/pkg/webhook/admission sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics -# sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20230707163321-8a64e5f3bd78 +# sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20231015215740-bf15e44028f9 ## explicit; go 1.20 sigs.k8s.io/controller-runtime/tools/setup-envtest sigs.k8s.io/controller-runtime/tools/setup-envtest/env diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go index d8446e85b..5410e1cdd 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go @@ -22,8 +22,10 @@ import ( "net/http" "time" + "golang.org/x/exp/maps" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -121,6 +123,10 @@ type Informer interface { HasSynced() bool } +// AllNamespaces should be used as the map key to deliminate namespace settings +// that apply to all namespaces that themselves do not have explicit settings. +const AllNamespaces = metav1.NamespaceAll + // Options are the optional arguments for creating a new Cache object. type Options struct { // HTTPClient is the http client to use for the REST client @@ -172,6 +178,11 @@ type Options struct { // the namespaces in here will be watched and it will by used to default // ByObject.Namespaces for all objects if that is nil. // + // It is possible to have specific Config for just some namespaces + // but cache all namespaces by using the AllNamespaces const as the map key. + // This will then include all namespaces that do not have a more specific + // setting. + // // The options in the Config that are nil will be defaulted from // the respective Default* settings. DefaultNamespaces map[string]Config @@ -214,6 +225,11 @@ type ByObject struct { // Settings in the map value that are unset will be defaulted. // Use an empty value for the specific setting to prevent that. // + // It is possible to have specific Config for just some namespaces + // but cache all namespaces by using the AllNamespaces const as the map key. + // This will then include all namespaces that do not have a more specific + // setting. + // // A nil map allows to default this to the cache's DefaultNamespaces setting. // An empty map prevents this and means that all namespaces will be cached. // @@ -392,6 +408,9 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) { for namespace, cfg := range opts.DefaultNamespaces { cfg = defaultConfig(cfg, optionDefaultsToConfig(&opts)) + if namespace == metav1.NamespaceAll { + cfg.FieldSelector = fields.AndSelectors(appendIfNotNil(namespaceAllSelector(maps.Keys(opts.DefaultNamespaces)), cfg.FieldSelector)...) + } opts.DefaultNamespaces[namespace] = cfg } @@ -418,6 +437,15 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) { // 3. Default from the global defaults config = defaultConfig(config, optionDefaultsToConfig(&opts)) + if namespace == metav1.NamespaceAll { + config.FieldSelector = fields.AndSelectors( + appendIfNotNil( + namespaceAllSelector(maps.Keys(byObject.Namespaces)), + config.FieldSelector, + )..., + ) + } + byObject.Namespaces[namespace] = config } @@ -457,3 +485,21 @@ func defaultConfig(toDefault, defaultFrom Config) Config { return toDefault } + +func namespaceAllSelector(namespaces []string) fields.Selector { + selectors := make([]fields.Selector, 0, len(namespaces)-1) + for _, namespace := range namespaces { + if namespace != metav1.NamespaceAll { + selectors = append(selectors, fields.OneTermNotEqualSelector("metadata.namespace", namespace)) + } + } + + return fields.AndSelectors(selectors...) +} + +func appendIfNotNil[T comparable](a, b T) []T { + if b != *new(T) { + return []T{a, b} + } + return []T{a} +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go index 5b20195d7..87c31a7c0 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go @@ -23,6 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" apimeta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" toolscache "k8s.io/client-go/tools/cache" @@ -210,6 +211,9 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj cache, ok := c.namespaceToCache[key.Namespace] if !ok { + if global, hasGlobal := c.namespaceToCache[metav1.NamespaceAll]; hasGlobal { + return global.Get(ctx, key, obj, opts...) + } return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", key) } return cache.Get(ctx, key, obj, opts...) diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go index d70237e95..9deb6756c 100644 --- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go @@ -361,7 +361,7 @@ func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Ob isStatus := false // We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change // that reaction, we use the callstack to figure out if this originated from the status client. - if bytes.Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeSubResourceClient).Patch")) { + if bytes.Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeSubResourceClient).statusPatch")) { isStatus = true } return t.update(gvr, obj, ns, isStatus, false) @@ -404,7 +404,9 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob return fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err) } passedRV := accessor.GetResourceVersion() - reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(oldObject.DeepCopyObject()).Elem()) + if err := copyFrom(oldObject, obj); err != nil { + return fmt.Errorf("failed to restore non-status fields: %w", err) + } accessor.SetResourceVersion(passedRV) } else { // copy status from original object if err := copyStatusFrom(oldObject, obj); err != nil { @@ -972,6 +974,19 @@ func copyStatusFrom(old, new runtime.Object) error { return nil } +// copyFrom copies from old into new +func copyFrom(old, new runtime.Object) error { + oldMapStringAny, err := toMapStringAny(old) + if err != nil { + return fmt.Errorf("failed to convert old to *unstructured.Unstructured: %w", err) + } + if err := fromMapStringAny(oldMapStringAny, new); err != nil { + return fmt.Errorf("failed to convert back from map[string]any: %w", err) + } + + return nil +} + func toMapStringAny(obj runtime.Object) (map[string]any, error) { if unstructured, isUnstructured := obj.(*unstructured.Unstructured); isUnstructured { return unstructured.Object, nil @@ -1090,6 +1105,15 @@ func (sw *fakeSubResourceClient) Patch(ctx context.Context, obj client.Object, p body = patchOptions.SubResourceBody } + // this is necessary to identify that last call was made for status patch, through stack trace. + if sw.subResource == "status" { + return sw.statusPatch(body, patch, patchOptions) + } + + return sw.client.patch(body, patch, &patchOptions.PatchOptions) +} + +func (sw *fakeSubResourceClient) statusPatch(body client.Object, patch client.Patch, patchOptions client.SubResourcePatchOptions) error { return sw.client.patch(body, patch, &patchOptions.PatchOptions) } diff --git a/vendor/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md b/vendor/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md index 40379c9b8..1bdeebbc5 100644 --- a/vendor/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md +++ b/vendor/sigs.k8s.io/controller-runtime/tools/setup-envtest/README.md @@ -4,7 +4,7 @@ This is a small tool that manages binaries for envtest. It can be used to download new binaries, list currently installed and available ones, and clean up versions. -To use it, just go-install it on 1.16+ (it's a separate, self-contained +To use it, just go-install it on 1.19+ (it's a separate, self-contained module): ```shell @@ -45,7 +45,7 @@ setup-envtest sideload 1.16.2 < downloaded-envtest.tar.gz ## Where does it put all those binaries? By default, binaries are stored in a subdirectory of an OS-specific data -directory, as per the OS's conventions. +directory, as per the OS's conventions. On Linux, this is `$XDG_DATA_HOME`; on Windows, `%LocalAppData`; and on OSX, `~/Library/Application Support`.