From da43741dfaa0a7b73c9457926aad207aa8cb575e Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Sat, 8 May 2021 09:20:45 +0000 Subject: [PATCH 1/3] Cluster IP Communication --- CHANGELOG.md | 1 + go.mod | 6 +- go.sum | 12 +++ pkg/apis/deployment/v1/deployment_spec.go | 43 +++++++++ .../deployment/v1/zz_generated.deepcopy.go | 5 ++ pkg/deployment/deployment_inspector.go | 2 +- pkg/deployment/images.go | 17 ++-- pkg/deployment/images_test.go | 4 +- pkg/deployment/pod/utils.go | 46 ++++++++++ .../reconcile/action_wait_for_member_up.go | 3 + .../reconcile/plan_builder_rotate_upgrade.go | 31 ++++++- pkg/deployment/resources/pod_creator.go | 85 +++++++++++------- .../resources/pod_creator_agent_args_test.go | 88 +++++++++++++++++-- .../resources/pod_creator_arangod.go | 12 ++- .../pod_creator_coordinator_args_test.go | 44 ++++++++-- .../pod_creator_dbserver_args_test.go | 44 ++++++++-- .../resources/pod_creator_single_args_test.go | 45 ++++++++-- pkg/deployment/resources/pod_creator_sync.go | 2 +- pkg/deployment/resources/secrets.go | 1 + pkg/util/k8sutil/interfaces/pod_creator.go | 4 +- 20 files changed, 420 insertions(+), 75 deletions(-) create mode 100644 pkg/deployment/pod/utils.go diff --git a/CHANGELOG.md b/CHANGELOG.md index f4cc5f53f..9ea5756c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change Log ## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A) +- Add IP, DNS, ShortDNS, HeadlessService (Default) communication methods ## [1.1.8](https://github.com/arangodb/kube-arangodb/tree/1.1.8) (2021-04-21) - Prevent Single member recreation diff --git a/go.mod b/go.mod index 7a0280a45..c62e6658c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/arangodb/kube-arangodb go 1.16 replace ( - github.com/arangodb/go-driver => github.com/arangodb/go-driver v0.0.0-20200617115956-9dac4c7fed22 + github.com/arangodb/go-driver => github.com/arangodb/go-driver v0.0.0-20210518064911-4985e8be3d90 github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring => github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.46.0 github.com/prometheus-operator/prometheus-operator/pkg/client => github.com/prometheus-operator/prometheus-operator/pkg/client v0.46.0 github.com/stretchr/testify => github.com/stretchr/testify v1.5.1 @@ -42,6 +42,7 @@ require ( github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 github.com/jessevdk/go-assets-builder v0.0.0-20130903091706-b8483521738f // indirect github.com/jessevdk/go-flags v1.4.0 // indirect + github.com/json-iterator/go v1.1.10 github.com/julienschmidt/httprouter v1.3.0 github.com/kevinburke/rest v0.0.0-20210222204520-f7a2e216372f // indirect github.com/magiconair/properties v1.8.0 @@ -52,7 +53,7 @@ require ( github.com/prometheus-operator/prometheus-operator/pkg/client v0.0.0-00010101000000-000000000000 github.com/prometheus/client_golang v1.7.1 github.com/robfig/cron v1.2.0 - github.com/rs/zerolog v1.14.3 + github.com/rs/zerolog v1.19.0 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.5.1 @@ -60,7 +61,6 @@ require ( github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 // indirect github.com/voxelbrain/goptions v0.0.0-20180630082107-58cddc247ea2 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 - golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 golang.org/x/tools v0.1.1-0.20210504181558-0bb7e5c47b1a // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 40456a39a..cdcf4b08b 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,10 @@ github.com/arangodb/arangosync-client v0.6.3 h1:CJL9IxjCNVci2HNuWncZdVzHBeYTz0Ce github.com/arangodb/arangosync-client v0.6.3/go.mod h1:C0DmhtoPKJGm2PO18FrfZf4mVWcG7qW2YPBTFMR2P1g= github.com/arangodb/go-driver v0.0.0-20200617115956-9dac4c7fed22 h1:3Ken6Y1Qs+VLCTEiv1+807Gx2ToiuRCo8Dd1mPE5FC0= github.com/arangodb/go-driver v0.0.0-20200617115956-9dac4c7fed22/go.mod h1:JG79qtPYRxUB6CdGWSH1XwpolSBjthuZX+Iaz/H38rA= +github.com/arangodb/go-driver v0.0.0-20210517114204-8cc084268066 h1:NneOFWxfa7rhNXIfEYWgxytudmgj2KPZfYSnKXSVGcw= +github.com/arangodb/go-driver v0.0.0-20210517114204-8cc084268066/go.mod h1:3NUekcRLpgheFIGEwcOvxilEW73MV1queNKW58k7sdc= +github.com/arangodb/go-driver v0.0.0-20210518064911-4985e8be3d90 h1:NMnMsS32jOF+e0v+MLXlgRJM7ejSAXxHg1UDv1q417I= +github.com/arangodb/go-driver v0.0.0-20210518064911-4985e8be3d90/go.mod h1:3NUekcRLpgheFIGEwcOvxilEW73MV1queNKW58k7sdc= github.com/arangodb/go-upgrade-rules v0.0.0-20180809110947-031b4774ff21 h1:+W7D5ttxi/Ygh/39vialtypE23p9KI7P0J2qtoqUV4w= github.com/arangodb/go-upgrade-rules v0.0.0-20180809110947-031b4774ff21/go.mod h1:RkPIG6JJ2pcJUoymc18NxAJGraZd+iAEVnOTDjZey/w= github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g= @@ -226,6 +230,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/addlicense v0.0.0-20200817051935-6f4cd4aacc89/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA= github.com/google/addlicense v0.0.0-20200906110928-a0294312aa76 h1:JypWNzPMSgH5yL0NvFoAIsDRlKFgL0AsS3GO5bg4Pto= github.com/google/addlicense v0.0.0-20200906110928-a0294312aa76/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA= github.com/google/addlicense v0.0.0-20210428195630-6d92264d7170 h1:jLUa4MO3autxlRJmC4KubeE5QGIb5JqW9oEaqYTb/fA= @@ -415,6 +420,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.14.3 h1:4EGfSkR2hJDB0s3oFfrlPqjU1e4WLncergLil3nEKW0= github.com/rs/zerolog v1.14.3/go.mod h1:3WXPzbXEEliJ+a6UFE4vhIxV8qR1EML6ngzP9ug4eYg= +github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg= +github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -463,6 +470,7 @@ github.com/voxelbrain/goptions v0.0.0-20180630082107-58cddc247ea2/go.mod h1:DGCI github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= @@ -544,6 +552,7 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -563,6 +572,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= @@ -642,6 +652,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -650,6 +661,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200818005847-188abfa75333/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210504181558-0bb7e5c47b1a h1:xiJ7cj6CCsHjXZvlwLWEB1qwiw7jA7iWBzOLnkHM52c= diff --git a/pkg/apis/deployment/v1/deployment_spec.go b/pkg/apis/deployment/v1/deployment_spec.go index adb85046f..5942f798a 100644 --- a/pkg/apis/deployment/v1/deployment_spec.go +++ b/pkg/apis/deployment/v1/deployment_spec.go @@ -50,6 +50,46 @@ func validatePullPolicy(v core.PullPolicy) error { } } +// DeploymentCommunicationMethod define communication method used for inter-cluster communication +type DeploymentCommunicationMethod string + +// Get returns communication method from pointer. If pointer is nil default is returned. +func (d *DeploymentCommunicationMethod) Get() DeploymentCommunicationMethod { + if d == nil { + return DefaultDeploymentCommunicationMethod + } + + switch v := *d; v { + case DeploymentCommunicationMethodHeadlessService, DeploymentCommunicationMethodDNS, DeploymentCommunicationMethodIP, DeploymentCommunicationMethodShortDNS: + return v + default: + return DefaultDeploymentCommunicationMethod + } +} + +// String returns string representation of method. +func (d DeploymentCommunicationMethod) String() string { + return string(d) +} + +// New returns pointer. +func (d DeploymentCommunicationMethod) New() *DeploymentCommunicationMethod { + return &d +} + +const ( + // DefaultDeploymentCommunicationMethod define default communication method. + DefaultDeploymentCommunicationMethod = DeploymentCommunicationMethodHeadlessService + // DeploymentCommunicationMethodHeadlessService define old communication mechanism, based on headless service. + DeploymentCommunicationMethodHeadlessService DeploymentCommunicationMethod = "headless" + // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. + DeploymentCommunicationMethodDNS DeploymentCommunicationMethod = "dns" + // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. Use namespaced short DNS (used in migration) + DeploymentCommunicationMethodShortDNS DeploymentCommunicationMethod = "short-dns" + // DeploymentCommunicationMethodIP define ClusterIP Servce IP based communication. + DeploymentCommunicationMethodIP DeploymentCommunicationMethod = "ip" +) + // DeploymentSpec contains the spec part of a ArangoDeployment resource. type DeploymentSpec struct { Mode *DeploymentMode `json:"mode,omitempty"` @@ -118,6 +158,9 @@ type DeploymentSpec struct { Timeouts *Timeouts `json:"timeouts,omitempty"` ClusterDomain *string `json:"ClusterDomain,omitempty"` + + // CommunicationMethod define communication method used in deployment + CommunicationMethod *DeploymentCommunicationMethod `json:"communicationMethod,omitempty"` } // GetRestoreFrom returns the restore from string or empty string if not set diff --git a/pkg/apis/deployment/v1/zz_generated.deepcopy.go b/pkg/apis/deployment/v1/zz_generated.deepcopy.go index 72ce1847a..297974ff4 100644 --- a/pkg/apis/deployment/v1/zz_generated.deepcopy.go +++ b/pkg/apis/deployment/v1/zz_generated.deepcopy.go @@ -567,6 +567,11 @@ func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = new(string) **out = **in } + if in.CommunicationMethod != nil { + in, out := &in.CommunicationMethod, &out.CommunicationMethod + *out = new(DeploymentCommunicationMethod) + **out = **in + } return } diff --git a/pkg/deployment/deployment_inspector.go b/pkg/deployment/deployment_inspector.go index f74be1e8a..decc8857d 100644 --- a/pkg/deployment/deployment_inspector.go +++ b/pkg/deployment/deployment_inspector.go @@ -235,7 +235,7 @@ func (d *Deployment) inspectDeploymentWithError(ctx context.Context, lastInterva } // Ensure we have image info - if retrySoon, exists, err := d.ensureImages(ctx, d.apiObject); err != nil { + if retrySoon, exists, err := d.ensureImages(ctx, d.apiObject, cachedStatus); err != nil { return minInspectionInterval, errors.Wrapf(err, "Image detection failed") } else if retrySoon || !exists { return minInspectionInterval, nil diff --git a/pkg/deployment/images.go b/pkg/deployment/images.go index 4763eec31..c0c6c4b27 100644 --- a/pkg/deployment/images.go +++ b/pkg/deployment/images.go @@ -30,6 +30,8 @@ import ( "strings" "time" + inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector" + "github.com/arangodb/kube-arangodb/pkg/util/errors" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/interfaces" @@ -81,7 +83,7 @@ type imagesBuilder struct { // ensureImages creates pods needed to detect ImageID for specified images. // Returns: retrySoon, error -func (d *Deployment) ensureImages(ctx context.Context, apiObject *api.ArangoDeployment) (bool, bool, error) { +func (d *Deployment) ensureImages(ctx context.Context, apiObject *api.ArangoDeployment, cachedStatus inspectorInterface.Inspector) (bool, bool, error) { status, lastVersion := d.GetStatus() ib := imagesBuilder{ APIObject: apiObject, @@ -96,8 +98,7 @@ func (d *Deployment) ensureImages(ctx context.Context, apiObject *api.ArangoDepl return nil }, } - - retrySoon, exists, err := ib.Run(ctx) + retrySoon, exists, err := ib.Run(ctx, cachedStatus) if err != nil { return retrySoon, exists, errors.WithStack(err) } @@ -107,11 +108,11 @@ func (d *Deployment) ensureImages(ctx context.Context, apiObject *api.ArangoDepl // Run creates pods needed to detect ImageID for specified images and puts the found // image ID's into the status.Images list. // Returns: retrySoon, error -func (ib *imagesBuilder) Run(ctx context.Context) (bool, bool, error) { +func (ib *imagesBuilder) Run(ctx context.Context, cachedStatus inspectorInterface.Inspector) (bool, bool, error) { // Check ArangoDB image if _, found := ib.Status.Images.GetByImage(ib.Spec.GetImage()); !found { // We need to find the image ID for the ArangoDB image - retrySoon, err := ib.fetchArangoDBImageIDAndVersion(ctx, ib.Spec.GetImage()) + retrySoon, err := ib.fetchArangoDBImageIDAndVersion(ctx, cachedStatus, ib.Spec.GetImage()) if err != nil { return retrySoon, false, errors.WithStack(err) } @@ -124,7 +125,7 @@ func (ib *imagesBuilder) Run(ctx context.Context) (bool, bool, error) { // fetchArangoDBImageIDAndVersion checks a running pod for fetching the ID of the given image. // When no pod exists, it is created, otherwise the ID is fetched & version detected. // Returns: retrySoon, error -func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, image string) (bool, error) { +func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, cachedStatus inspectorInterface.Inspector, image string) (bool, error) { role := k8sutil.ImageIDAndVersionRole id := fmt.Sprintf("%0x", sha1.Sum([]byte(image)))[:6] podName := k8sutil.CreatePodName(ib.APIObject.GetName(), role, id, "") @@ -225,7 +226,7 @@ func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, ima apiObject: ib.APIObject, } - pod, err = resources.RenderArangoPod(ib.APIObject, role, id, podName, args, &imagePod) + pod, err = resources.RenderArangoPod(cachedStatus, ib.APIObject, role, id, podName, args, &imagePod) if err != nil { log.Debug().Err(err).Msg("Failed to render image ID pod") return true, errors.WithStack(err) @@ -324,7 +325,7 @@ func (i *ImageUpdatePod) GetVolumes() ([]core.Volume, []core.VolumeMount) { func (i *ImageUpdatePod) GetSidecars(*core.Pod) { } -func (i *ImageUpdatePod) GetInitContainers() ([]core.Container, error) { +func (i *ImageUpdatePod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error) { return nil, nil } diff --git a/pkg/deployment/images_test.go b/pkg/deployment/images_test.go index 6b6763a6c..bd669a80a 100644 --- a/pkg/deployment/images_test.go +++ b/pkg/deployment/images_test.go @@ -29,6 +29,8 @@ import ( "testing" "time" + "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" + "github.com/arangodb/kube-arangodb/pkg/util/constants" "github.com/arangodb/kube-arangodb/pkg/deployment/resources" @@ -331,7 +333,7 @@ func TestEnsureImages(t *testing.T) { require.NoError(t, err) // Act - retrySoon, _, err := d.ensureImages(context.Background(), d.apiObject) + retrySoon, _, err := d.ensureImages(context.Background(), d.apiObject, inspector.NewEmptyInspector()) // Assert assert.EqualValues(t, testCase.RetrySoon, retrySoon) diff --git a/pkg/deployment/pod/utils.go b/pkg/deployment/pod/utils.go new file mode 100644 index 000000000..f9adc5272 --- /dev/null +++ b/pkg/deployment/pod/utils.go @@ -0,0 +1,46 @@ +package pod + +import ( + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" + "github.com/arangodb/kube-arangodb/pkg/util/errors" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service" + core "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func GenerateMemberEndpoint(services service.Inspector, apiObject meta.Object, spec api.DeploymentSpec, group api.ServerGroup, member api.MemberStatus) (string, error) { + memberName := member.ArangoMemberName(apiObject.GetName(), group) + svc, ok := services.Service(memberName) + if !ok { + return "", errors.Newf("Service %s not found", memberName) + } + + return GenerateMemberEndpointFromService(svc, apiObject, spec, group, member) +} + +func GenerateMemberEndpointFromService(svc *core.Service, apiObject meta.Object, spec api.DeploymentSpec, group api.ServerGroup, member api.MemberStatus) (string, error) { + if group.IsArangod() { + switch method := spec.CommunicationMethod.Get(); method { + case api.DeploymentCommunicationMethodDNS, api.DeploymentCommunicationMethodIP: + switch method { + case api.DeploymentCommunicationMethodDNS: + return k8sutil.CreateServiceDNSNameWithDomain(svc, spec.ClusterDomain), nil + case api.DeploymentCommunicationMethodIP: + if svc.Spec.ClusterIP == "" { + return "", errors.Newf("ClusterIP of service %s is empty", svc.GetName()) + } + + return svc.Spec.ClusterIP, nil + case api.DeploymentCommunicationMethodShortDNS: + return svc.GetName(), nil + default: + return "", errors.Newf("Unexpected method %s", method.String()) + } + default: + return k8sutil.CreatePodDNSNameWithDomain(apiObject, spec.ClusterDomain, group.AsRole(), member.ID), nil + } + } else { + return k8sutil.CreateSyncMasterClientServiceDNSNameWithDomain(apiObject, spec.ClusterDomain), nil + } +} diff --git a/pkg/deployment/reconcile/action_wait_for_member_up.go b/pkg/deployment/reconcile/action_wait_for_member_up.go index 7c66f8d8c..877ec2e11 100644 --- a/pkg/deployment/reconcile/action_wait_for_member_up.go +++ b/pkg/deployment/reconcile/action_wait_for_member_up.go @@ -19,6 +19,7 @@ // // Author Ewout Prangsma // Author Tomasz Mielech +// Author Adam Janikowski // package reconcile @@ -150,6 +151,8 @@ func (a *actionWaitForMemberUp) checkProgressAgent(ctx context.Context) (bool, b shortCtx, c := context.WithTimeout(ctx, 3*time.Second) defer c() + shortCtx = agency.WithAllowDifferentLeaderEndpoints(ctx) + if err := agency.AreAgentsHealthy(shortCtx, clients); err != nil { log.Debug().Err(err).Msg("Not all agents are ready") return false, false, nil diff --git a/pkg/deployment/reconcile/plan_builder_rotate_upgrade.go b/pkg/deployment/reconcile/plan_builder_rotate_upgrade.go index e17d39e25..7d6b1d4f9 100644 --- a/pkg/deployment/reconcile/plan_builder_rotate_upgrade.go +++ b/pkg/deployment/reconcile/plan_builder_rotate_upgrade.go @@ -25,6 +25,10 @@ package reconcile import ( "context" + json "github.com/json-iterator/go" + + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" + "github.com/arangodb/kube-arangodb/pkg/deployment/resources" "github.com/arangodb/go-driver" @@ -115,7 +119,7 @@ func createRotateOrUpgradePlanInternal(ctx context.Context, log zerolog.Logger, !decision.AutoUpgradeNeeded) } else { // Use new level of rotate logic - rotNeeded, reason := podNeedsRotation(ctx, log, pod, spec, group, status, m, cachedStatus, context) + rotNeeded, reason := podNeedsRotation(ctx, log, apiObject, pod, spec, group, status, m, cachedStatus, context) if rotNeeded { newPlan = createRotateMemberPlan(log, m, group, reason) } @@ -282,9 +286,10 @@ func memberImageInfo(spec api.DeploymentSpec, status api.MemberStatus, images ap // given pod differs from what it should be according to the // given deployment spec. // When true is returned, a reason for the rotation is already returned. -func podNeedsRotation(ctx context.Context, log zerolog.Logger, p *core.Pod, spec api.DeploymentSpec, +func podNeedsRotation(ctx context.Context, log zerolog.Logger, apiObject k8sutil.APIObject, p *core.Pod, spec api.DeploymentSpec, group api.ServerGroup, status api.DeploymentStatus, m api.MemberStatus, cachedStatus inspectorInterface.Inspector, planCtx PlanBuilderContext) (bool, string) { + if m.PodUID != p.UID { return true, "Pod UID does not match, this pod is not managed by Operator. Recreating" } @@ -318,9 +323,31 @@ func podNeedsRotation(ctx context.Context, log zerolog.Logger, p *core.Pod, spec } if m.PodSpecVersion != checksum { + if _, err := json.Marshal(renderedPod); err == nil { + log.Info().Str("id", m.ID).Str("Before", m.PodSpecVersion).Str("After", checksum).Msgf("XXXXXXXXXXX Pod needs rotation - checksum does not match") + } return true, "Pod needs rotation - checksum does not match" } + endpoint, err := pod.GenerateMemberEndpoint(cachedStatus, apiObject, spec, group, m) + if err != nil { + log.Err(err).Msg("Error while getting pod endpoint") + return false, "" + } + + if e := m.Endpoint; e == nil { + if spec.CommunicationMethod == nil { + // TODO: Remove in 1.2.0 release to allow rotation + return false, "Pod endpoint is not set and CommunicationMethod is not set, do not recreate" + } + + return true, "Communication method has been set - ensure endpoint" + } else { + if *e != endpoint { + return true, "Pod endpoint changed" + } + } + return false, "" } diff --git a/pkg/deployment/resources/pod_creator.go b/pkg/deployment/resources/pod_creator.go index 86e25c822..8c8e7aa25 100644 --- a/pkg/deployment/resources/pod_creator.go +++ b/pkg/deployment/resources/pod_creator.go @@ -64,12 +64,12 @@ func versionHasAdvertisedEndpoint(v driver.Version) bool { } // createArangodArgsWithUpgrade creates command line arguments for an arangod server upgrade in the given group. -func createArangodArgsWithUpgrade(input pod.Input) []string { - return createArangodArgs(input, pod.AutoUpgrade().Args(input)...) +func createArangodArgsWithUpgrade(cachedStatus interfaces.Inspector, input pod.Input, additionalOptions ...k8sutil.OptionPair) ([]string, error) { + return createArangodArgs(cachedStatus, input, pod.AutoUpgrade().Args(input)...) } // createArangodArgs creates command line arguments for an arangod server in the given group. -func createArangodArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) []string { +func createArangodArgs(cachedStatus interfaces.Inspector, input pod.Input, additionalOptions ...k8sutil.OptionPair) ([]string, error) { options := k8sutil.CreateOptionPairs(64) //scheme := NewURLSchemes(bsCfg.SslKeyFile != "").Arangod @@ -107,15 +107,13 @@ func createArangodArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) versionHasAdvertisedEndpoint := versionHasAdvertisedEndpoint(input.Version) - /* if config.ServerThreads != 0 { - options = append(options, - k8sutil.OptionPair{"--server.threads", strconv.Itoa(config.ServerThreads)}) - }*/ - /*if config.DebugCluster { - options = append(options, - k8sutil.OptionPair{"--log.level", "startup=trace"}) - }*/ - myTCPURL := scheme + "://" + net.JoinHostPort(k8sutil.CreatePodDNSNameWithDomain(input.ApiObject, input.Deployment.ClusterDomain, input.Group.AsRole(), input.Member.ID), strconv.Itoa(k8sutil.ArangoPort)) + endpoint, err := pod.GenerateMemberEndpoint(cachedStatus, input.ApiObject, input.Deployment, input.Group, input.Member) + if err != nil { + return nil, err + } + endpoint = util.StringOrDefault(input.Member.Endpoint, endpoint) + + myTCPURL := scheme + "://" + net.JoinHostPort(endpoint, strconv.Itoa(k8sutil.ArangoPort)) addAgentEndpoints := false switch input.Group { case api.ServerGroupAgents: @@ -128,8 +126,11 @@ func createArangodArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) options.Add("--server.statistics", "false") for _, p := range input.Status.Members.Agents { if p.ID != input.Member.ID { - dnsName := p.GetEndpoint(k8sutil.CreatePodDNSNameWithDomain(input.ApiObject, input.Deployment.ClusterDomain, api.ServerGroupAgents.AsRole(), p.ID)) - options.Addf("--agency.endpoint", "%s://%s", scheme, net.JoinHostPort(dnsName, strconv.Itoa(k8sutil.ArangoPort))) + dnsName, err := pod.GenerateMemberEndpoint(cachedStatus, input.ApiObject, input.Deployment, api.ServerGroupAgents, p) + if err != nil { + return nil, err + } + options.Addf("--agency.endpoint", "%s://%s", scheme, net.JoinHostPort(util.StringOrDefault(p.Endpoint, dnsName), strconv.Itoa(k8sutil.ArangoPort))) } } case api.ServerGroupDBServers: @@ -162,8 +163,11 @@ func createArangodArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) } if addAgentEndpoints { for _, p := range input.Status.Members.Agents { - dnsName := p.GetEndpoint(k8sutil.CreatePodDNSNameWithDomain(input.ApiObject, input.Deployment.ClusterDomain, api.ServerGroupAgents.AsRole(), p.ID)) - options.Addf("--cluster.agency-endpoint", "%s://%s", scheme, net.JoinHostPort(dnsName, strconv.Itoa(k8sutil.ArangoPort))) + dnsName, err := pod.GenerateMemberEndpoint(cachedStatus, input.ApiObject, input.Deployment, api.ServerGroupAgents, p) + if err != nil { + return nil, err + } + options.Addf("--cluster.agency-endpoint", "%s://%s", scheme, net.JoinHostPort(util.StringOrDefault(p.Endpoint, dnsName), strconv.Itoa(k8sutil.ArangoPort))) } } @@ -176,12 +180,12 @@ func createArangodArgs(input pod.Input, additionalOptions ...k8sutil.OptionPair) args = append(args, input.GroupSpec.Args...) } - return args + return args, nil } // createArangoSyncArgs creates command line arguments for an arangosync server in the given group. -func createArangoSyncArgs(apiObject metav1.Object, spec api.DeploymentSpec, group api.ServerGroup, - groupSpec api.ServerGroupSpec, member api.MemberStatus) []string { +func createArangoSyncArgs(cachedStatus interfaces.Inspector, apiObject metav1.Object, spec api.DeploymentSpec, group api.ServerGroup, + groupSpec api.ServerGroupSpec, member api.MemberStatus) ([]string, error) { options := k8sutil.CreateOptionPairs(64) var runCmd string var port int @@ -241,7 +245,7 @@ func createArangoSyncArgs(apiObject metav1.Object, spec api.DeploymentSpec, grou args = append(args, groupSpec.Args...) } - return args + return args, nil } // CreatePodFinalizers creates a list of finalizers for a pod created for the given group. @@ -314,7 +318,7 @@ func (r *Resources) RenderPodForMember(ctx context.Context, cachedStatus inspect member, ok := cachedStatus.ArangoMember(memberName) if !ok { - return nil, errors.Newf("Service of member %s not found", memberName) + return nil, errors.Newf("ArangoMember %s not found", memberName) } // Update pod name @@ -346,13 +350,16 @@ func (r *Resources) RenderPodForMember(ctx context.Context, cachedStatus inspect input := memberPod.AsInput() - args := createArangodArgs(input) + args, err := createArangodArgs(cachedStatus, input) + if err != nil { + return nil, errors.WithStack(err) + } if err := memberPod.Validate(cachedStatus); err != nil { return nil, errors.WithStack(errors.Wrapf(err, "Validation of pods resources failed")) } - return RenderArangoPod(apiObject, role, newMember.ID, newMember.PodName, args, &memberPod) + return RenderArangoPod(cachedStatus, apiObject, role, newMember.ID, newMember.PodName, args, &memberPod) } else if group.IsArangosync() { // Check image if !imageInfo.Enterprise { @@ -408,7 +415,10 @@ func (r *Resources) RenderPodForMember(ctx context.Context, cachedStatus inspect } // Prepare arguments - args := createArangoSyncArgs(apiObject, spec, group, groupSpec, *newMember) + args, err := createArangoSyncArgs(cachedStatus, apiObject, spec, group, groupSpec, *newMember) + if err != nil { + return nil, errors.WithStack(err) + } memberSyncPod := MemberSyncPod{ tlsKeyfileSecretName: tlsKeyfileSecretName, @@ -423,7 +433,7 @@ func (r *Resources) RenderPodForMember(ctx context.Context, cachedStatus inspect arangoMember: *member, } - return RenderArangoPod(apiObject, role, newMember.ID, newMember.PodName, args, &memberSyncPod) + return RenderArangoPod(cachedStatus, apiObject, role, newMember.ID, newMember.PodName, args, &memberSyncPod) } else { return nil, errors.Newf("unable to render Pod") } @@ -476,13 +486,27 @@ func (r *Resources) createPodForMember(ctx context.Context, spec api.DeploymentS imageInfo = *m.Image + kubecli := r.context.GetKubeCli() + apiObject := r.context.GetAPIObject() + + endpoint, err := pod.GenerateMemberEndpoint(cachedStatus, apiObject, spec, group, m) + if err != nil { + return errors.WithStack(err) + } + + if m.Endpoint == nil || *m.Endpoint != endpoint { + // Update endpoint + m.Endpoint = &endpoint + if err := status.Members.Update(m, group); err != nil { + return errors.WithStack(err) + } + } + pod, err := r.RenderPodForMember(ctx, cachedStatus, spec, status, memberID, imageInfo) if err != nil { return errors.WithStack(err) } - kubecli := r.context.GetKubeCli() - apiObject := r.context.GetAPIObject() ns := r.context.GetNamespace() secrets := kubecli.CoreV1().Secrets(ns) if !found { @@ -518,7 +542,6 @@ func (r *Resources) createPodForMember(ctx context.Context, spec api.DeploymentS m.PodUID = uid m.PodSpecVersion = sha - m.Endpoint = util.NewString(k8sutil.CreatePodDNSNameWithDomain(apiObject, spec.ClusterDomain, role, m.ID)) m.ArangoVersion = m.Image.ArangoDBVersion m.ImageID = m.Image.ImageID @@ -571,7 +594,7 @@ func (r *Resources) createPodForMember(ctx context.Context, spec api.DeploymentS log.Debug().Str("pod-name", m.PodName).Msg("Created pod") m.PodUID = uid - m.Endpoint = util.NewString(k8sutil.CreateSyncMasterClientServiceDNSNameWithDomain(apiObject, spec.ClusterDomain)) + m.Endpoint = &endpoint m.PodSpecVersion = sha } // Record new member phase @@ -596,7 +619,7 @@ func (r *Resources) createPodForMember(ctx context.Context, spec api.DeploymentS } // RenderArangoPod renders new ArangoD Pod -func RenderArangoPod(deployment k8sutil.APIObject, role, id, podName string, +func RenderArangoPod(cachedStatus inspectorInterface.Inspector, deployment k8sutil.APIObject, role, id, podName string, args []string, podCreator interfaces.PodCreator) (*core.Pod, error) { // Prepare basic pod @@ -620,7 +643,7 @@ func RenderArangoPod(deployment k8sutil.APIObject, role, id, podName string, podCreator.Init(&p) - if initContainers, err := podCreator.GetInitContainers(); err != nil { + if initContainers, err := podCreator.GetInitContainers(cachedStatus); err != nil { return nil, errors.WithStack(err) } else if initContainers != nil { p.Spec.InitContainers = append(p.Spec.InitContainers, initContainers...) diff --git a/pkg/deployment/resources/pod_creator_agent_args_test.go b/pkg/deployment/resources/pod_creator_agent_args_test.go index dcfe0b07b..3cb0b413c 100644 --- a/pkg/deployment/resources/pod_creator_agent_args_test.go +++ b/pkg/deployment/resources/pod_creator_agent_args_test.go @@ -25,6 +25,11 @@ package resources import ( "testing" + "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" + inspectorInterface "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector" + "github.com/stretchr/testify/require" + core "k8s.io/api/core/v1" + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" "github.com/stretchr/testify/assert" @@ -34,6 +39,54 @@ import ( "github.com/arangodb/kube-arangodb/pkg/util" ) +type inspectorMock interface { + AddService(t *testing.T, svc ...*core.Service) inspectorMock + + RegisterMemberStatus(t *testing.T, apiObject *api.ArangoDeployment, group api.ServerGroup, members ...api.MemberStatus) inspectorMock + + Get(t *testing.T) inspectorInterface.Inspector +} + +func newInspectorMock(t *testing.T) inspectorMock { + return inspectorMockStruct{ + services: map[string]*core.Service{}, + } +} + +type inspectorMockStruct struct { + services map[string]*core.Service +} + +func (i inspectorMockStruct) RegisterMemberStatus(t *testing.T, apiObject *api.ArangoDeployment, group api.ServerGroup, members ...api.MemberStatus) inspectorMock { + var z inspectorMock = i + for _, member := range members { + memberName := member.ArangoMemberName(apiObject.GetName(), group) + + svc := core.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: memberName, + }, + Spec: core.ServiceSpec{ + ClusterIP: "127.0.0.1", + }, + } + z = z.AddService(t, &svc) + } + return z +} + +func (i inspectorMockStruct) AddService(t *testing.T, svc ...*core.Service) inspectorMock { + for _, s := range svc { + i.services[s.GetName()] = s + } + + return i +} + +func (i inspectorMockStruct) Get(t *testing.T) inspectorInterface.Inspector { + return inspector.NewInspectorFromData(nil, nil, nil, i.services, nil, nil, nil, nil) +} + // TestCreateArangodArgsAgent tests createArangodArgs for agent. func TestCreateArangodArgsAgent(t *testing.T) { // Default deployment @@ -64,7 +117,12 @@ func TestCreateArangodArgsAgent(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--agency.activate=true", @@ -119,7 +177,12 @@ func TestCreateArangodArgsAgent(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--agency.activate=true", @@ -178,7 +241,12 @@ func TestCreateArangodArgsAgent(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--agency.activate=true", @@ -232,7 +300,12 @@ func TestCreateArangodArgsAgent(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--agency.activate=true", @@ -286,7 +359,12 @@ func TestCreateArangodArgsAgent(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--agency.activate=true", diff --git a/pkg/deployment/resources/pod_creator_arangod.go b/pkg/deployment/resources/pod_creator_arangod.go index 526e82d0a..0aa585a6a 100644 --- a/pkg/deployment/resources/pod_creator_arangod.go +++ b/pkg/deployment/resources/pod_creator_arangod.go @@ -391,7 +391,7 @@ func (m *MemberArangoDPod) IsDeploymentMode() bool { return m.spec.IsDevelopment() } -func (m *MemberArangoDPod) GetInitContainers() ([]core.Container, error) { +func (m *MemberArangoDPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error) { var initContainers []core.Container if c := m.groupSpec.InitContainers.GetContainers(); len(c) > 0 { @@ -426,7 +426,10 @@ func (m *MemberArangoDPod) GetInitContainers() ([]core.Container, error) { { // Upgrade container - run in background if m.autoUpgrade || m.status.Upgrade { - args := createArangodArgsWithUpgrade(m.AsInput()) + args, err := createArangodArgsWithUpgrade(cachedStatus, m.AsInput()) + if err != nil { + return nil, err + } c, err := k8sutil.NewContainer(args, m.GetContainerCreator()) if err != nil { @@ -447,7 +450,10 @@ func (m *MemberArangoDPod) GetInitContainers() ([]core.Container, error) { { versionArgs := pod.UpgradeVersionCheck().Args(m.AsInput()) if len(versionArgs) > 0 { - args := createArangodArgs(m.AsInput(), versionArgs...) + args, err := createArangodArgs(cachedStatus, m.AsInput(), versionArgs...) + if err != nil { + return nil, err + } c, err := k8sutil.NewContainer(args, m.GetContainerCreator()) if err != nil { diff --git a/pkg/deployment/resources/pod_creator_coordinator_args_test.go b/pkg/deployment/resources/pod_creator_coordinator_args_test.go index b235eed15..5b50fc9e5 100644 --- a/pkg/deployment/resources/pod_creator_coordinator_args_test.go +++ b/pkg/deployment/resources/pod_creator_coordinator_args_test.go @@ -25,6 +25,8 @@ package resources import ( "testing" + "github.com/stretchr/testify/require" + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" "github.com/stretchr/testify/assert" @@ -64,7 +66,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -116,7 +123,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -169,7 +181,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -225,7 +242,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=tcp://name-agent-a1.name-int.ns.svc:8529", @@ -276,7 +298,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -329,7 +356,12 @@ func TestCreateArangodArgsCoordinator(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", diff --git a/pkg/deployment/resources/pod_creator_dbserver_args_test.go b/pkg/deployment/resources/pod_creator_dbserver_args_test.go index fd2914cb1..de8fef1e7 100644 --- a/pkg/deployment/resources/pod_creator_dbserver_args_test.go +++ b/pkg/deployment/resources/pod_creator_dbserver_args_test.go @@ -25,6 +25,8 @@ package resources import ( "testing" + "github.com/stretchr/testify/require" + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" "github.com/stretchr/testify/assert" @@ -64,7 +66,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -116,7 +123,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -170,7 +182,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc.cluster.local:8529", @@ -226,7 +243,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=tcp://name-agent-a1.name-int.ns.svc:8529", @@ -277,7 +299,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", @@ -330,7 +357,12 @@ func TestCreateArangodArgsDBServer(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", diff --git a/pkg/deployment/resources/pod_creator_single_args_test.go b/pkg/deployment/resources/pod_creator_single_args_test.go index 53fc9b25e..3029c4c2b 100644 --- a/pkg/deployment/resources/pod_creator_single_args_test.go +++ b/pkg/deployment/resources/pod_creator_single_args_test.go @@ -25,6 +25,8 @@ package resources import ( "testing" + "github.com/stretchr/testify/require" + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -54,7 +56,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.directory=/data", @@ -91,7 +97,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: true, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgsWithUpgrade(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgsWithUpgrade(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.auto-upgrade=true", @@ -132,7 +142,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.directory=/data", @@ -168,7 +182,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.directory=/data", @@ -206,7 +224,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.directory=/data", @@ -243,7 +265,11 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "a1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--database.directory=/data", @@ -292,7 +318,12 @@ func TestCreateArangodArgsSingle(t *testing.T) { AutoUpgrade: false, Member: api.MemberStatus{ID: "id1"}, } - cmdline := createArangodArgs(input) + + i := newInspectorMock(t).RegisterMemberStatus(t, apiObject, input.Group, input.Member) + i = i.RegisterMemberStatus(t, apiObject, api.ServerGroupAgents, agents...) + + cmdline, err := createArangodArgs(i.Get(t), input) + require.NoError(t, err) assert.Equal(t, []string{ "--cluster.agency-endpoint=ssl://name-agent-a1.name-int.ns.svc:8529", diff --git a/pkg/deployment/resources/pod_creator_sync.go b/pkg/deployment/resources/pod_creator_sync.go index aabba473c..2d49c222e 100644 --- a/pkg/deployment/resources/pod_creator_sync.go +++ b/pkg/deployment/resources/pod_creator_sync.go @@ -264,7 +264,7 @@ func (m *MemberSyncPod) IsDeploymentMode() bool { return m.spec.IsDevelopment() } -func (m *MemberSyncPod) GetInitContainers() ([]core.Container, error) { +func (m *MemberSyncPod) GetInitContainers(cachedStatus interfaces.Inspector) ([]core.Container, error) { var initContainers []core.Container if c := m.groupSpec.InitContainers.GetContainers(); len(c) > 0 { diff --git a/pkg/deployment/resources/secrets.go b/pkg/deployment/resources/secrets.go index 7cc6ed778..f58999d29 100644 --- a/pkg/deployment/resources/secrets.go +++ b/pkg/deployment/resources/secrets.go @@ -150,6 +150,7 @@ func (r *Resources) EnsureSecrets(ctx context.Context, log zerolog.Logger, cache k8sutil.CreatePodDNSName(apiObject, role, m.ID), k8sutil.CreateServiceDNSName(service), service.Spec.ClusterIP, + service.GetName(), } if spec.ClusterDomain != nil { diff --git a/pkg/util/k8sutil/interfaces/pod_creator.go b/pkg/util/k8sutil/interfaces/pod_creator.go index 8022a9cb3..6e48e20ca 100644 --- a/pkg/util/k8sutil/interfaces/pod_creator.go +++ b/pkg/util/k8sutil/interfaces/pod_creator.go @@ -24,11 +24,13 @@ package interfaces import ( "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/secret" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/service" core "k8s.io/api/core/v1" ) type Inspector interface { secret.Inspector + service.Inspector } type PodModifier interface { @@ -41,7 +43,7 @@ type PodCreator interface { GetRole() string GetVolumes() ([]core.Volume, []core.VolumeMount) GetSidecars(*core.Pod) - GetInitContainers() ([]core.Container, error) + GetInitContainers(cachedStatus Inspector) ([]core.Container, error) GetFinalizers() []string GetTolerations() []core.Toleration GetNodeSelector() map[string]string From abc7ecb0641f3254bd3476f4a18c05a16d5e0420 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 18 May 2021 10:29:11 +0000 Subject: [PATCH 2/3] Generate assets --- Makefile | 4 +- dashboard/assets.go | 116 ++++++++++++++++++------------------ pkg/deployment/pod/utils.go | 22 +++++++ 3 files changed, 83 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index 11b08709d..f23004c2a 100644 --- a/Makefile +++ b/Makefile @@ -229,7 +229,7 @@ dashboard/assets.go: $(DASHBOARDSOURCES) $(DASHBOARDDIR)/Dockerfile.build -v $(DASHBOARDDIR)/public:/usr/code/public:ro \ -v $(DASHBOARDDIR)/src:/usr/code/src:ro \ $(DASHBOARDBUILDIMAGE) - go run github.com/jessevdk/go-assets-builder -s /dashboard/build/ -o dashboard/assets.go -p dashboard dashboard/build + $(GOPATH)/bin/go-assets-builder -s /dashboard/build/ -o dashboard/assets.go -p dashboard dashboard/build .PHONY: bin bin: $(BIN) @@ -418,6 +418,8 @@ tools: update-vendor @go get golang.org/x/tools/cmd/goimports@0bb7e5c47b1a31f85d4f173edc878a8e049764a5 @echo ">> Fetching license check" @go get github.com/google/addlicense@6d92264d717064f28b32464f0f9693a5b4ef0239 + @echo ">> Fetching GO Assets Builder" + @go get github.com/jessevdk/go-assets-builder@b8483521738fd2198ecfc378067a4e8a6079f8e5 .PHONY: vendor vendor: diff --git a/dashboard/assets.go b/dashboard/assets.go index edf9980dd..aa0553242 100644 --- a/dashboard/assets.go +++ b/dashboard/assets.go @@ -26,106 +26,106 @@ import ( "github.com/jessevdk/go-assets" ) -var _Assetsae1884d1b816c0c01a2d8489774efacc09dcaa2b = "(window.webpackJsonpdashboard=window.webpackJsonpdashboard||[]).push([[2],[function(e,t,n){\"use strict\";e.exports=n(246)},function(e,t){e.exports=function(e){if(void 0===e)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return e}},function(e,t){e.exports=function(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}},function(e,t){function n(){return e.exports=n=Object.assign||function(e){for(var t=1;t-1:!!s&&r(e,t,n)>-1}},function(e,t,n){var r=n(57),o=n(41),a=n(343),i=n(21);e.exports=function(e,t){return(i(e)?r:a)(e,o(t,3))}},function(e,t,n){\"use strict\";function r(e,t,n,r,o,a,i){try{var l=e[a](i),c=l.value}catch(u){return void n(u)}l.done?t(c):Promise.resolve(c).then(r,o)}function o(e){return function(){var t=this,n=arguments;return new Promise((function(o,a){var i=e.apply(t,n);function l(e){r(i,o,a,l,c,\"next\",e)}function c(e){r(i,o,a,l,c,\"throw\",e)}l(void 0)}))}}n.d(t,\"a\",(function(){return o}))},function(e,t,n){\"use strict\";for(var r=function(e){return null!==e&&!Array.isArray(e)&&\"object\"===typeof e},o={3:\"Cancel\",6:\"Help\",8:\"Backspace\",9:\"Tab\",12:\"Clear\",13:\"Enter\",16:\"Shift\",17:\"Control\",18:\"Alt\",19:\"Pause\",20:\"CapsLock\",27:\"Escape\",28:\"Convert\",29:\"NonConvert\",30:\"Accept\",31:\"ModeChange\",32:\" \",33:\"PageUp\",34:\"PageDown\",35:\"End\",36:\"Home\",37:\"ArrowLeft\",38:\"ArrowUp\",39:\"ArrowRight\",40:\"ArrowDown\",41:\"Select\",42:\"Print\",43:\"Execute\",44:\"PrintScreen\",45:\"Insert\",46:\"Delete\",48:[\"0\",\")\"],49:[\"1\",\"!\"],50:[\"2\",\"@\"],51:[\"3\",\"#\"],52:[\"4\",\"$\"],53:[\"5\",\"%\"],54:[\"6\",\"^\"],55:[\"7\",\"&\"],56:[\"8\",\"*\"],57:[\"9\",\"(\"],91:\"OS\",93:\"ContextMenu\",144:\"NumLock\",145:\"ScrollLock\",181:\"VolumeMute\",182:\"VolumeDown\",183:\"VolumeUp\",186:[\";\",\":\"],187:[\"=\",\"+\"],188:[\",\",\"<\"],189:[\"-\",\"_\"],190:[\".\",\">\"],191:[\"/\",\"?\"],192:[\"`\",\"~\"],219:[\"[\",\"{\"],220:[\"\\\\\",\"|\"],221:[\"]\",\"}\"],222:[\"'\",'\"'],224:\"Meta\",225:\"AltGraph\",246:\"Attn\",247:\"CrSel\",248:\"ExSel\",249:\"EraseEof\",250:\"Play\",251:\"ZoomOut\"},a=0;a<24;a+=1)o[112+a]=\"F\"+(a+1);for(var i=0;i<26;i+=1){var l=i+65;o[l]=[String.fromCharCode(l+32),String.fromCharCode(l)]}var c={codes:o,getCode:function(e){return r(e)?e.keyCode||e.which||this[e.key]:this[e]},getKey:function(e){var t=r(e);if(t&&e.key)return e.key;var n=o[t?e.keyCode||e.which:e];return Array.isArray(n)&&(n=t?n[e.shiftKey?1:0]:n[0]),n},Cancel:3,Help:6,Backspace:8,Tab:9,Clear:12,Enter:13,Shift:16,Control:17,Alt:18,Pause:19,CapsLock:20,Escape:27,Convert:28,NonConvert:29,Accept:30,ModeChange:31,\" \":32,PageUp:33,PageDown:34,End:35,Home:36,ArrowLeft:37,ArrowUp:38,ArrowRight:39,ArrowDown:40,Select:41,Print:42,Execute:43,PrintScreen:44,Insert:45,Delete:46,0:48,\")\":48,1:49,\"!\":49,2:50,\"@\":50,3:51,\"#\":51,4:52,$:52,5:53,\"%\":53,6:54,\"^\":54,7:55,\"&\":55,8:56,\"*\":56,9:57,\"(\":57,a:65,A:65,b:66,B:66,c:67,C:67,d:68,D:68,e:69,E:69,f:70,F:70,g:71,G:71,h:72,H:72,i:73,I:73,j:74,J:74,k:75,K:75,l:76,L:76,m:77,M:77,n:78,N:78,o:79,O:79,p:80,P:80,q:81,Q:81,r:82,R:82,s:83,S:83,t:84,T:84,u:85,U:85,v:86,V:86,w:87,W:87,x:88,X:88,y:89,Y:89,z:90,Z:90,OS:91,ContextMenu:93,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,F13:124,F14:125,F15:126,F16:127,F17:128,F18:129,F19:130,F20:131,F21:132,F22:133,F23:134,F24:135,NumLock:144,ScrollLock:145,VolumeMute:181,VolumeDown:182,VolumeUp:183,\";\":186,\":\":186,\"=\":187,\"+\":187,\",\":188,\"<\":188,\"-\":189,_:189,\".\":190,\">\":190,\"/\":191,\"?\":191,\"`\":192,\"~\":192,\"[\":219,\"{\":219,\"\\\\\":220,\"|\":220,\"]\":221,\"}\":221,\"'\":222,'\"':222,Meta:224,AltGraph:225,Attn:246,CrSel:247,ExSel:248,EraseEof:249,Play:250,ZoomOut:251};c.Spacebar=c[\" \"],c.Digit0=c[0],c.Digit1=c[1],c.Digit2=c[2],c.Digit3=c[3],c.Digit4=c[4],c.Digit5=c[5],c.Digit6=c[6],c.Digit7=c[7],c.Digit8=c[8],c.Digit9=c[9],c.Tilde=c[\"~\"],c.GraveAccent=c[\"`\"],c.ExclamationPoint=c[\"!\"],c.AtSign=c[\"@\"],c.PoundSign=c[\"#\"],c.PercentSign=c[\"%\"],c.Caret=c[\"^\"],c.Ampersand=c[\"&\"],c.PlusSign=c[\"+\"],c.MinusSign=c[\"-\"],c.EqualsSign=c[\"=\"],c.DivisionSign=c[\"/\"],c.MultiplicationSign=c[\"*\"],c.Comma=c[\",\"],c.Decimal=c[\".\"],c.Colon=c[\":\"],c.Semicolon=c[\";\"],c.Pipe=c[\"|\"],c.BackSlash=c[\"\\\\\"],c.QuestionMark=c[\"?\"],c.SingleQuote=c[\"'\"],c.DoubleQuote=c['\"'],c.LeftCurlyBrace=c[\"{\"],c.RightCurlyBrace=c[\"}\"],c.LeftParenthesis=c[\"(\"],c.RightParenthesis=c[\")\"],c.LeftAngleBracket=c[\"<\"],c.RightAngleBracket=c[\">\"],c.LeftSquareBracket=c[\"[\"],c.RightSquareBracket=c[\"]\"],e.exports=c},function(e,t,n){var r=n(161),o=n(64),a=n(92),i=o((function(e,t){return a(e)?r(e,t):[]}));e.exports=i},function(e,t,n){\"use strict\";n.d(t,\"a\",(function(){return i})),n.d(t,\"d\",(function(){return l})),n.d(t,\"b\",(function(){return c})),n.d(t,\"c\",(function(){return u})),n.d(t,\"e\",(function(){return s})),n.d(t,\"f\",(function(){return f}));var r=n(44),o=n.n(r),a=n(67),i=function(e,t){return e&&t},l=function(e,t){return e&&!0!==e&&\"\".concat(e,\" \").concat(t)},c=function(e,t){return e&&(!0===e?t:\"\".concat(e,\" \").concat(t))},u=function(e){return\"justified\"===e?\"justified\":l(e,\"aligned\")},s=function(e){return l(e,\"aligned\")},f=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"\",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(n&&\"equal\"===e)return\"equal width\";var r=o()(e);return\"string\"!==r&&\"number\"!==r||!t?Object(a.a)(e):\"\".concat(Object(a.a)(e),\" \").concat(t)}},,function(e,t){e.exports=function(e){return null!=e&&\"object\"==typeof e}},function(e,t,n){var r=n(98);e.exports=function(e,t,n){var o=null==e?void 0:r(e,t);return void 0===o?n:o}},function(e,t,n){var r=n(162),o=\"object\"==typeof self&&self&&self.Object===Object&&self,a=r||o||Function(\"return this\")();e.exports=a},function(e,t,n){var r=n(0),o=n(252);e.exports=o(r)},function(e,t,n){var r=n(50),o=n(122);e.exports=function(e){return null!=e&&o(e.length)&&!r(e)}},function(e,t,n){\"use strict\";var r=n(9),o=n.n(r),a=n(10),i=n.n(a),l=n(2),c=n.n(l),u=n(46),s=n(68),f=n.n(s),p=function(){function e(t){o()(this,e),this.handlers=new Set(t)}return i()(e,[{key:\"addHandlers\",value:function(t){var n=new Set(this.handlers);return t.forEach((function(e){n.delete(e),n.add(e)})),new e(n)}},{key:\"dispatchEvent\",value:function(e,t){t?this.handlers.forEach((function(t){t(e)})):f()(this.handlers).pop()(e)}},{key:\"hasHandlers\",value:function(){return this.handlers.size>0}},{key:\"removeHandlers\",value:function(t){var n=new Set(this.handlers);return t.forEach((function(e){n.delete(e)})),new e(n)}}]),e}(),d=function(){function e(t,n){o()(this,e),this.handlerSets=n,this.poolName=t}return i()(e,[{key:\"addHandlers\",value:function(t,n){var r=new Map(this.handlerSets);return r.has(t)?r.set(t,r.get(t).addHandlers(n)):r.set(t,new p(n)),new e(this.poolName,r)}},{key:\"dispatchEvent\",value:function(e,t){var n=this.handlerSets.get(e);n&&n.dispatchEvent(t,\"default\"===this.poolName)}},{key:\"hasHandlers\",value:function(e){var t=this.handlerSets.get(e);return!!t&&t.hasHandlers()}},{key:\"removeHandlers\",value:function(t,n){var r=new Map(this.handlerSets);if(!r.has(t))return new e(this.poolName,r);var o=r.get(t).removeHandlers(n);return o.hasHandlers()?r.set(t,o):r.delete(t),new e(this.poolName,r)}}]),e}();c()(d,\"createByType\",(function(e,t,n){var r=new Map;return r.set(t,new p(n)),new d(e,r)}));var h=function(){function e(t){o()(this,e),c()(this,\"handlers\",new Map),c()(this,\"pools\",new Map),c()(this,\"createEmitter\",(function(e,t){return function(n){t.forEach((function(t){t.dispatchEvent(e,n)}))}})),this.target=t}return i()(e,[{key:\"addHandlers\",value:function(e,t,n){this.removeTargetHandler(t),this.pools.has(e)?this.pools.set(e,this.pools.get(e).addHandlers(t,n)):this.pools.set(e,d.createByType(e,t,n)),this.addTargetHandler(t)}},{key:\"hasHandlers\",value:function(){return this.handlers.size>0}},{key:\"removeHandlers\",value:function(e,t,n){var r=this.pools.get(e);if(r){var o=r.removeHandlers(t,n);o.hasHandlers(t)?(this.removeTargetHandler(t),this.pools.set(e,o)):(this.removeTargetHandler(t),this.pools.delete(e)),this.pools.size>0&&this.addTargetHandler(t)}}},{key:\"addTargetHandler\",value:function(e){var t=this.createEmitter(e,this.pools);this.handlers.set(e,t),this.target.addEventListener(e,t)}},{key:\"removeTargetHandler\",value:function(e){this.handlers.has(e)&&(this.target.removeEventListener(e,this.handlers.get(e)),this.handlers.delete(e))}}]),e}(),v=n(21),m=n.n(v),y=function(e){return m()(e)?e:[e]},b=function(e){return\"document\"===e?document:\"window\"===e?window:e||document},g=new(function(){function e(){var t=this;o()(this,e),c()(this,\"targets\",new Map),c()(this,\"getTarget\",(function(e){var n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],r=b(e);if(t.targets.has(r))return t.targets.get(r);if(!n)return null;var o=new h(r);return t.targets.set(r,o),o})),c()(this,\"removeTarget\",(function(e){t.targets.delete(b(e))}))}return i()(e,[{key:\"sub\",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(Object(u.a)()){var r=n.target,o=void 0===r?document:r,a=n.pool,i=void 0===a?\"default\":a,l=this.getTarget(o);l.addHandlers(i,e,y(t))}}},{key:\"unsub\",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(Object(u.a)()){var r=n.target,o=void 0===r?document:r,a=n.pool,i=void 0===a?\"default\":a,l=this.getTarget(o,!1);l&&(l.removeHandlers(i,e,y(t)),l.hasHandlers()||this.removeTarget(o))}}}]),e}());t.a=g},function(e,t,n){var r=n(56),o=n(262),a=n(263),i=\"[object Null]\",l=\"[object Undefined]\",c=r?r.toStringTag:void 0;e.exports=function(e){return null==e?void 0===e?l:i:c&&c in Object(e)?o(e):a(e)}},function(e,t,n){\"use strict\";function r(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}n.d(t,\"a\",(function(){return r}))},function(e,t,n){\"use strict\";var r=n(0),o=n.n(r),a=n(106),i=n(6),l=n.n(i),c=n(111),u=/^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|valueLink|accept|acceptCharset|accessKey|action|allow|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|default|defer|dir|disabled|download|draggable|encType|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|itemProp|itemScope|itemType|itemID|itemRef|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class)|(on[A-Z].*)|((data|aria|x)-.*))$/i,s=Object(c.a)(u.test.bind(u));function f(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}var p,d=\"__EMOTION_THEMING__\",h=((p={})[d]=l.a.object,p);function v(e){this.setState({theme:e})}var m=s,y=function(e){return\"theme\"!==e&&\"innerRef\"!==e},b=function(){return!0},g=function(e,t){for(var n=2,r=arguments.length;n-1&&e%1==0&&e1&&void 0!==arguments[1]?arguments[1]:{},n=t.htmlProps,r=void 0===n?c:n,a=t.includeAria,l=void 0===a||a,u={},s={};return i()(e,(function(e,t){var n=l&&(/^aria-.*$/.test(t)||\"role\"===t);(o()(r,t)||n?u:s)[t]=e})),[u,s]}},function(e,t){e.exports=function(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n-1}},function(e,t){e.exports=function(e,t){return e.has(t)}},function(e,t){e.exports=function(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}},function(e,t,n){var r=n(33),o=n(29);e.exports=function(e){return o(e)&&r(e)}},function(e,t){e.exports=function(e){var t=-1,n=Array(e.size);return e.forEach((function(e){n[++t]=e})),n}},function(e,t,n){var r=n(301),o=n(29),a=Object.prototype,i=a.hasOwnProperty,l=a.propertyIsEnumerable,c=r(function(){return arguments}())?r:function(e){return o(e)&&i.call(e,\"callee\")&&!l.call(e,\"callee\")};e.exports=c},function(e,t,n){(function(e){var r=n(31),o=n(302),a=t&&!t.nodeType&&t,i=a&&\"object\"==typeof e&&e&&!e.nodeType&&e,l=i&&i.exports===a?r.Buffer:void 0,c=(l?l.isBuffer:void 0)||o;e.exports=c}).call(this,n(127)(e))},function(e,t,n){(function(e){var r=n(162),o=t&&!t.nodeType&&t,a=o&&\"object\"==typeof e&&e&&!e.nodeType&&e,i=a&&a.exports===o&&r.process,l=function(){try{var e=a&&a.require&&a.require(\"util\").types;return e||i&&i.binding&&i.binding(\"util\")}catch(t){}}();e.exports=l}).call(this,n(127)(e))},function(e,t,n){var r=n(72),o=n(304),a=Object.prototype.hasOwnProperty;e.exports=function(e){if(!r(e))return o(e);var t=[];for(var n in Object(e))a.call(e,n)&&\"constructor\"!=n&&t.push(n);return t}},function(e,t,n){var r=n(73),o=n(59);e.exports=function(e,t){for(var n=0,a=(t=r(t,e)).length;null!=e&&n0&&a(s)?n>1?e(s,n-1,a,i,l):r(l,s):i||(l[l.length]=s)}return l}},function(e,t){e.exports=function(e,t){for(var n=-1,r=null==e?0:e.length;++n1&&void 0!==arguments[1]?arguments[1]:\"\",n=e&&e.split(\"/\")||[],r=t&&t.split(\"/\")||[],i=e&&o(e),l=t&&o(t),c=i||l;if(e&&o(e)?r=n:n.length&&(r.pop(),r=r.concat(n)),!r.length)return\"/\";var u=void 0;if(r.length){var s=r[r.length-1];u=\".\"===s||\"..\"===s||\"\"===s}else u=!1;for(var f=0,p=r.length;p>=0;p--){var d=r[p];\".\"===d?a(r,p):\"..\"===d?(a(r,p),f++):f&&(a(r,p),f--)}if(!c)for(;f--;f)r.unshift(\"..\");!c||\"\"===r[0]||r[0]&&o(r[0])||r.unshift(\"\");var h=r.join(\"/\");return u&&\"/\"!==h.substr(-1)&&(h+=\"/\"),h};\"function\"===typeof Symbol&&Symbol.iterator;var l=!0,c=\"Invariant failed\";var u=function(e,t){if(!e)throw l?new Error(c):new Error(c+\": \"+(t||\"\"))};function s(e){return\"/\"===e.charAt(0)?e:\"/\"+e}function f(e,t){return function(e,t){return new RegExp(\"^\"+t+\"(\\\\/|\\\\?|#|$)\",\"i\").test(e)}(e,t)?e.substr(t.length):e}function p(e){return\"/\"===e.charAt(e.length-1)?e.slice(0,-1):e}function d(e){var t=e.pathname,n=e.search,r=e.hash,o=t||\"/\";return n&&\"?\"!==n&&(o+=\"?\"===n.charAt(0)?n:\"?\"+n),r&&\"#\"!==r&&(o+=\"#\"===r.charAt(0)?r:\"#\"+r),o}function h(e,t,n,o){var a;\"string\"===typeof e?(a=function(e){var t=e||\"/\",n=\"\",r=\"\",o=t.indexOf(\"#\");-1!==o&&(r=t.substr(o),t=t.substr(0,o));var a=t.indexOf(\"?\");return-1!==a&&(n=t.substr(a),t=t.substr(0,a)),{pathname:t,search:\"?\"===n?\"\":n,hash:\"#\"===r?\"\":r}}(e)).state=t:(void 0===(a=r({},e)).pathname&&(a.pathname=\"\"),a.search?\"?\"!==a.search.charAt(0)&&(a.search=\"?\"+a.search):a.search=\"\",a.hash?\"#\"!==a.hash.charAt(0)&&(a.hash=\"#\"+a.hash):a.hash=\"\",void 0!==t&&void 0===a.state&&(a.state=t));try{a.pathname=decodeURI(a.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname \"'+a.pathname+'\" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(a.key=n),o?a.pathname?\"/\"!==a.pathname.charAt(0)&&(a.pathname=i(a.pathname,o.pathname)):a.pathname=o.pathname:a.pathname||(a.pathname=\"/\"),a}function v(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,o){if(null!=e){var a=\"function\"===typeof e?e(t,n):e;\"string\"===typeof a?\"function\"===typeof r?r(a,o):o(!0):o(!1!==a)}else o(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r-1&&e%1==0&&e<=n}},function(e,t,n){var r=n(85),o=n(292),a=n(293),i=n(294),l=n(295),c=n(296);function u(e){var t=this.__data__=new r(e);this.size=t.size}u.prototype.clear=o,u.prototype.delete=a,u.prototype.get=i,u.prototype.has=l,u.prototype.set=c,e.exports=u},function(e,t,n){var r=n(297),o=n(29);e.exports=function e(t,n,a,i,l){return t===n||(null==t||null==n||!o(t)&&!o(n)?t!==t&&n!==n:r(t,n,a,i,e,l))}},function(e,t){e.exports=function(e,t){for(var n=-1,r=t.length,o=e.length;++no?0:o+t),(n=n>o?o:n)<0&&(n+=o),o=t>n?0:n-t>>>0,t>>>=0;for(var a=Array(o);++r3&&void 0!==arguments[3]&&arguments[3],o=t[e];if(void 0!==o)return o;if(r){var a=t[E(e)];if(void 0!==a)return a;if(n){var i=n[e];if(void 0!==i)return i}}return\"checked\"!==e&&(\"value\"===e?t.multiple?[]:\"\":void 0)},C=function(e){function t(){var e,n;i()(this,t);for(var r=arguments.length,a=new Array(r),l=0;l0&&n.setState(a)}));var c=n.constructor.autoControlledProps,u=O()(m()(m()(n)),\"getInitialAutoControlledState\",n.props)||{},f=c.reduce((function(e,t){return e[t]=j(t,n.props,u,!0),e}),{});return n.state=o()({},u,f),n}return h()(t,e),c()(t,[{key:\"componentWillReceiveProps\",value:function(e){var t=this,n=this.constructor.autoControlledProps.reduce((function(n,r){var o=x()(e[r]),a=!x()(t.props[r])&&o;return o?a&&(n[r]=j(r,e)):n[r]=e[r],n}),{});Object.keys(n).length>0&&this.setState(n)}}]),t}(k.Component)},function(e,t,n){e.exports=n(69)},function(e,t,n){var r=n(192);e.exports=function(e){return e&&e.length?r(e):[]}},function(e,t,n){var r=n(324),o=n(187),a=n(188);e.exports=function(e,t,n){return t=o(t),void 0===n?(n=t,t=0):n=o(n),e=a(e),r(e,t,n)}},function(e,t,n){var r=n(97),o=n(47),a=n(33),i=n(78),l=n(350),c=\"[object Map]\",u=\"[object Set]\";e.exports=function(e){if(null==e)return 0;if(a(e))return i(e)?l(e):e.length;var t=o(e);return t==c||t==u?e.size:r(e).length}},function(e,t,n){var r=n(100),o=n(64),a=n(192),i=n(92),l=o((function(e){return a(r(e,1,i,!0))}));e.exports=l},,,,,,,,,,function(e,t,n){var r=n(83),o=n(89),a=n(120),i=n(57),l=n(63),c=n(90),u=200;e.exports=function(e,t,n,s){var f=-1,p=o,d=!0,h=e.length,v=[],m=t.length;if(!h)return v;n&&(t=i(t,l(n))),s?(p=a,d=!1):t.length>=u&&(p=c,d=!1,t=new r(t));e:for(;++f0){if(++t>=n)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}},function(e,t,n){var r=n(83),o=n(170),a=n(90),i=1,l=2;e.exports=function(e,t,n,c,u,s){var f=n&i,p=e.length,d=t.length;if(p!=d&&!(f&&d>p))return!1;var h=s.get(e),v=s.get(t);if(h&&v)return h==t&&v==e;var m=-1,y=!0,b=n&l?new r:void 0;for(s.set(e,t),s.set(t,e);++m3&&void 0!==arguments[3]?arguments[3]:{};if(\"function\"!==typeof e&&\"string\"!==typeof e)throw new Error(\"createShorthand() Component must be a string or function.\");if(x()(n)||b()(n))return null;var a=m()(n),l=h()(n),u=p()(n),f=Object(k.isValidElement)(n),d=s()(n),v=a||l||c()(n);if(!u&&!f&&!d&&!v)return null;var y=r.defaultProps,g=void 0===y?{}:y,w=f&&n.props||d&&n||v&&t(n),j=r.overrideProps,C=void 0===j?{}:j;C=p()(C)?C(o()({},g,w)):C;var T=o()({},g,w,C);if(g.className||C.className||w.className){var _=O()(g.className,C.className,w.className);T.className=i()(_.split(\" \")).join(\" \")}if((g.style||C.style||w.style)&&(T.style=o()({},g.style,w.style,C.style)),x()(T.key)){var S=T.childKey,P=r.autoGenerateKey,N=void 0===P||P;x()(S)?N&&(a||l)&&(T.key=n):(T.key=\"function\"===typeof S?S(T):S,delete T.childKey)}return f?Object(k.cloneElement)(n,T):v||d?E.a.createElement(e,T):u?n(e,T,T.children):void 0}function C(e,t){if(\"function\"!==typeof e&&\"string\"!==typeof e)throw new Error(\"createShorthandFactory() Component must be a string or function.\");return function(n,r){return j(e,t,n,r)}}j.handledProps=[];C(\"div\",(function(e){return{children:e}})),C(\"iframe\",(function(e){return{src:e}})),C(\"img\",(function(e){return{src:e}}));var T=C(\"input\",(function(e){return{type:e}})),_=C(\"label\",(function(e){return{children:e}})),S=C(\"p\",(function(e){return{children:e}}))},function(e,t,n){var r=n(83),o=n(89),a=n(120),i=n(90),l=n(338),c=n(93),u=200;e.exports=function(e,t,n){var s=-1,f=o,p=e.length,d=!0,h=[],v=h;if(n)d=!1,f=a;else if(p>=u){var m=t?null:l(e);if(m)return c(m);d=!1,f=i,v=new r}else v=t?[]:h;e:for(;++s1&&h.reverse(),C&&E=o?e:r(e,t,n)}},function(e,t,n){e.exports=n(325)},function(e,t,n){var r=n(35),o=n(29),a=\"[object Boolean]\";e.exports=function(e){return!0===e||!1===e||o(e)&&r(e)==a}},function(e,t,n){e.exports=function(){\"use strict\";return function(e){function t(t){if(t)try{e(t+\"}\")}catch(n){}}return function(n,r,o,a,i,l,c,u,s,f){switch(n){case 1:if(0===s&&64===r.charCodeAt(0))return e(r+\";\"),\"\";break;case 2:if(0===u)return r+\"/*|*/\";break;case 3:switch(u){case 102:case 112:return e(o[0]+r),\"\";default:return r+(0===f?\"/*|*/\":\"\")}case-2:r.split(\"/*|*/}\").forEach(t)}}}}()},function(e,t){e.exports=function(e,t,n,r){var o=n?n.call(r,e,t):void 0;if(void 0!==o)return!!o;if(e===t)return!0;if(\"object\"!==typeof e||!e||\"object\"!==typeof t||!t)return!1;var a=Object.keys(e),i=Object.keys(t);if(a.length!==i.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),c=0;c=4;)t=1540483477*(65535&(t=255&e.charCodeAt(o)|(255&e.charCodeAt(++o))<<8|(255&e.charCodeAt(++o))<<16|(255&e.charCodeAt(++o))<<24))+((1540483477*(t>>>16)&65535)<<16),r=1540483477*(65535&r)+((1540483477*(r>>>16)&65535)<<16)^(t=1540483477*(65535&(t^=t>>>24))+((1540483477*(t>>>16)&65535)<<16)),n-=4,++o;switch(n){case 3:r^=(255&e.charCodeAt(o+2))<<16;case 2:r^=(255&e.charCodeAt(o+1))<<8;case 1:r=1540483477*(65535&(r^=255&e.charCodeAt(o)))+((1540483477*(r>>>16)&65535)<<16)}return r=1540483477*(65535&(r^=r>>>13))+((1540483477*(r>>>16)&65535)<<16),((r^=r>>>15)>>>0).toString(36)};var i=function(e){function t(e,t,r){var o=t.trim().split(h);t=o;var a=o.length,i=e.length;switch(i){case 0:case 1:var l=0;for(e=0===i?\"\":e[0]+\" \";lr&&(r=(t=t.trim()).charCodeAt(0)),r){case 38:return t.replace(v,\"$1\"+e.trim());case 58:return e.trim()+t.replace(v,\"$1\"+e.trim());default:if(0<1*n&&0c.charCodeAt(8))break;case 115:i=i.replace(c,\"-webkit-\"+c)+\";\"+i;break;case 207:case 102:i=i.replace(c,\"-webkit-\"+(102l.charCodeAt(0)&&(l=l.trim()),l=[l],0d)&&(L=(B=B.replace(\" \",\":\")).length),01?o-1:0),i=1;iI.length&&I.push(e)}function D(e,t,n){return null==e?0:function e(t,n,r,o){var l=typeof t;\"undefined\"!==l&&\"boolean\"!==l||(t=null);var c=!1;if(null===t)c=!0;else switch(l){case\"string\":case\"number\":c=!0;break;case\"object\":switch(t.$$typeof){case a:case i:c=!0}}if(c)return r(o,t,\"\"===n?\".\"+z(t,0):n),1;if(c=0,n=\"\"===n?\".\":n+\":\",Array.isArray(t))for(var u=0;u