From c952932f1b78b8d308c17fc17029f9faacd41712 Mon Sep 17 00:00:00 2001 From: Carlisia Campos Date: Tue, 1 Sep 2020 14:15:23 -0700 Subject: [PATCH] Migrate ServerStatusRequest controller and resource to kubebuilder (#2838) * Convert ServerStatusRequest controller to controller-runtime Signed-off-by: Carlisia * Add select stm Signed-off-by: Carlisia * Fixed status patch bug Signed-off-by: Carlisia * Add mgr start Signed-off-by: Carlisia * Trying to sync Signed-off-by: Carlisia * Clean async now Signed-off-by: Carlisia * Clean up + move context out Signed-off-by: Carlisia * Bug: not closing the channel Signed-off-by: Carlisia * Clean up some tests Signed-off-by: Carlisia * Much better way to fetch an update using a backoff loop Signed-off-by: Carlisia * Even better way to retry: use apimachinery lib Signed-off-by: Carlisia * Refactor controller + add test Signed-off-by: Carlisia * partially fix unit tests Signed-off-by: Ashish Amarnath * Fix and add tests Signed-off-by: Carlisia * Add changelog Signed-off-by: Carlisia * Add ability to disable the controller + cleanups Signed-off-by: Carlisia * Fix bug w/ disabling controllers + fix test + clean up Signed-off-by: Carlisia * Move role.yaml to the correct folder Signed-off-by: Carlisia * Add sample serverstatusrequest.yaml Signed-off-by: Carlisia * Add requeue + better formatting Signed-off-by: Carlisia * Increase # of max concurrent reconciles Signed-off-by: Carlisia Co-authored-by: Ashish Amarnath --- changelogs/unreleased/2838-carlisia | 1 + .../bases/velero.io_serverstatusrequests.yaml | 2 + config/crd/crds/crds.go | 2 +- config/rbac/role.yaml | 20 ++ .../velero_v1_serverstatusrequest.yaml | 25 ++ go.mod | 4 +- go.sum | 94 ++++++ internal/velero/serverstatusrequest.go | 73 +++++ .../velero/serverstatusrequest_test.go | 98 +++---- ...uest.go => server_status_request_types.go} | 13 +- pkg/builder/server_status_request_builder.go | 7 +- pkg/cmd/cli/plugin/get.go | 24 +- pkg/cmd/cli/serverstatus/server_status.go | 83 ++---- pkg/cmd/cli/version/version.go | 37 +-- pkg/cmd/cli/version/version_test.go | 32 ++- pkg/cmd/server/server.go | 85 +++--- .../server_status_request_controller.go | 159 ++++++----- .../server_status_request_controller_test.go | 270 ++++++++++++++++++ pkg/serverstatusrequest/process.go | 114 -------- 19 files changed, 760 insertions(+), 383 deletions(-) create mode 100644 changelogs/unreleased/2838-carlisia create mode 100644 config/samples/velero_v1_serverstatusrequest.yaml create mode 100644 internal/velero/serverstatusrequest.go rename pkg/serverstatusrequest/process_test.go => internal/velero/serverstatusrequest_test.go (65%) rename pkg/apis/velero/v1/{server_status_request.go => server_status_request_types.go} (79%) create mode 100644 pkg/controller/server_status_request_controller_test.go delete mode 100644 pkg/serverstatusrequest/process.go diff --git a/changelogs/unreleased/2838-carlisia b/changelogs/unreleased/2838-carlisia new file mode 100644 index 000000000..11afb4e4e --- /dev/null +++ b/changelogs/unreleased/2838-carlisia @@ -0,0 +1 @@ +Convert ServerStatusRequest controller to kubebuilder \ No newline at end of file diff --git a/config/crd/bases/velero.io_serverstatusrequests.yaml b/config/crd/bases/velero.io_serverstatusrequests.yaml index b3096ffb2..2c66b208f 100644 --- a/config/crd/bases/velero.io_serverstatusrequests.yaml +++ b/config/crd/bases/velero.io_serverstatusrequests.yaml @@ -16,6 +16,8 @@ spec: singular: serverstatusrequest preserveUnknownFields: false scope: Namespaced + subresources: + status: {} validation: openAPIV3Schema: description: ServerStatusRequest is a request to access current status information diff --git a/config/crd/crds/crds.go b/config/crd/crds/crds.go index df4ae587b..d13c7880e 100644 --- a/config/crd/crds/crds.go +++ b/config/crd/crds/crds.go @@ -38,7 +38,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4W\xcdn\xe36\x10\xbe\xfb)\x06\xdb\xc3^*y\x83\xbd\x14\xba\xb5i\x17\b\x9a\x04\vg\x9bK\xd1\x03E\x8d\xeci(\x92\xe5\f\x9d\xbaO_\x90\x92lٖ\xbd\xc1\x02\xab\x1b\x87Ùo\xbe\xf9!\xb5(\x8ab\xa1<=c`r\xb6\x02\xe5\t\xff\x15\xb4i\xc5\xe5\xcbO\\\x92[noj\x14u\xb3x!\xdbTp\x1bY\\\xb7Bv1h\xfc\x15[\xb2$\xe4\xec\xa2CQ\x8d\x12U-\x00\x94\xb5NT\x12sZ\x02hg%8c0\x14k\xb4\xe5K\xac\xb1\x8ed\x1a\f\xd9\xc3\xe8\u007f\xfb\xa1\xfcX~X\x00\xe8\x80\xf9\xf8\x17\xea\x90Eu\xbe\x02\x1b\x8dY\x00X\xd5a\x05\x01YH\a\xf4\x8eI\\ \xe4r\x8b\x06\x83+\xc9-أNn\xd7\xc1E_\xc1a\xa3?=@\xea\xc3YeC\xab\xd1\xd0.o\x19b\xf9}v\xfb\x9eX\xb2\x8a71(3\a$o3\xd9u4*\x9c)$\a> c\xd8\xe2\x1f\xf6źW\xfb\x89\xd04\\A\xab\f\xe3\x02\x80\xb5\xf3X\xc1c\x82\xea\x95\xc6f\x01\xb0U\x86\x9a\xccH\x0f\xdey\xb4?\u007f\xbe{\xfe\xf8\xa47ة^\x98,;\x8fAh\x8c1}\x93\xfc\xeee\x00\r\xb2\x0e\xe4\xb3Ex\x9fL\xf5:Ф\x8c\"\x83l\x10\x86\xbc`\x03\x9c݀kA6\xc4\x100\xc7`\xfb\x1cO\xccBRQ\x16\\\xfd7j)\xe1)\xc5\x19\x18x\xe3\xa2iR\x19l1\b\x04\xd4nm\u9ffde\x06q٥Q\x82\x03\xc5\xe3GV0Xe\x12\t\x11\u007f\x04e\x1b\xe8\xd4\x0e\x02&\x1f\x10\xed\xc4ZV\xe1\x12\x1e\\@ ۺ\n6\"\x9e\xab\xe5rM2V\xb4v]\x17-\xc9n\x99\xeb\x92\xea(.\xf0\xb2\xc1-\x9a%ӺPAoHPK\f\xb8T\x9e\x8a\f\xdc\xe6\x82.\xbb\xe6\x870\x94?\xbf\x9f \x95]J\x1bK \xbbދs\x95]\xe4=\x15\x19\x10\x83\x1a\x8e\xf5\xf8\x0f\xf4&Qbe\xf5\xdb\xd3\x17\x18\x9d\xe6\x14\x1cs\x9e\xd9>\x1c\xe3\x03\xf1\x89(\xb2-\x86>qmp]\xb6\x88\xb6\xf1\x8e\xac\xe4\x856\x84\xf6\x98t\x8euG\x922\xfdOD\x96\x94\x9f\x12ns_C\x8d\x10}\xa3\x04\x9b\x12\xee,ܪ\x0eͭb\xfc\xee\xb4'\x86\xb9H\x94~\x9d\xf8\xe98:V\xec\xd9ڋ\xc7i1\x9b\xa1\xd3\xfe\u007f\xf2\xa8S\xc2\x12k\xe9 \xb5\xa4s\x0f@\xeb\x02\xa83\xfdrbx\xae9\xd3W+\xfd\x12\xfd\x93\xb8\xa0\xd6x\xef\xf4\xa4\xcd/\xa0\xfae\xee\xc4\b+\x8d\xb8\xbeQq^\xf1\xc42\x80l\x94L:T\x14\xd9}\x9b\xcf\xc4q\x91\xf2L\xbbJ\xedj\x95\xd5\xf8)\u05ceջ\xab\xb1<\xcc\x1cH\xa1l\xdc+\xb8V\xd0NM\x8e(k<\v\"D\xfbf\x90\xfdL\xbekRi\xb5\x84\xe1*\xc0Չ\xf2\xc8s\x1b\x8d\x19,\x15\xdau^\t\xd5\x06\xc7Fn]8\x83H\xbd\x8d]\xdf\xd5\xdf\xc6\xef֙\xd8\xe1\xfen\xb8\x8a\xfc\xf9XwZ \xbd`\x00\x91B\x80p|\x05N\xbf\xa1&\x18\xbck\x06\x00C\xd1r\x8a\xf3\x8d\xd8Sr)\xe0\xd14,\xe6\x8b\xffHc\xae\xa2\x8e\x14N\xb3y\xb4y\xc2\xd7W\x87\x81(\x89\xfc\xf6q\x90\xd5Gbu\f\x01\xad\fF\xf2M\xf8M\x03\xc1(\x96I[\xa47\xd0\xd5<ߟ돐\x92)\x90$\x98vѫ\xe2\xb9~i]\xe8\x94T\x90F{\x91\x0e\x9d\xec\xa7\x17\x98\xaa\rV !\x9en^\x9e\bȬ\xd6\xd7#x\xe8u\xfa\xabp8\x00\xaavQ.\x10\x9b/\xc5+\xd4^E\xe47\x8a\xaf\xe3\xf9\x9c4\xe6Ҋou\x8e6v\xa7.\nx\xc4\xd73\xd9\nUs\xdas\x05<:\x99۸\x10\xd3L-\x9f\x88\x0eO\xec\x9b\xc3*\xd7]1<\xa9\xf3\x06@~\x996\x93\x14sߛ\x83\xe4\xd0 Jk\xf4\x82\xcd\xe3\xe9\x93\xfaݻ\xa3\x17r^jg\x1b\xea\xff\a\xe0Ͽ\x16\xbdUl\x9eG\x1cI\xf8\u007f\x00\x00\x00\xff\xfflC\xbf\xee\x8e\f\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec}mo\xe46\x92\xf0\xf7\xfc\n\xc2\x1b\xc0\xf6\xad\xbb=\xb3{\xb7\xb8\x1b\x1c\x10xg\x01M\xd7\xfe\x14P\xad\x8d\x19\x88;.\x88,y\x93\x8b=2\xfd\xf7\xb7\xa1\xdc\xf7\x1f\xcb\xdaA\xe5\xa2\xf7\xb3[\x19]^i\xf4\x89U\xc0\xb5\\c\xcaO\xbf\xe9\xdaa\f\xbfT$\xb7FE\xc8\xe9\x02\x0e\x0f\x15y\xfb\xe1\x9d\xd7\x17\f\xfb\xef\xcd\xdd\xed`6\xc6XH\xb1b\xa9Qe>S\xc9\xe8,3\x06\xe6\x1c$\xf0\x04\x14\xf9\xfa\xe8\xf3٧\x9f.\xcf>\x9c\x1f\a\x806F)\xdc\x17\x94\x1b\x8a+\x95\x97\xc6\xd5~\x9b\xc9\x03_1)\xb8AM\b\x1e.愒\x95\x9fiR\xe5A\x19\xc3&[Az\xe2\xe2#n\x05!\xf8\xb0l\x92\xf1\xa2\xd4ޓxDz\f\xb3\xacx\xb2\xa4|a\xb0t\xb3\f\x01\xda\xc0\x1fQk\xae齙3\xaa\x90*\xa1\x05\xa4H\xbf\x84\x06\x80LEi\x96\xfe\xf5\xd7'\x84\xc1\x1b\xf2u\xe3\x13Sr\xee\xa0\xd6[\x18\x00\x19W\xcba\x05\xd2\xea\xb8v\x03O\x88\x84\x05\x95i\x06J\x19\x0et\xb7\x04\xbd\x84~NK;\xac\xeb\xc3m\x19x\xaf\xa7\xa1\xbe\xaeL\xb6\x00\xc0\x1dYn\xb7UJ攉\xd3T$\xeaTSu\xabN\x197\"e\x92RM'\r&tj%\xc2\xc4I\xa7\x89\xb7\xf1&\x15\xb1\x9e\xfeN\x96\x9c3\xbe\x98\xd0\xea)\xc6't\xa2\x96\x90e\x87\xbd\xa7\x1b\xc0:\x1d\xda¬\xb1\xe6K\xfd]\xd5A\x86\xb2\x1dm\xfev^\xb13\xfb\xd5)\xb9\x14zw&\xd1\xeeQ1r\xc4봓\xe3\x9d_\xde|\xfa\xfb\xd5Nj˛0F\xd7d\x91\xbb\x19_\x00\xccn\x16\xd9\xc1\xf8\x02\x8f\xc9N\x16\xd9f|\x01P\x1fd\x91\x8e\xf1\x05q\xca\aYd\xa4\xe0\xd8\xc7\"\x1b\x8c/d\xae=X$\xae!\x00\xe6\xc8\"\u007fc,\x12\xf8*\x92=~\xe7\xd4\xf6\xc6Q\xae\xf69D4k\x811^\xc6\xdb\\b\x10q\x04c\xbb\xed\x14\xe2\xabϴ\x1d\xc2\xe6\xcde\x06\xc0%5\xe9\xfbLU\x14\x04\x95\x05\x14B\xf0\xe1ڽ\x1d\xfb#\x1b\xddc;\xde\xe1r\xc0c\xf1@\x1a\xb8\x98\x92\x0f.\xa6K\xc9۟.ޝ_\xde\\\xbc\xbf8\xff\x14\x82\f\x12{F\x88\x0f\xcd\x0fB\xc9\xe1\xe3\x99\x14v\xec0,\n\t+&\xca*=7\x18n\xe7\xf1\xdc:m\xe1\xd3\xc5\xc0\xc1\x9a(\x90+\x96@\xf7gB\xf7\xb3\x87\r\x14\f\xb1K!h\x89\xf9`\x88\x8f\xaa\x16\xd8\xd1C9\b\x86\xf9\x04V\x94\x1d\x0f\xdbR\xc1 k\xc5b\x87\xba\x10\f\x11Ջw0\xa7ef\xfd\x13\a\a\xd3\xfe\xd2ڎa\xec\xe5\xbd\x14\xbd\x1c\xc8\xcd\xd1b1\u05f6x\xc3\xfbN\x1f\x83\xf1\x1e\xba\xf4\xba\x96p\xb5\x06D\x04̬\x04oq\x04\xe4\xe6\xd4#V\x9e\x11\x1bF\x9b\xb3\xc5\aZ\xfc\x15֟`\x1e\x0e`\x13٘y\xe7\x92հ\xc00\x02\"1r\xddN+\x9c\xf5\r\xc3\a韏\xd85Z\xb8\xb8qY\x93\xa8\x99\x19\xb4\xc4,\x86\f9@~\xc4h.~\xb4\xc5uS\x85q\xbc/zY}M\x8fD\xf0\x04\n\xadN\xc5\xcaHI\xb8;\xbd\x13\xf2\xd6\xd8\x12\x86\xb3Ol$@\x9db\x1a\xfe\xe9\xef\xf0\u007f\xa2gt\xf3\xf1\xdd\xc77\xe4,M\x89@6Z*\x98\x97\x99M\xf1\x89\x90\xc3~ԅ\xbd'XfzBJ\x96~\x13\xcaH\xfd\x18L\x0f\xa2\xb0y^\x8fB\x13\xd7\x18\x9d\\G\x98\xb4\xedaH\xaa:\xf7ƴeZ\xe1\xf9\xc9K\x15Ϊ\xfd\x98A\xb4\xca禅Ȟ\t\x91\x01\xe5\x110\xfa\x86\xbf\xbaF\x9f\xb4®\xd1;D\xd65\x90\xd6\x1fC\x16\x1c\xd6\xc2\xc0\xa6ȉp\xe9H\xeaT\x887D\x95E!\xa4VU\xc1\xf0\xd4\x1c\xf6p]\x964j\x8e\xa7U\xf5\xceI\xfd\x1b\xa6\x94\xef\xac\xd9\xeb\t\xb8\xd1\xc3\xe1\x04C\xf8S.R\xb8\x8c\x9e1\x82pv\xc2Y\x82A|\x04F\x94\xa6\xbaTӥP\xfa\xe2*\x12\xb6\x05Q\x88\xf4\xe2\xea\xa4\xf5\x97\nV\xf7\xc8#\x88\xe0\xeeF\b!\xa3E\x89\xbea\x82\x15\\Ѽ\xc4uV0\xf4\x88-*\xae\xa8^\x1a\xcd\xedN2\xad!\x869\xd8a\xac)\x90\xb9\"b~b\xb8U\xadl\xaf^\x1f|1\xa5a\xee\x97\xf8([\x80\xb8r\x8a\x03B\x8e\x97\x13^\x9d\xf2Vh\x95Y\x15\r\xf2\xec\xea\xc27\xd0\xf8B\xe8\x1e&%\xaa\xadznY\xe1\x93E\xdf?\x81\xcc\xf0\xb0\xe34\x9cy\xdb1\xf3\xc6fI\xf7\xa9\x8a\xdb=2\x86}6(O\xeb^\x1bG\xf6\xc7iR\x94q\xac\u05fd\x9fC.\xe4\xfa\xc4\xff\t\xc5\x12r\x904\x9b(-$]D\xca\f?M\x9c^\xfd\x97\xfdX\x1cgn,~{\x96\xe1.\x1b\xe2|vI)\x8d-\x91\xad\xbd\x94\x87\xf4\x8bH\x9e\x8ab\xbaZ}\xf4\x1dm\x92\xae\x13N\x87\xd8a5\x8f@W\xc6Jde\x0e\xea\xa4\xd2\xe5\xa3\xc1\x1ah\xc0WdE\xa5\xfab\x16I\xcaVL\xf5K\x91\xec\x1a\x94\xaf?F1\x1f\x82\xfc\xd3N\x9fq\r\x8bh\x03f2\x1c\t\x9d\x86\x95/\xad\x16\xa5.\xcax;h.dNu\x15}\xb8/\x84B\xf7\xa5o?\x11\r\xb8\xa5\xaf\xbc>\x88\x84SP\xadA\xf27俎\xfe\xf1\xfb\x9f'\xc7\xdf\x1c\x1d\xfd\xf0j\xf2\x1f?\xfe\xfe\xe8\x1fS\xfc\x8f\u007f9\xfe\xe6\xf8g\xff\xc7\uf3cf\x8f\x8e~\xf8\xeb\x87oo\xae\xce\u007fd\xc7?\xff\xc0\xcb\xfc\xd6\xfe\xf5\xf3\xd1\x0fp\xfecO \xc7\xc7\xdf|\x1d9\xe1\xfbI\xed\xa9\x980\xae'BN\xec\xd6?P\x14\xbdo\xf8\xedx\x1c\xbe\xf3\xc9\xeb\x14\xc3D)i\xea\\_\x88A\fS\x8f\x06,\u007f\x90v\xa4 \x91\xa0_\x96g\xd5ΩQ\xe9p\xa8\xea\x06\x16\xbf\x02g\xebP\x13Ϣ\xa7\xb61\xb0\x05\x17\xc1@\xeb\x10\x1f\x14\xb5\r\v=\xfc[\b\xf6\xf2\xfb1:\x83Ggps\xfcz\x9d\xc1\xd7\xf6\xac\x8c\x9e\xe0/\xe3\t\x8e|5f\x95\x13dJ!\xc9N1s\x8b\xca\xea\n\v?wfv\xd5-\x91H!\x8a2\xa3:6\n\xbd;\xf1d\xea\x05`L\x86K\x9dWkC\xe5\xf9ଢ\xb3,#\x8c[\x91\x87\x93\xf2\xc9\x1e\x12\xacmO\xa8\"A\x87\bV\xc0\xb5a+|\xb3fS\x11\xa5\xa9Ԍ/\xa6\xe4\xfbe\x90\x1b\xd6\xeaR.;\x82q\x92\x97\x99fE\x06\xa4j\xcaW\xd5\xe4\x87@UJ$\x8cj\x9fzb\x9b\xd4(\xedы\xb8\xd0\xf46\x04f!!\x81\x14x\x02ػ\xa5l4\x1a\x9c\xad\t\xe5䜯\xf0kA\xabOK\x9b\xc2iU\xa7j^\xad\xaf\xd9\f\x87\x00\xb0_$\xd1\xd0\x1cS\x97\xe8\xd1\xee\xe1\x1c\xc4\xf4\xdc\x06\x19\xe5\xda7̩\"\x92!jD\xacR\\ecD\x18\f[\xdap\x1dK\xad\xb4\xd9\xf0X\xa0\x14\xf93f\xa3Ī\xa6O\xa5\x96\xbe,\x95\xf4\t\xd4\xd1\xc7SE\a\xa9\xa1CT\xd0}\xeag\xb4)X\x9f\x1d/\v\xe3U\xc7!jc\xb4\xfaVH\x98\xb3\xfbA<\xe4\x8cW\xfbBX\n\\\xb39\x8b\xd0\xe8\x8d\xd6#\xa1\x00\x8e\x95\xa5@\x93\xa5m\xde\xc6\xdb\t\x1f\xe1\xf4\xfb\x85s\x9f\xad%\xff\x18\x8c\xfa\xba\xcb\xe70rݑ\xeb><~]\\\xd7\x1d\x84_$\xcb}&\x8b\x14\xeb\x1cc\v1\xdf5j%\xf1\xd47o\x81\bXk\x9fSY7 8\xc5\xef\x85\x1c>l;軪\xd5Bȶ\x00\x16wd\xc9\x16\x86\xcc2XAH\xd8\xd3j\xd7$\xa7\x9c.lc7-|\xf8\x8a\bI\f#\x91,\r*\x9d\xac\xcdP\\\xa4\x11k\x86\re\x82\xa6\x8d;{B\x16\x9f\xb1[ \xef\xa0\xc8\xc4\xda\xf5o\xe3)\xb9\xd6T\x1b\xb6s\r:$!+\x82=\xe0:\xae\xca,\xbb\x12\x19K\x02|\xf3mR\xbb@\x1a+\xca,#\x05\x02\x9a\x92\x8f\x1c\xe5\xc3YvG\xd7A\xf1\xc6KX\x818\xbcp̵;\v\x97\xffK\xca\xd3\f$v\xe0r^\xb7\x16t\r2g\x9c\x86\xb5\v U\xba\x12:\b!%4I\x84L]\xd7#\xdf׆\xcaP\xbfH\xc5\xd1P\xdbi\xd0\xebf\xd6Y \xdcY&\x92[EJ\xaeYV7:\xf3]\xce\xdcUY\x810\xfb\xeb\xd1\r6R\xfd\xe7\xa4:+\x13\xbcK\xe6\xf4w\xf5?\xe1\x0faJk\xbc\x95ҧ\x93\xe4\xf6\xd8\xe8\xa6\x06H\x0e\x98\b(8ć\x8a\xe7¨!\x86\x8c\xea~\u007f\x95\x00\x99b3\xbc\b\xa8\xed\x9b\x14(\xb2E\xec\bDo{5^j\x8faq\xf9\xe0\x8e\x1f\xcdѣYfd\x04.c\x1c\x9a]3\x19\xf6\xf2k\x9f\xb9\xd8L&\x03\xc4Y\x90$e\x12\xfbǯ}\xd5`$L\xdf\x16\x12\xbbg\v\xa1\xc9\xd1\xe1\xe9\xe1qx;\x8d6L\xdf\xff\xc3\xe8\xc8\x19X\x19\x19\xdau\xa8k\x96F\rby\x91\xad\x11\xbf\x87\xe9\ta\xb1\xd1VW\xce(K\xee\xf7\xc85m9!\xaa_Ǻ\xed\xa1%\xf5\xfd\xa9-,\x03Z\xcb\xd2\xea\x0f\x91@\x8f\x0e\u007f>ۤ\x93\b\x98,/ܝe\x94H\xa0\x19S\x9a%\xf8\xa5\x98\xa0\x97\x1ff\x96\xe1\xd9)/\xc2\xca?\xfc\xe8\x93\\j\x83?\xfe\xd8:\x86\xd0e\xf0ǚ)\xd6M\x10W\xfc3j\x15\x8f\xa4U8mB\xfa[\xe8F\xad\"f\xbcD\xad\xe2\x97#\xf1\"_,$\\kQ\f\xca\x0e\xb0 \x1e%7\xc0\xdf/\xb4+|O\xd2\xe0M\xb4wq\x9e]]T\xbeg\xd1\n\xbacjF LU&K\x1f\xe7\xe0\xa0\xd4)\xa6\x01\x94\x85\xf59\xf9\x8b\xc0BC\x89\x85\x04\xbcUI\xf0\x93\xaa\xe6\x1c\x11\x01\xdc\xfe\b:\t=\x17\xe8\x17q\xd9\x11.\xaa\xe67iX\xb2A\"\xa9Z\x02\xf6\x90\x87{V_zN\x95\xe06\xec\xe96\x8d\x05\x9b\xceL\x91\x82*e\x03_\xba^\x80\xfdĕH\x0f\x0fCU\xb0\xc6d\xc8B\xd2\x04H\x01\x92\x89\x94`\x1f\xb4T\xdcq2\x83\xc5\xc3w\xa5n\x0eG\xaff\x92\xfe\x18\x18m\a0\x1aZ\xdd\xe1\x17\b\xf4S\xabտkޑ\x88:?\xda\xe1#\x94\xbe\xdai1X\xae\x85\xc4_\xd2,[ׇ,\x10\xaa\xab\xfe\xd3\xd5\xd6l#;\xf4\x1c\xe0\xd6<{~\x8c!e\xfc\xb7\b\xb4\xee\xa4/\xbc\xf7\x9a&\xcbp*\bLc\x1f\xd3o\xfa\x8e1\xfdf\xef\x18\xd3o\xfc\x18\xd3o\xc6\xf4\x9b1\xfdfL\xbf\x19\xd3oZ\xe3E8\xe6\xc6\xf4\x9b1\xfdfs\x8c\xe97\xc1cL\xbf\xd9=\xc6\xf4\x9b\xbdcL\xbf\xd93\xc6\xf4\x9b\xf01\xa6\xdfl\x8d_[\xa0lL\xbf\xf9\xb5\x06\xca\xc6\xf4\x9b~/\x8f\xe97\x0f\x8e1\xfdfL\xbf\x19\xd3oz|{\xd4*\xc6\xf4\x9b_\xb7V\xf1ˑx\x03\xfa7\x05\xbd\xe43N\xae\xa4\x98E7r\xba\xc2\xd84K\\\xba\x8a\x98G\x85\xd4\xfdT\xa6\xf55\xea\x8d>\xbd\xbegFЕ\xb6\xf6\xaam\x9fB\xd3\xd9/%\xb4\x89E\xff\b\xbao\xbc\xa4N\va\xff_\x1d?o\x04έ_\xab?ˏ\x13\xa4\xe1\x11\xf3>\xd1\xf2:\xf6\x1d\x9a\xf0\xb4+R\x1e\xad\x95\r\x8d\x92\xc7\xeb'\xd1\xd1\U0006724c?UT|oD\xbc\x19ێ\x80\xbd\x15\r\xdf\x15\u05ceQ\xac\x1b\xb3{\xa4\x98\xf6\xdexv32\x1dc\xf6nŲ\xb7\xa2\xd2\x11P\x9bq\xecΈt\x04\xcc:\x86\xbd+\x1a\x1d\x01\xf4\xfc\x9e駋D?b\x14::\x003HY\x8d\xf5\xa5F\xea!.\xf1\xf4f)A-E\x16\xc8\xe3Z\xfc\xed\x03\xe3,/ss\xb0\x95aLlU嵆r\f\xcfs\xacd\xb7!&\x03\x96\xa5\x80\xd7\xd1Q\x96\x857\xe6\xc2&bK\x8a\x96\xbc*\x93\x04 52\xa9\xd1\xd7/\x10\xe2\x1f\xa7՚\xab;\xf5_\x87љ\xbd$\r\xad\xa3?\xfe!b\xbfí\xaa\xa8\x14\x83\x87\xd3\v\x10n \xfe\x86\xa6\x16\xc4\v\xf48g\xc3S\xa4\x13\xecI% \u007f\x17e\x8c\x95\xbf;\x8d`#! F.Ʀ\x10\f\xe0\x89\x83R\a\xf6\xa7\r\x18\xdcDaag\xca@\x15\xfc\x8fq\x81Ŧ\vDK\xaa\xa7I\x13\u061d\"@X\x9c\xafaXz\xc0\xd0ԀG\xbb\xbf\xac\x8ey\x0f\xbc\x91z\x88Ws\xa8'mP\x1a\xc0Ӡcx\xf0\xfb\v\xdd\x13\x19\xb9\x8f\xf1\xe1\xfeA\xa1\xfe\xf80\u007f\\\x88\u007f\u007fx?\xd2\t?(\xb4?\x80X\xe2\x9c\uf44e\xf7\xa1N\xf7\x81\x0e\xf7\xfd!\xfcȍ{\x02G\xfb\x1e';\xba\xcb#@v;؇\xba\xca\x1f\xd9M\x1e\x1bx\xdf\x1fto\x84ϣ\x14ᎀ{|\xe8<\x9a~\xe3\x18zD\xf0 \x92\x153\xce4\xa3\xd9;\xc8\xe8\xfa\x1a\x12\xc1\xd3@\xadf\xe3\x12\x95\xeaT*\v\xcc\xda\xc9\x11\xaeٺNpI\xdd\ry\x90\xfarG\xef\xf9\x0fe\x9a\xa8\xf2\xe1u\xfdv\xdd\x1b}\xed\xbf\xa4\x97\x9e|\x11\xf3\xdd\x16\t\x0e\xdf\xf8\xbf\x88;\"\xe6\x1a89b\xdc\xef\xfdq8\xcfs\x86{\xed\xad\xa9\x0e\xaf9\xbb\xaf_y\xd0\xc1\xb5\x8c\xbf8\xc7\n\xba\x94\x94z*O\x9a\x03\xffخ4\av^\x86z\xb2[\xee4\xeb\x90k\xf3\xed\xc0\r\xab\xaf\xd7z\x8ds\xf6\x1c\x03=\xba\xaeX\xfe\xd7OD\x91IP\x0f&@\xd5\xe9L\x81(\xecL~j\xa72\x05B\xecH|\xeaNc\n\x84\xdbJz\x8aHa\xfa\xa2\xde\xc4GJ[ڟ\xb2D\n\x11ccG\xa5+\x8d\x96R\xaf\xb1?-i\xb4\x94\xbe\xac\xa5\xf4\xd2m\x01\xcdr\x10\xa5~1f\xc0ݒ%˦\xb6\xc1rPD\x94\xf1)\xd4F\x8fpS\xea\f\xb6=\xed\x055\xbf\"\xcb!\x82\xc2\xc2\xdc\xde\x1d>\x9f\x8d\xde+u\"P\xc0z\xa9\"\x94\xbc\xbb\xbc\xfe黳?\x9f\u007f7%\xe74Y6[=qB\x03\xc5\x1a\xf2\x9a%]\x01\xa1\xa4\xe4쟥\xbd\x99\x90\x1cU_9~\xa6;\xc8#$\x87\xe1,\x01\a\xbd\xb5)\xdf1\x85\rq\x10\x86kQ \x14\x84^\xfeږ%\xe4\xdc\x00\xb1\xfa!ʝ%H \v\xb6\n2T\fL\x9b\xffChZ5}0\a՜\x12&8\xa13Q\x06\xb1\xc6%\x10\x0eڜ\xe0\xca/%\xb8j\xf5\t+\x15\x04]\v8+\xf1:\xb3B\xb2\x9cJ\x96\xad\x9b\x13\xa4ٔ\\\n\xafq\xaf\xc3t\x81&\xea\xde}<\xbf&\x97\x1foH!\xb1ՒͶ\xc1\u007f\x0fܨ\x19\x98m\xb1\x9b\x9cN\xc9\x19_[0\x96K3E\x8c\x9a\r\xfe\xe6\xeb\xc0\x89>\xaa\xc4j\x1f\xc0\xef\x90V\xeah\x1e\xb2\xe6\x9c\xde\x1b.\x1a\xba\xfd\xb9(\xb9\xb6i\xa1\xf6TW\xc4o#\x9f\xcfq\xe1\xffS\x9dD\x12/\x82]\fx<\x90\x0f\x8e\xf1@\x92\xc3O\x8eZ6\x8f\xa4Ul\x1e\xf1HzA\x1bz&/椚#SD\xe4L\x1b+}.d\xb3\xd254\xb9\x94\xe9\x96)\xea\xd8\x12foS,J\x8e\xben\xbeQG$\xf4\x12\xe4\x1dS\xe8䢼\xf6) Ø\xa40g<8-\x03U\xcd`\x8f\xf3KdU\x11/)HJ\xc9\xf4\xfa\xad\xe0\x1a\xee\x03l\xf26\xd1_;0D\x146\xdb\xd5\xe78\xd9\x14\xf1\x10f[r\xac\xea\nސBd,Y\x9f\xfa\x05!\xe6\xe1^\x9f\x06|\xbb\xdf\x175U\xb7\xf5\xfe\xc3Ę\f\xf56o}\xff\xa9\x95E\x94\xccW\x92\xadX\x06\v8W\t͐&\x87\x98\x8ag;`\x06\x9e,\x83\x02)2E\xee\x96`N.\xa1f\x8d\xe8\xb0H('\v\x1a\x9c*\x94\x9b\x1d*\xfc\xc4\f\x99\x19.\xa0\x15)\xa8\x04\xae=\xf8P\x96\x88E\xd93!2\x97\x13\x9f\xad빻\x02\x14.~\xe2p\xf7\x93\xf9v\xb0{>\xa3\x8b\xaa0F\x81\xde\xf2\xd6\xc4N{\xd76\xd9t\xeb\x12\b\xcd\xee\xe8:t\xbawK\u061c\x1fSo\xc8\xebc<\x9bT\x91ꋡ\x9c\xf6\x0f\xc7\x187|{v\xf5\xd3\xf5߯\u007f:{\xf7\xe1\xe22\x86-\x9a\x9d\x82\xa0K\xe1\x12Z\xd0\x19\xcbX\xb8\x12\xb6\x95\xcd\xd4\x04\x85b(MOS)B\x13c\x11˲\xe4\x9c\xf1E\xa3\xbexH\xaer\xb3\xed\x05\x92ټ=م\xa4<Y\xec\x99\xeb\x18\b1\af\xe0\xae~\xb2\x15\x86\xe3\xbev\x8e_R}J%χ\xc4\xd3?\x95\xbc\xddu\xab\x88\x95R\xb9HaJ\xae\xacH\x06Ն\x15\xdf\n\x82J \x06 \u05ccfٚ\x18\xebmE3\xb0\t\xfcX;\x17\xac`ugS\xcdi\xa6\x02\xd9s\xac\\5\x8a\xcb\ac\xa2\x0eع\n\x06I\x81\v\xed\xec\xe5\b\xba\x17s\x84E\xac\xcd\xdcHZkɯ\b\xe5\xb0\x16\xabLyL_U\xb3ƈH \xccR\x81\xea\x16\xab\x95\x15\x1d\x91\x03\"\x81\xa6X\xdb[P\xbd\xb4Y\x159U\xb7\x90\xda\x1f\xa2\xb4b\xe7e\xb0\xb3\xad\x16}\xb3.\x80́\xea284\x83ڰ\xcdQ\x01NgY\xa8\x03#\xba}\x02M?\xf2l\xfdI\b\xfd\xbe*E\x1d@\xb6\xdf;\x9b\xa6\x1d\xb90\nn(c\xc0\xb9Mp\xe3\x90\r4*e=\xb5\x85:c\xd4s2\x01Y\xf23\xf5\xad\x14e\xa0H\xdfR\xad\xbf\xbdx\x87\xbc\xb0\xb4\xf6\ap-\xd7\xd8\x06 \x9c\x11t\xdbW\xe4o\xe6ܹ\x93\x16\xaa\xb2x\x160'%W\xa0\xa7\xe4\x03]\x13\x9a)\xe1ͺ`k\xf6\n\xb3\xfc\x9a\xfe\x97)\xba\xe7,02\x13:\x94\xafl\x80C\x16\xb0\xfd\x95PߞA\xa6\r\xc8V\xbe83\xbf\r\xa8\xa1@\xe9-(RHH \x05\x9e\x04\xd2j#\xb6\xfa\xa7\u007f}\x96\xb4-\xa4\xf2K\xc1\r\x03\x19@\xe7\x17\xe2S\xe4\xf8\xa1\xf0\xc7cU\x03\x1dt\xac\xe2\xdd\xd7\x19\xac \xb8\xfd\xe1f_t\x03\xc3\x18u\x9eN\x10h\x84W0\xa33Ȭ\xf2eO\x89\xda>%\x91\xde\xc2(W\xa3\x14\xd9\xd0\x12\xc5O\"\xc3\x8dD$O!\x15ɳ\xebt1\xb9\xc0\xb6\x02\u007fP\x8b\xf1\xeb\x06\f\xc2Z\xb1\x8e\x805;}\xccv\x19\xa9\xba\x17\xe0}V\xd8\x19\x85\xfd\x8fU\xb1B\xdcTu\x169\x176\x91\xbc\xd9z\xc4\xf5Y\x0e!\x96\x92k\x96\xf9\xf0o^dFr\xb7fk\x830aב4\xfa\x9c\x9fTh\xa8\x9b\xaa\xbb\x96+!\n\xef\u007f\x97J\x13Z\xe5\xb1\xfa\x9e\vWՇ\f*o\xc2f\xe9n\xa3\xc0v\u007fZ\x98I\xafX\n$e\xf39\xf8<\xdc\x19\x90\x82J\x9a\x83\x0e˕qA\xb1\x19,\x98M\x8e\x14sB\r\x1a\x0e\x0fU]\xfc\x1f\x82\x01L\xb5d\x9a\xe4l\xb1\xb4\a\x99P\x92\t\xbe >*\x95\t\x9a\x12\xc3C\x03\xa0\nI\xee\xa8\xcc\t%\tM\x96pbs\x91\xd3Rb\xefY\r4]O\x94\x0es\n\x1a\xd5\x19\xe3C\ue7a8d\xbb\n2p\xa7\xd0\u009d\x81\xa6>[\xc3']x\xad\xady`\x03\xe0zh\xf3\x8c.^J\xb7\x9e\xb1\xa7~\xe7\x18{\xea\xbb1\xf6\xd4o\x8f\xb1\xa7\xfe\xd8Sߏ\xb1\xa7\xfe\xd8S\xbf{\x8c=\xf5q\x8c=\xf5Ǟ\xfacO\xfd\xb1\xa7>\x8e\xb1\xa7~\x9f1\xf6\xd4o\x8e\xb1\xa7~s\x8c=\xf5\xfb\x8c\xb1\xa7\xfeo\xb8S\xe4\xd8S\xffeu\x8a\x1c{\xea\xef\x1b/\xbd\x8f\xe6\xd8S\xff\x85x\xe9\xc9\xd8S\u007f\xec\xa9\xdf\x18cO\xfd\xb1\xa7~5ƞ\xfa;\xc7\xd8Sߎ\xb1\xa7\xfe\x8e\xf1۵\x94ƞ\xfa/\xcbRz\xe9\xb6\xc0\xd8S\u007f\xec\xa9\x1f\xf4V`\x1ae\xca\x02\xbao\xf6i*\x13\xdcE\xd5\x17\xa4\x12Jf\xe5|\x0e\x12uC\x9c\xd9V\x1eI\x00X\xdf\xfa\xcf'6\xfa|\x0f\x05\xfa\x04\xbb\xd8\xd8z\x9a\x10\xed\xbfsJ\xbe\xaa\xf6\x8e\xae\x15\x91\xa0\xc2:\xe00N\xce?\xbe\xaf\r\xaa\xf0n81\xed\x00p%\x1fy\x12\x9b:[o}G\x99q\bFm\x02Y\x92\tes\x9b,\x8a\x93%\xe5\x1c2g\u007f\x04%\xf7,\xa9\"3\x00ND\x01\xdcf\x0eR\xa2\x18_d@\xa8\xd64YN\xcd\xecCTd\xb7\xed\xaeMi=K\xa5%\xd0\xdcn\xbf\x84<\xacA\xac\x99\x1e\xa1\x89\x14J\x91\xbc\xcc4+\xaa\t\x12\x05X\xb2\xa3B\xb3\x86\xfd\xa6b\x82\x14\xd84\x1eY\xc2I\xbd\x02\x8b\x94\x90i6\x1bա\x85v\x82\xfd\xb1\xf3B\xaf\xab\xa4b s&U\xc8.%\x19CC\x00\xd7k\x8b\x10q\x8e'h\tjl7\x8a\x18\r\x91%\x16\xa5\x96C\x8dQ$\xdd\x14?\x1b>c\xf7rc\x8a\x8d.\xb6u\x06u\x88\x86\xe4\x99\x1dv.\xf3\xcc\xe4\xa4\xd9,ݗy\x04y\x190\x1d\xacf\x9an\xfdH\xfa\x1cV\xe6\xecC\x02l\x15r\xf6\xe9\x0e\xce\xf7\xa4\x8cO\x83\xcc\x19Ǵ\xe5\x0f\xa0\x14]\xc0UP\xd8j\x97A\x87\x91\xab\x9aD\x82T\xfa9\xcb\xd0iSkVu\xda\xe4\xa1jN9\x00hnWW\xa5\xe3\xdfI\xa65 \xc9b\xcbA\x8c\xd3\a\xe9\xf4[\x13k\xb6~\xfb\xe0?g?\x13\"\x00\x15\xea9<\xb5\xe9\xf93 3\xc9`N\xe6\x8c\xd3\xcc\xe5\x10\x9e`K\xa2\x10ڲ\xce\x10\xa5\x8c\xb1/\xb8OQ\xf3X\x99\x92\xef-ZB\x96/K\x9e`\x02\xa3KF\xe7\"\x05\xc2\xe6d\x81y\x8dҦ\xd4\xff\xeb\xab\xff\xf8S\x00\xd0\xd9\xda\xe8\xa4\x18$\xd7BӬڶ\f\xf8\xc2P\x94\x15\x104\v\xf1\xdcյ\xc7\xd5\xee\xe3%=\x16\xc1\xaf\xffp;\x8bRյ \xa7)\xacN\x1b\xf48\xc9Ģ\xeb\xfa\xa3\xfejr\x84a\xddq\x84\xb1\x9b~\xe4!\xf6=\xce\xc8R\xdc\xd9f\x9e\x83\xce[\x9d\x12_\x88\xa2\xccl0\xe3\xbd9\xe1\xb8\x17e\x00\u007f#\xdbհ\x9d\xdc+\xcc4\xf7\xd3ڐ7.Y\xd7/#h\xedX&\xe7\x9c\xccUk\xb3R\u0094\xbc\xa7Y6\xa3\xc9\xed\x8d\xf8N,\xd4G~.eP_2\x8f3[\rD\x95&ɲ\xe4\xb7\xf6\x8e\x11?\xf5L\x84\xf8dD\xa9\x8bR\xfb\n\xa3\x06F\xab\xb5#?\x0eJ\x80\xb7\xea\x90S]\x1a3\x83{D\x98\x1b\xbe\x90\x89E5g\xd5<\xc8\u007fx\xf5\xaf\xffn\x19H\xc8\xea%\xf9\xf7WX\\\xa0N\xac\xc0A\xe9m\x14Ɯf\x19\xc8X\xd6`H\xbc\x8b\x15<)'б\x87\xfe\tLכ\x9b\xbf\xa3\xddʴ\x82l~bKS}C\xda\x00\x90\x87\xa8Z\x1d:Yh\xf4\xf7\xe76\x0eW\"+sx\a+\x16\u007f\xd7^\v\x86\xaf\x86ɘ\xd2D\x84\x984\xb3L$\xb7$u`\x1a9\x86\x9b\x8d\xfe\xfbc$8\x8fr\xe7\xba\x1a\x97&Q\x92Ӣ\bu\x0ec\xb1\xa0\xa4w\xade\"\xb7`\xbc\xa9\xb1\x87\xb0\x8c\xd8\b\x87\xfdx\x982\xec\xdfl\xe0\xa7\x06\xe37\xbd\xa0\xc1\x8da\x89\xaf\xc7\xd9\xea\x10X\xb5!\xb5\xdf\t\x86\xeb\xf5!\xb3[\xc8EC\x9d\xcfс\x80\x98\xfc\xd2\x16fy\xe5CϩvvBT\x04\t\xa9\xae\x00\xa9\x982\x8a\xc5g\xa4\xe8\xb7\x19e\xb9sm\x05C\f\x0f9E\xf7\xc5\x0e\xf7\xd5O\x1a4\x19\xf4Z r\a\x14\xbe\x87d[Z\x06\x84}\xcdcy\xf3\x95H\x1d\x18d\xa9\xb6\x03\xbd1\x06\x037\u007fGq\xdf\x10%`\x18s\xfe\\\xe3\xa6͛\xcd/Q\xcc\xd9B\xfcB,\x19\xa7=\x98##/v\v\x18\xd6 \xa4\xe9\xdep\x04\xd40w\x9cWajs<\x82\x81\x1b\x8aqS#\x87o\x0e\x9f\x8d/[$KQ\xd0E\xc4Md\x1b\xb8\xde\x04FR\xb0\x06FDI\x831G\x11\x9eM\x8d+\x1cTH\xab.`\x11 m!V-O\xbd\xc9b[L\xdc\x05\xe7|\x13B\xa5(yj}\xeaux\xe5\xc3\x06\".\x05\x0f\x9f.S\xae=\x19\xb6\x17\xc0\xea\x01\xf3\x1b6\b`\x9c\xbc\x9e\xbe~\xf5\xcb\x11߸\x86\r\xf1\x1d\xd5b\xa9\xc1\x97\x9em\xf5\xfe>\x8aA\x18\xf8\xe0\u070e\xf5\x05\x12,\xae\xed\xbb\x9d\xcf\xe4N2\r\x8d[6\x8f\xd042\x16n\xa3\xb1\xd0qxv\xc1\xc0\xdbi\xe2\xfbs\x13\xa2\xca٣\xf3{˨\x83\xb1\x80L\xa6\xcb#\xadb!v\x88\x8a&\xaa\x0f\x0e\x82!\x1eٙ\x1c*\xec<\x10\xbc\xd5\xd1\xc7\xc1m\xd3\xf9}\x11\xdcس\xb5U\xe7\xf7\x05E\xbfw\xd1\u07b3`D8a\xbc{\xcfb!v\xecٟaIW\x11\xf2L\xb1\x9ceTfk\xb3\xd9\xd7\x16\x83dVj\x02|Ť\xe0y\xcc=d+*\x19\x9de@$`3\x9f\x04\x14\xf9\xfa\xe8\xf3\xd9'\xcc,:6\x923\x18&\xf8])\x15\xe3\x8b-\xeaoLw\x18o98\xd8\"`\x8f\x17CYᒘ\xa7\x15^\x8dƐ\x97\xba\xb4\x97w\xdd'Y\xa9\xd8\xea\xb9\xe4E\x9c\x95Vi\xbb\xbf\x02#\xcd5Xy\xc7\x02\xf8\xc3F\x1b\x99\x9aය\xb5\x04\x86\x83Q)\xab\x1b\x8au\xa6l\x04q\b\u007f\xb9P\xb3\x87\xacs&\xbb\xb6U6\xfd\xdc^9\x1c\xe2\x1a\xd8J\xad\xc1\xa6\x81\xcf\xebV\x0e\xa3\xde\x00\n\f\xa4\xbd\x10\xaas9\x82}\xa6\xdcVJ\xed{\xc4\xdeE\xee\xee~\xa7\xf7\x98\x80gos\xef\xb521\xb7I\x11\x9f!\x03)\xbcи\xa3LW\x95\t\x8c3\xfd6\xec6B4Tl\xab\xba>\xdb\x1d\xb0\xd1=w\xa2\xd7c\x0fm\xd3~r\xdaC>\x0f|}\xf7ww\xbe\xc8x\x92\x95)\xbc\xcdJ\xa5A~\xf2\u05feo\xcel#:\xda\xf9N\xa3\xe8\xc0_\x97\x9d\xd8G&*\x11Eǡ\x97\xf5\xab\x95N\xe1&\x94\xfa\xc2B\xacWq\x97B\xfb\xee\vJ\v\t\x9d\x89P\xbc̲\x8d\xf4wYn\x91\x8ay\xcah\b\x9d\x99\xc1\xbb5u?5c\xa2\xa9\x82\xf6DS\xe3q\xdb\xccNe,A76\xf7\xff`\xff\xcb\xcc\xd6}bk]v\xe7l\x9e\r&/bt\xf1\x04ۊ\xf3\x1a\xbe\xad\x97\xb3\x9f\xdd\\\xf4\x0e7ڞ#\xd2\x03M۴\xe6?\x1fDJ\xf5\xd3\x1b(\xf2\x14\xf20\x86\xb6\x89\xa3\x89\xa3\x9a\xd2\xdcs3\x9aܖ\xc5K@\x18\xb6߿\x86\f\xe5\xf8^d}\xd7|\xd2\"*\aMW\xaf\xa7\xed\u007f16*\xcb4f\xa1v\xa8N\xf6\xe2nēQ!\x18Oي\xa5%\xcdZT\xd6\xc0R\x8dL,Q`ٶq\x8eM\xc2\xdc\xdb-\x9c\x12\x9f\x0e\x15t\x06\xf7yG\xd1Ub\x94a\x97\x10\xd9\xc5D\xdb\x0e\xb8\x8d\x17,\xe6\\\xdc\xd1\xdd~\xa0<\xee\x1ck6\x9a\xfc\x8e\xd2\xc5\x1b\xd7\x00\xc6?\x85\xeb=\xbb|\u05ed\x80\xecq^\xb7\xaf\xf8\xde3\x11w&\xaa\xed]\xd2\xca-\xbaKjb\xa6\xbc:!\x94\xdc\xc2\xda&PR\xee\xbasz\x10\x122\xea/\xab\xbd\x05\x9b\xaa`\xdf\xeb^\xf8\xc3.\xeb[\xd8\xe3\rj-\xd7|\xcf\a\x80q\xdd\xe6\x87*\x90W-\xd5\xddG\xb1O\x1e\xef\x89\xd6\xf5\x90\xfe\x1e#=\xa7]!\xb0\xba%[Y\x14\x1bk͠\xd3\xd0ג\x15X\x84\xb3g\xd6\xeer{\x87m\xf2\x99f,\xad\x80[\x8a\xba\xe0'\xe4Rh\xf3?\xe7\xf7Li\xf5@\x8f\xe9w\x02ԥ\xd0\xf8\xec \x94\xd8I\xf5D\x88}\x18\t\x94[ކ\xa5$\b\xbfZ\xde\xc5\xdc]Xa\u05f7g\x11L\x91\vn\x98\x8c[y\xd5\f[9\xe0\xbe^\x88\v>A\x8e\xe4\xa1\xef\x01Zm\x1aS\x1e\x95B\xb6\xf0\xb5\xe3C{`\u0380\xb8ϣ\x0f\u05fe\x83\xe9\xb9EF\x13H}\x1b]jpA5,XBr\x90{\xef\x9e,\f\x9fڽu\x0f\x86\xc1z)\xbbCU\xd3[\xe8~o\xb2\u007f{\xa3\x15W\xc7\xefQ\xc0u\xae\x9e\xa6\xbe#\xe7\xd5\x03\xfc\xe9\x01\xfcl\xcb\f\xfbQ'hia(\xfb\u007f\r;EB\xf9?RP&Ք\x9c\xb9J\x82\xceo6\x9fw\x9aG\x13\xb4\x81\xca\xd4\xc6M\xea\x94\x13\xb0E\xb1\x9d \xc5|K\xa2\x19C[(\xcbū\x90\xc8\xc1-\xac\x0fNZ'oW\x02\xdb\xc1\x05?\xa8\xb2\xec\xdb\xe7\xc0\xcb\x19\xdb\x1e\xf8\x00\xff\xed`\xba%\x04;\xc1\xee\x15\x8c{(b\xe7?U\x9a\xee\a\x9bX\xb3\xb9\xcf\xfdha\x0f\x1dl\xf5\xafi~\xadE\bM\xb5\xb4\xa5\xc2o\u007f\x8e\xca\x05\xe8.e\xdf\xe9\xaa\x18f\x9f\x923\xbeނ\xda]f]\x99H\x15E\x15\xad\x0e\xebB\xbaD\xee& \x976\xa3hn\xe1o\xee\xc9N\xa4;\x88W\x9f\xf7k\xf2\x9f\xaa\xc7:\xec\xc0\xc6b)\xb6\xc0u\v\xb8\xfa\xbcM9\xb6\x94\x80\xd3B-\x85&G+F]\xa1\x86(Sק]n\xb9\xf5#-:\x95,!-3\xe8\xba\xcac\xab\xe7\x8d\u007f\xd0+.%g\xff,۷\x9axg\x87{z\x9b\x16j\xe9Tg\xbbrk\xd9Q{+\x85\xbdɇI\xe8 n7\x19\x81_\xedyn\t)\x96T\xedgsW扪O}\xe3\xb8U\x1c\xeeS\xe7\\\x80\x97\xf9&\xe0\t\xb9\x84\xbb\xad\xdf\xde#A\u007f\xae\xee\x11\xdfz\xe0\x82_I\xb1\x90\xdb-\xa3&\xfe\xc0lQ\xc1\x84\\Q\xa9\x19Ͳ\xf5\xfb\xae\x06\xd1\xfe\xab}\xf1\xa4Z\xc7f\xbf\\h=ړ1\x18F\xd0Ap\xb6\xac\xef\x05\x1e\xe9\xfa\xd6\xf7\xf3\x87\x0f\xf7獇7\x1cz\xb4\xbe\x91\xdf`\xc2\x1dɣ\x8e\x1b\xb8\xd1\xf6O\xccl7\xef\x8e{&\xc7\xdc\x1d\x95\x9c\xf1\xc5\xfe\xe5~\xef\x1e\xea\xe0f\xee\xfd\xa7\xe3g~\x82m\x8e\xb6\xc3w\x1c\xca\xd1:d\xf7\xc6O+\x90\xca:\x01^\xd7\u007f!\xb6l\x04\xc3\xfd\x03\xb1Ԝ6p\xef\xa6\xe2~\xa9\x15\x02[\xa3\xeb<\xe6\x16\xed\xb7\x8c\xa7o|\x1eH\x91\x95\x92f\xee\xcfDp\xab\xed\xab7\xe4\x87\x1f\xbf\"\x0e\x03\x9f\xfd<̏\xff?\x00\x00\xff\xff\xc1T\x93\xf8ǭ\x01\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec\x1c\xcbn#\xb9\xf1\xee\xaf((\x87I\x00K\xde\xc1^\x02\xddf=^\xc4\xd8\xc9\xec`\xc7\xf1%ȁ\xea.Y\x8c\xd9d\x87dˣ\x04\xf9\xf7\xa0\x8a\xfdV?؎\x1dl\x16\xe6ɦ\xc8b\xb1\xde,\x16\xfbb\xbd^_\x88\\ޣu\xd2\xe8-\x88\\\xe27\x8f\x9a\xfes\x9b\xc7?\xba\x8d4W\xc7\xf7;\xf4\xe2\xfdţ\xd4\xe9\x16\xae\v\xe7M\xf6\v:S\xd8\x04?\xe2^j\xe9\xa5\xd1\x17\x19z\x91\n/\xb6\x17\x00Bk\xe3\x05u;\xfa\x17 1\xda[\xa3\x14\xda\xf5\x03\xea\xcdc\xb1\xc3]!U\x8a\x96W\xa8\xd6?~\xb7\xf9~\xf3\xdd\x05@b\x91\xa7\xdf\xc9\f\x9d\x17Y\xbe\x05](u\x01\xa0E\x86[p\xc9\x01\xd3B\xa1\xdb\x1cQ\xa15\x1bi.\\\x8e\t\xad\xf6`M\x91o\xa1\xf9!L*1\t\xbb\xf8Z\xce\xe7.%\x9d\xff\xa9\xd3\xfdI:\xcf?媰B\xb5\xd6\xe3^'\xf5C\xa1\x84m\xfa/\x00r\x8b\x0e\xed\x11\xff\xa2\x1f\xb5y\xd2?JT\xa9\xdb\xc2^(G?\xbb\xc4丅τI.\x12L/\x00\x8eBɔ\xf7\x19p39\xea\x0f_n\xef\xbf'<2\x11:\x01Rt\x89\x959\x8f\xabQ\x04\xe9@\xc0=o\x12l\xc9\x0e\xf0\a\xe1\xc1\"\xe3\xa2=\x8d\xc8-\xae+,S0\xb6\x84\t\x90\xa3\x95&\x95\t\xfc \x92\xc7\"\x0fS\xdd\xc1\x14*\x85\x1d\x82-\xf4\xa6\x1c\x9b[\x93\xa3\xf5\xb2\"!\xb5\x96\xd4\xd4}=L\xdf\xd1V\xc2\x18HINЁ? \x94\xdcƔ\xa9\x97\t0{\xf0\a\xe9\x1a\xbc\x99$-\xb0@C\x84\x06\xb3\xfb;&~\x03_\x89\xce\xd6U\xd8&F\x1f\xd1Ҿ\x13\xf3\xa0\xe5?k\xc8\x0e\xbc\xe1%\x95\xf0Xr\xb4jR{\xb4Z(bB\x81\x97 t\n\x998\x81EZ\x03\n݂\xc6C\xdc\x06\xfel,\x82\xd4{\xb3\x85\x83\xf7\xb9\xdb^]=H_\xe9Ib\xb2\xac\xd0ҟ\xaeX\xda\xe5\xae\xf0ƺ\xab\x14\x8f\xa8\xae\x9c|X\v\x9b\x1c\xa4\xc7\xc4\x17\x16\xafD.\u05cc\xb8f5\xd9d\xe9\xef*.\xbaw-L\xfd\x89\xc4\xc6y+\xf5C\xdd\xcdB\xcca\x13Ѵ({ڴ\x19\xcbڥs-\"od\xae\x9cƳ\x04\xfa\xf6l\xf2K\v4\x11X\xd2\xd9\xeav\x0f\x98\xe5\xfet\t\xd2W\xbd\xf30)\fjp\xf8M0\xea9\xfap۟\xfb\xc2\xfa\xf0\x02\\\xaaQ\xf8\xbff\x12;\x9b\xaf\xa5\xafY\xc0\xa0O\xedy\x97 \xf75\x83\xd2K\xd8K\xe5\x91\xe3\x9ei\x14[\xaeo\x96S/E\x968\xafI-\x13>9\xdc\xd4G\xc8\xd9\xf1=\n\xf5\xa7\x87X\xb9:It\x9d\xfc,d\xe0\f\x83\xb4\x98\x85\xbc\xc5\x1d\xeb@\xd3Ñڇ\xcf\x1f1\x9d&\x14\xc4J\xe4\xd9v>\xf4Pn/_\x1e\x03\xe27S\x06T\xf5\t+\xe4\xa3.A\xc0#\x9eB\x14$4\x10\xa3\x04-5z\x908'\x12'\xc6\xd8D<\xe2\x89\x01\x95\xb9\xae\x88\xf9\xf1\xa2\x11\xda#\x9e\xe2\x06\xf6HI\x98\x95\x99\x80@S\xea`\x82p\xcad\t\x19\x813\x97\xac!\xe0M\xcc&a\x89\xb9\xa9Zʼngm\xb7fc'\x8d\xfb\x88\xa7w.0\x8c\xb4\xe3 \xf3\xe8\r\x93\x01\x06\x87\xacGU&\xf3^(\x99\xd6K\x05}\xb8\xd5SQw\xb7}6\xfeV_\xc2\xcd7\xe9\b=\x9d\xc2G\x83\xee\xb3\xf1\xdc\xf3j\x84\r\xe8?\x8b\xaca*\xab\x9e\x0ef\x9e\xe8\xd1N\x90F\t}h\xb7\xe1\x84Y\xb3J:\xb8\xd5tV*\xe9\xc2in\x86\x19/\x96\x8cRV8΄j\xa3\xd7\xech7\x03kE\xc3,\xd9cl\x87;m\xf4Z\xcbFC\xa5\x03]@\xed\x8e|O\x80\x10\xd2\xf7J$\x98BZ0QE4D\xe7\xad\xf0\xf8 \x13\xc8\xd0> \xe4\xe4\vb\xb9\x11m\x9fC[,s\xb1\xa1A\xd5JC\x9fƠ\xb4&\xbd\x8e\x1aW\xb1?b\xf0`>zzp\xcc\xde\xd8As\x1c\x13Am\x91\xa6\x9c\xb0\x15\xea\xcb\"/\xb1\x88;\xe7\xf1C@/\xf8\xd7Lp\xa2\xf4_\xe4\"Y\xd8\xff\r\xb9\x906J\xcb?\xf0\x15\x9f\xc2\xce\xec2\xeb\xd6^\x88\u0590\x0e\x88\xe3G\xa1\xfa\xb7\x1d#[4d\x81P\x85P\xc0\xec\xcf\"\x9fKx:\x18\x17<\xf2^\xe2Hr\xb8ۤ\x83\xd5#\x9eV\x97gviu\xabW!D\xe8k}\x04\xd8:\xe20Z\x9d`ųW\xff]8\x15-\x9d\x91\x03\xf9>8>\x10\xa7\x93l\x15M\xd0\xd4\xfa\xf2\x91B\xe8i\xec#e37\xce/@\xe8\x8bq>dD;\x01\xef\xb2|\x1b\x04\xb9*\xf3l \xf6\x1e-8olu\xd5GF\xb2\x976&.\xba\xb9\x03\a1\xb6\xce\xde\x05\xb0t\x98[5\xfa\x1d\xec\xef*\xdc\x01\xd2\xdfs\x10\x13\x0e`\x18rnM\x82\xce͉M\x94\x85\x9fIl\xd6IM\x11\x0eK|\xb76+\xacs\xc9֪-\t\x85\x89\x9c\x8b\x8f\x137\xdfZyY2\x1f\xf4\xff\xbc\xc8.\xc7\x0eX\xeb\xb3L\xe8(\av\x86\xe8u\x98[\xa9X\t*\x1cQ\xecC\xc1\xe6bI\xe4Z\n߯'\x18Ȥ\xbe\xe5E\xe0\xfd\xab\x84\x0f\xb5\xd1\xc5\xe7\x1d\x1f\xae\xab\xd9\r\v\xea\x8e\xe1Kұ\x96\x1b\xbe\xaf\xb0\xd8\xe1\xe4yV\u007fQج\x8do\xa7>\brn\xd2w\x0e\xf6\xd2:\xdf \x1b\rS:\xbe$}\xbd\xb3\x9c\xbe\xb1\xf6\x99G\xb9\x9f\xc3\xdcV2\xee`\x9e\xea\v\xfd\xf1\x8bߡ\xc6\xd7c\br\x0f\xd2\x03\xea\xc4\x14\x9a\x93Fd\fx\x91\xc0\x8exA\x86X\xbf\xd74\xd4E\x16K\x885K\xa2\xd43\xf9\xa5\xf6\x84\x1f\x85T\xaf\xc5F/34ŌcnZ\xb7\x1e!\xcc\xedTjd\xe2\x9b̊\fDF\x8c\x88&9E\x1b2î\f\xc0\x93\x90\x9e=\x12Af\xf7\xe4M4\xc8\xc4d\xb9B\x8f\xb0ý\xb1\xac\xefN\xa6X\xbb\xfeR.\xcc\xf8\xbdc\xbf\t\xd8\v\xa9\n\x1bmu\x17rc\xd9\t\xa94G\u007f\x8e\xc0&\xaa\x84`\x1a\xd9\xc9U\xcaj\x98kU8\x8f6\xbe\xe6\xf6vx\xde@\xfdu\x12\x86\xac\xf9aΰl4\xe5\x16\x8d˪\x8bpI\xd9*E\t\xf5\xfa\xb3\xd1qdq\xedX\x9dv\\)\xd7\\\x01W\xb7\x06\xb9.\x9e\xaa\x8a\x90\x87\xadF\xb9tɭ\xf0\xe2\xa3]\rԭ\xc3\xe2ȼ\xc2\xf6WT\x9f\x1cUb5SX5]\xc2m\xaa5F\xa8\xd8I\xc0w\xc9g;eĿB\xea\xcd\xd6>\x8dW<\x957r\xe8\xc5\xf1\xfd\xa6\xfb\x8b7e\xfd\x13\xf31E\x93\xee\xf8\xceW\x1cJ#Q%\xe5\xca\xea\xb5\xe1\xe3M\xb9\xa3>\xb8&\x17_\xeaN\x93\xd7 L\x87\xedǤ\xc6z\xaff7uw\xf7)l\xc4\xcb\f7\x1f\x8b\x90.Y\xe7\xc2:$\xdaV\x1b\f\x93vc\x8e\xe4`\x9e@\x99r\xf7?\xf4\xf1\xb7\xc8Y\u007f\xce\xcb,\xdeExE_\tdE\xaey\x11\xbe\x1f\x9e\xd7:\xa1\xb5\x98\xc6\xfa<&\xbbc\x90\x84s&\x91\x82\xdf\x0eK_>\xf7y\x8d\x87\xdf\xe3\x81È\xd2\x0f\xc5;\xeb\xa1\x0f-\xac\xeb\xaf>\\\xcc\x00u^\xf8\xc2\xcd\u007f6\x83\x87A\"r_\xd8\xd2\x17$\x85\xe5'\xe0\x04\x02\xc3K\xe9\xe5\x1f\xceP\xc2\xf9 X\x93ߧ\xf8T\x0fkNs·\xac|\xa5y\xf0$\x1c\u007f\x99\"\xe4\xe4\xa5\xeb~r\xa8\xddF\xbeM\x11\xdc\xc0\x16R\xe1qM\xb0{\xbfOZ\xa6Qf\xf3\x13\xf9\xc9\xdd}\xa1\x11\xf5\xcd_IV\x9eV=\xac\x1f\xd9\xc9\xd0\xd5\xce\x1a>\xe3\xd3Yߍ&\xc4\xfb9\xd7p{\x83\xe9}\xfdU\xa4\xd8M5\xdfQ\xe2˲3\x05\xe8\xealop/\xa3'\x94j\xc1\v\x17c\x0e~/\xcf\r-\x1f\xd3\x13\xda\xc9\x1fz\xbf\x8dh\xe1\x84\x06\x0ek߀\x92\xf4\xba\x9a/g\xbdo\xfe\xe3\xa5\xd7嗲\x8e᎙?M\x95\xb6d\xa5\xf4LeO\xa3y\"I0\xf7eƸ\xfdɬՊ\xff\xa9\xbe\x88\xc5\xff&F\x87\xb8\xcfm\xe1\xaf\u007f\xbb\x80ҋ\xdcWxP\xe7\u007f\x02\x00\x00\xff\xff\xdb*.\x0eeL\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4VMo\xe36\x10\xbd\xebW\f\xb6\x87\xbdT\xf2\x06{)t+\xd2\x16\b\xda\x06A\xbcͥ\xe8\x81&G\xf64\x14\xa9r\x86N\xdd__\x90\x94b[\x967\xbb\x87\xd5M\xa3\xf9x|\xf3fĪ\xae\xebJ\r\xf4\x84\x81ɻ\x16\xd4@\xf8\xaf\xa0Ko\xdc<\xff\xc0\r\xf9\xd5\xfef\x83\xa2n\xaagr\xa6\x85\xdb\xc8\xe2\xfbGd\x1f\x83Ɵ\xb0#GB\xdeU=\x8a2JT[\x01(缨d\xe6\xf4\n\xa0\xbd\x93\xe0\xad\xc5Po\xd15\xcfq\x83\x9bH\xd6`\xc8\x15\xa6\xfa\xfb\x0f\xcd\xc7\xe6C\x05\xa0\x03\xe6\xf0O\xd4#\x8b\xea\x87\x16\\\xb4\xb6\x02p\xaa\xc7\x16\x18C\n\x12%\x91\x03\xfe\x13\x91\x85\x9b=Z\f\xbe!_\xf1\x80:\x15\xde\x06\x1f\x87\x16\x8e\x1fJ\xfc\b\xaa\x1ch\x9dS\xads\xaaǒ*\u007f\xb5\xc4\xf2\xeb5\x8f\xdfh\xf4\x1al\f\xca.\x03\xca\x0eLn\x1b\xad\n\x8b.\x15\xc0\x100\u007f\xf8\xc3=;\xff\xe2~!\xb4\x86[\xe8\x94e\xac\x00X\xfb\x01[\xb8O\xa8\a\xa5\xd1T\x00{e\xc9dz\xca9\xfc\x80\xeeLJ\xbb\xa7\x8fk\xbd\xc3^\x15#\x80Aց\x86\xec\xb7t\x06 \x06\x05#\x12\x10\x0fJkd\x06\x1dC@'P\x90\x02\xb9·>\x97\x1b\x13\x03\xa8\x8d\x8f\x02\xb2Cx\xcaԎgkF\x87!\xf8\x01\x83\xd0Dt\x0e9\xca\xec\xd56\xc3\xf8>\x1d\xa2\xf8\x80I\xc2B\xce5Fy\xa0\x01\xce\a\x04߁\xec\x88!`f\xcf\xc99\xba\xccI\aʁ\xdf\xfc\x8dZ\x9a\xf1\xf4\f\xbc\xf3њ\xa4\xc6=\x06\x81\x80\xdao\x1d\xfd\xf7\x9a\x99\x13\r\xa9\xa4U2\xe9`z\xc8\t\x06\xa7l\xa2?\xe2\xf7\xa0\x9c\x81^\x1d `\xaa\x01ѝd\xcb.\xdc\xc0\xef>`&\xb0\x85\x9d\xc8\xc0\xedj\xb5%\x99\x06K\xfb\xbe\x8f\x8e\xe4\xb0\xca\xe3A\x9b(>\xf0\xca\xe0\x1e\xed\x8ai[\xab\xa0w$\xa8%\x06\\\xa9\x81\xea\f\xdc\xe5\xb9jz\xf3]\x18\xa7\x90ߟ \x95C\x12\fK \xb7}5g\xa9_\xe5=ɼ\xa8\xa1\x84\x15\xfcGz\x93)\xb1\xf2\xf8\xf3\xfa\x13LEs\v\xce9\xcfl\x1f\xc3\xf8H|\"\x8a\\\x87\xa14\xae\v\xbe\xcf\x19љ\xc1\x93+ZҖН\x93\xceqӓ\xf0\xa4\xd2ԟ\x06n\xf3z\x81\rB\x1c\x8c\x124\r\xdc9\xb8U=\xda[\xc5\xf8\xcdiO\fs\x9d(}\x9b\xf8ӭx\xeeX\xd8z5O+k\xb1C\vӻ\x1eP\xa7\x9e%\xe2R,u\xa4\xf3\x18@\xe7\x03\xa8\xa5\x90\xe6M\f\xd9\xfb\xabP\x8c;\xa2\xe0\x98m\x8e4\x83o\xe1XZ\x15پS\x8c\xe7\xa6\x19\x9a\x87\xe41\xafl\xa9C}\xd0\x16K\x82\xb2)\xf0-\x10\xe9A\x17\xfby\xbd\x1a\xee\xf1\xe5\xc2\xf6\x10|ړy\x15\x9f>\x8b\xfd\x87\xf2\x8fؒ\xe3ϟ\xa6\xf8\xe4\xbf\xce\xe9\xca=Y\xb5c\x1a\bѹ4\x91\xde%\xf3,)\x9co\xe4\xd9W\x12\xec/p,\"\xb9s\x9d\xcf\u007fm\x95J*)s\x82cS\xc7\x1a\x05\xd1E\xbak=-\xcf|\x15}\x01\x81\xe5\xc9\u007f\xfe\xaf\x0fL\xab\x83\x02.Ԭ3\x96\x05s\xaata^\x9c\x98\x11Y\xb4Vm,\xb6 !\xce#K\x9c\nA\x1d\xceU1\xc9\xe8x\xc7\xf9\xac@.ܓ\xf6_v\xe8\xae)\x1c^\x14/\xf5\xa6\xa4\x81\xcd\xe1Z\xe0\xed\xebem>$E\x96-\xa4\xad[\v]\xb0\xf4\x05D,t\xa9Hu\xe1vpA\xc2\xfa\xd4s\x9a\xfd3\xc1O\x97\x859\xf2+\xc5\x17\x9a:3\x1d\xef\xa67Ƿ,\xecz\xbc\x8b\xe6\x0f\xe3)\xcc\xc9\xc9Y|Pۉ\x8b\xe3nM\u05ecA\xd0\xdc\xcfo\xa2\xefޝ])\xf3\xab\xf6\xceP\xb9Hß\u007fU%+\x9a\xa7\tG2\xfe\x1f\x00\x00\xff\xff\xee@m\x0f\xc7\v\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4VM\x8f\xe44\x13\xbe\xe7W\x94\xf6=\xec\xe5MzG{A\xb9\xa1\x06\xa4\x110\x1aM/sA\x1c\x1c\xa7\xd2]\x8cc\aW\xb9\x87\x06\xf1ߑ\xed\xa4?\xd2\xe9\x9d\xdd\x03\xbe\xa5\\\x1f\x8f\x9f\xfaH\x15eY\x16j\xa0g\xf4L\xce֠\x06\xc2?\x05m\xfc\xe2\xea\xe5\x1b\xaeȭ\xf6w\r\x8a\xba+^ȶ5\xac\x03\x8b럐]\xf0\x1a\xbfÎ,\t9[\xf4(\xaaU\xa2\xea\x02@Y\xebDE1\xc7O\x00\xed\xacxg\f\xfar\x8b\xb6z\t\r6\x81L\x8b>E\x98\xe2\xef?T\x1f\xab\x0f\x05\x80\xf6\x98\xcc?Q\x8f,\xaa\x1fj\xb0\xc1\x98\x02\xc0\xaa\x1ek`\xf4\xd1H\x94\x04\xf6\xf8G@\x16\xae\xf6hл\x8a\\\xc1\x03\xea\x18x\xeb]\x18j8]d\xfb\x11T~\xd0&\xb9\xda$WO\xd9U\xba5\xc4\xf2\xe3-\x8d\x9fh\xd4\x1aL\xf0\xca,\x03J\nLv\x1b\x8c\xf2\x8b*\x05\xc0\xe01]\xfcb_\xac{\xb5?\x10\x9a\x96k\xe8\x94a,\x00X\xbb\x01kx\x88\xa8\a\xa5\xb1\x8d\xb2\xd0\xf8\x91\xff\xf1%\xd9i\r\u007f\xffS\x00액6\xb1\x97/݀\xf6\xdb\xc7\xfb\xe7\x8f\x1b\xbd\xc3^e!@\x8b\xac=\rIo\xe9\x89@\f\nF\xa0 \x0e\x94\xd6\xc8\f:x\x8fVƘ@\xb6s\xbeO\xe1F\xc7\x00\xaaqA@v\bω\xf9\xf1\xe9ը0x7\xa0\x17\x9a\xd0'\x93S\x15\x1ee3\x8c\xef\xe3#\xb2\x0e\xb4\xb1\xee\x90S\x8c\xb1z\xb0\x05N\x0f\x04ׁ\xec\x88\xc1c\"\xd7\xca%\xba\xc4I\aʂk~G-\xd5\xf8z\x06\u07b9`\xdaX\xac{\xf4\x02\x1e\xb5\xdbZ\xfa\xeb\xe8\x99#\r1\xa4Q2\x95\xc9t\xc8\nz\xabL\xa4?\xe0\xffA\xd9\x16zu\x00\x8f1\x06\x04{\xe6-\xa9p\x05?;\x8f\x89\xc0\x1av\"\x03\u05ebՖd\xea;\xed\xfa>X\x92\xc3*u\x0f5A\x9c\xe7U\x8b{4+\xa6m\xa9\xbcޑ\xa0\x96\xe0q\xa5\x06*\x13p\x9bڮ\xea\xdb\xff\x1d\x8b\xe4\xfd\x19R9\xc4zb\xf1d\xb7Gqꄛ\xbc\xc7.\xc8Ր\xcd2\xfe\x13\xbdQ\x14Yy\xfa~\xf3\t\xa6\xa0)\x05\x97\x9c'\xb6Of|\">\x12E\xb6C\x9f\x13\xd7y\xd7'\x8fh\xdb\xc1\x91͵\xa4\r\xa1\xbd$\x9dCӓ\xf0T\xa51?\x15\xac\xd3\xf4\x81\x06!\f\xad\x12l+\xb8\xb7\xb0V=\x9a\xb5b\xfc\xcfi\x8f\fs\x19)}\x9b\xf8\xf3\xa1y\xa9\x98\xd9:\x8a\xa7\x89\xb6\x98\xa1\x85\xee\xdd\f\xa8c\xce\"qі:ҩ\r\xa0s\x1eԒI\xf5&\x86[ W\xea\xb1\xf6_whoU8\xbc*^\xcaMv\x03\xcd\xe1\x96\xe1\xfa\xb8\xcb͛$\x97e\rq\xea\x96BW,}\x01\x11\vYʥ\xba\xb0\x1d\\\x91\xb09לz\xff\xa2\xe0\xa7ea\x8e\xfcF\xf0\x85\xa4\xceD\xa7\xd5\xf5\xee\xf4\x95\n\xbb\x1cW\xd5t1\xbe\xa2={9\x8b\xf3j;qq\x9a\xadq\xcd\x1a\x04ۇ\xf9\xa2\xfa\xee\xdd\xc5ƙ>\xb5\xb3-\xe5=\x1b~\xfd\xad\xc8^\xb1}\x9epD\xe1\xbf\x01\x00\x00\xff\xff\x05Z\xe4\x1a\xe6\v\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4V\xc1\x8e\xdc6\f\xbd\xfb+\x88\xf4\x90K\xed\xc9\"\x97·`\xdb\x02A\xd3`\x91M\xe6R\xf4\xa0\x91\xe8\x19veI\x15)\xa7ۯ/$\xcb;\xe3ٙ\xa4E\x11\xdfDS\xe4\xe3\xe3#\xa1\xa6m\xdbF\x05\xdabd\xf2\xae\a\x15\b\xff\x12t\xf9\xc4\xdd\xc3\x0fܑ\xdfL7;\x14u\xd3<\x903=\xdc&\x16?~@\xf6)j\xfc\x11\ar$\xe4]3\xa2(\xa3D\xf5\r\x80r\u038b\xcaf\xceG\x00\xed\x9dDo-\xc6v\x8f\xae{H;\xdc%\xb2\x06cɰ\xe4\x9f^u\xaf\xbbW\r\x80\x8eX\xae\u007f\xa4\x11Y\xd4\x18zp\xc9\xda\x06\xc0\xa9\x11{\x98\xbcM#\xb2S\x81\x0f^\xac\xd7s\xb2nB\x8b\xd1w\xe4\x1b\x0e\xa8s\xee}\xf4)\xf4p\xfc1\x87\xa8\xb8暶%\xda}\x8d\xf6\xaeF+\x0e\x96X~\xf9\x82\xd3;b)\x8e\xc1\xa6\xa8\xecUdŇ\xc9\xed\x93U\xf1\x9aW\x03\x10\"2\xc6\t?\xb9\a\xe7?\xbb\x9f\t\xad\xe1\x1e\x06e\x19\x1b\x00\xd6>`\x0f\xefs\x05Ai4\r\xc0\xa4,\x99r\u007f\xae\xc9\ato\xee\xden_\xdf\xeb\x03\x8ej6\x02\x18d\x1d)\x14\xbf+\xc5\x001(X\xd0\xc0\xe7\x03F\x84ma\x0eX|D\xae\xc0kH\x80\xa5\x02\xee\xaa)D\x1f0\n-\x04\xe7\xefDaO\xb63_\x9b\xf1\x1f\xe9ͦ\xccʇ\x9f\xee?\u0092\xb4\xb4`\xcdya\xfbx\x8d\x8f\xc4g\xa2\xc8\r\x18\xe7\xc6\rя%\":\x13<9)\am\tݚtN\xbb\x91$w\xfaτ,\xb9?\x1dܖ\xcd\x02;\x84\x14\x8c\x124\x1d\xbcup\xabF\xb4\xb7\x8a\xf1\x9bӞ\x19\xe66S\xfau\xe2O\x17\xe2\xdaqf\xeb8DuU]\xec\xd0\xe5I\xbd\x0f\xa8W\x83\x92c\xd0@ur\a\x1fA\xadجS|9Zw\xe2zi\x80a\xde\xe0\x03\xed\xd76\x00eL\xd9\xfe\xca\xde]\xb9w\x95\x9e\v\xb5ޖ\x1cY\x8e\xb9\x80\x10\xfdD\x06c\xbb\xd4V1\xa4X\x8b,\xbb\xb1k.\xe5:c\xb8\x16V\u009d\xc3[!\xb8\xabN\x19C\xa6u\xb94\xef\x1d\xac\xeb\xaf,C\xb5\xc7˹\x9fՙ\x15L\x11WS\xd8>\x85\xfe\xaa:DI\xe2\xff\xaa\x8fr\xa9z\xee\xaaFt\x8a\x11\x9dԈ\xe0\x87\x15|\xf5\xff5\x12\x0e\x8a\xf1\x8b\xfc^\x8e}\x97\xef-\x94[\x1aP?Z\x9c\xa3\x95m\xfeLP\xff\x1ai\xfeХ\xf1\x1cT\vo&EV\xed,>\xfb\xf3ɩ+\xff\xae\xf4\xf7B\xdb\xceL\xc7\a\xce\xcd\xf1T\xc8k\x97\a\xcd\xcd\xfcB\xc8K\xd3\xf4 1\xcdɫҪ\xe5\xa8\x05\xa55\x06A\xf3\xfe\xfc-\xf3\xe2\xc5\xea9R\x8eڻyL\xb9\x87\xdf~o\xe6\xa8h\xb6\v\x8el\xfc'\x00\x00\xff\xff\xbcn\x89\xa9\f\n\x00\x00"), } diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 9406b2529..7d2c8aafc 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -26,3 +26,23 @@ rules: - get - patch - update +- apiGroups: + - velero.io + resources: + - serverstatusrequests + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - velero.io + resources: + - serverstatusrequests/status + verbs: + - get + - patch + - update diff --git a/config/samples/velero_v1_serverstatusrequest.yaml b/config/samples/velero_v1_serverstatusrequest.yaml new file mode 100644 index 000000000..60cfcfc9b --- /dev/null +++ b/config/samples/velero_v1_serverstatusrequest.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: velero.io/v1 +kind: ServerStatusRequest +metadata: + creationTimestamp: "2020-08-21T15:34:34Z" + generateName: velero-cli- + generation: 1 + name: velero-cli-6wkzd + namespace: velero + resourceVersion: "544749" + selfLink: /apis/velero.io/v1/namespaces/velero/serverstatusrequests/velero-cli-6wkzd + uid: 335ea64e-1904-40ec-8106-1f2b22e9540e +spec: {} +status: + phase: Processed + plugins: + - kind: ObjectStore + name: velero.io/aws + - kind: VolumeSnapshotter + name: velero.io/aws + - kind: BackupItemAction + name: velero.io/crd-remap-version + - kind: BackupItemAction + name: velero.io/pod + processedTimestamp: "2020-08-21T15:34:34Z" \ No newline at end of file diff --git a/go.mod b/go.mod index e2aa4c19d..bd66b2368 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,9 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.4.0 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 - google.golang.org/grpc v1.28.0 + google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485 // indirect + google.golang.org/grpc v1.31.0 + google.golang.org/protobuf v1.25.0 // indirect k8s.io/api v0.18.4 k8s.io/apiextensions-apiserver v0.18.4 k8s.io/apimachinery v0.18.4 diff --git a/go.sum b/go.sum index 335552eb9..0f4205e80 100644 --- a/go.sum +++ b/go.sum @@ -72,13 +72,16 @@ github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkF github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aws/aws-sdk-go v1.28.2 h1:j5IXG9CdyLfcVfICqo1PXVv+rua+QQHbkXuvuU/JF+8= @@ -95,6 +98,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= +github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= @@ -108,10 +112,12 @@ github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlR github.com/cilium/ebpf v0.0.0-20191025125908-95b36a581eed/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= +github.com/container-storage-interface/spec v1.2.0 h1:bD9KIVgaVKKkQ/UbVUY9kCaH/CJbhNxe0eeB4JeJV2s= github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -122,12 +128,16 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= @@ -149,16 +159,21 @@ github.com/docker/libnetwork v0.8.0-dev.2.0.20190925143933-c8a5fca4a652/go.mod h github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29 h1:llBx5m8Gk0lrAaiLud2wktkX/e8haX7Ru0oVfQqtZQ4= github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= 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 h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 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 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -174,15 +189,19 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= +github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= +github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= @@ -193,46 +212,57 @@ github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70t github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4 h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY= github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5 h1:QhCBKRYqZR+SKo4gl1lPhPahope8/RLt6EVgY8X80w0= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= @@ -257,6 +287,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= @@ -278,6 +309,7 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +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/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= @@ -301,6 +333,7 @@ github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAO github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/cadvisor v0.35.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -308,11 +341,14 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f h1:Jnx61latede7zDD3DiiP4gmNz33uK0U5HDUaF0a/HVQ= @@ -329,17 +365,24 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= @@ -352,11 +395,13 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/heketi/heketi v9.0.1-0.20190917153846-c2e2a4ab7ab9+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= @@ -369,6 +414,7 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -377,12 +423,14 @@ github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -395,9 +443,11 @@ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kubernetes-csi/csi-lib-utils v0.7.0 h1:t1cS7HTD7z5D7h9iAdjWuHtMxJPb9s1fIv34rxytzqs= github.com/kubernetes-csi/csi-lib-utils v0.7.0/go.mod h1:bze+2G9+cmoHxN6+WyG1qT4MDxgZJMLGwc7V4acPNm0= github.com/kubernetes-csi/csi-test v2.0.0+incompatible/go.mod h1:YxJ4UiuPWIhMBkxUKY5c267DyA0uDZ/MtAimhx/2TA0= github.com/kubernetes-csi/external-snapshotter/v2 v2.2.0-rc1 h1:/71hejlH+46ySQJf7iZMOnuYaZNVNXq1lx6vIPqgUFE= @@ -415,12 +465,14 @@ github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H7 github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -446,6 +498,7 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1: github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -458,9 +511,12 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= @@ -494,7 +550,9 @@ github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -527,8 +585,10 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= @@ -543,8 +603,11 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -552,6 +615,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -559,6 +623,7 @@ github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -566,6 +631,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -581,6 +647,7 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= @@ -595,13 +662,17 @@ github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= @@ -693,6 +764,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -773,6 +845,7 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/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 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -806,6 +879,9 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191220175831-5c49e3ecc1c1 h1:PlscBL5CvF+v1mNR82G+i4kACGq2JQvKDnNq7LSS65o= google.golang.org/genproto v0.0.0-20191220175831-5c49e3ecc1c1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485 h1:wTk5DQB3+1darAz4Ldomo0r5bUOCKX7gilxQ4sb2kno= +google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -814,16 +890,26 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -831,12 +917,14 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -866,6 +954,7 @@ k8s.io/apiextensions-apiserver v0.18.4 h1:Y3HGERmS8t9u12YNUFoOISqefaoGRuTc43AYCL k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= k8s.io/apimachinery v0.18.4 h1:ST2beySjhqwJoIFk6p7Hp5v5O0hYY6Gngq/gUYXTPIA= k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apiserver v0.18.4 h1:pn1jSQkfboPSirZopkVpEdLW4FcQLnYMaIY8LFxxj30= k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= k8s.io/cli-runtime v0.18.4 h1:IUx7quIOb4gbQ4M+B1ksF/PTBovQuL5tXWzplX3t+FM= k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g= @@ -874,10 +963,12 @@ k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= k8s.io/cloud-provider v0.18.4/go.mod h1:JdI6cuSFPSPANEciv0v5qfwztkeyFCVc1S3krLYrw0E= k8s.io/cluster-bootstrap v0.18.4/go.mod h1:hNG705ec9SMN2BGlJ81R2CnyJjNKfROtAxvI9JXZdiM= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.18.4 h1:Kr53Fp1iCGNsl9Uv4VcRvLy7YyIqi9oaJOQ7SXtKI98= k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= k8s.io/cri-api v0.18.4/go.mod h1:OJtpjDvfsKoLGhvcc0qfygved0S0dGX56IJzPbqTG1s= k8s.io/csi-translation-lib v0.18.4/go.mod h1:FTci2m8/3oN8E+8OyblBXei8w4mwbiH4boNPeob4piE= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 h1:RPscN6KhmG54S33L+lr3GS+oD1jmchIU0ll519K6FA4= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -895,6 +986,7 @@ k8s.io/kube-proxy v0.18.4/go.mod h1:h2c+ckQC1XpybDs53mWhLCvvM6txduWVLPQwwvGqR9M= k8s.io/kube-scheduler v0.18.4/go.mod h1:vRFb/8Yi7hh670beaPrXttMpjt7H8EooDkgwFm8ts4k= k8s.io/kubectl v0.18.4/go.mod h1:EzB+nfeUWk6fm6giXQ8P4Fayw3dsN+M7Wjy23mTRtB0= k8s.io/kubelet v0.18.4/go.mod h1:D0V9JYaTJRF+ry+9JfnM4uyg3ySRLQ02XjfQ5f2u4CM= +k8s.io/kubernetes v1.18.0 h1:rVe+edi5GwutPQJ4KIZq1Nk506nmnfyz/KOZVCLv7Yo= k8s.io/kubernetes v1.18.0/go.mod h1:z8xjOOO1Ljz+TaHpOxVGC7cxtF32TesIamoQ+BZrVS0= k8s.io/legacy-cloud-providers v0.18.4/go.mod h1:Mnxtra7DxVrODfGZHPsrkLi22lwmZOlWkjyyO3vW+WM= k8s.io/metrics v0.18.4/go.mod h1:luze4fyI9JG4eLDZy0kFdYEebqNfi0QrG4xNEbPkHOs= @@ -916,9 +1008,11 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 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/apiserver-network-proxy/konnectivity-client v0.0.7 h1:uuHDyjllyzRyCIvvn0OBjiRB0SgBZGqHNYAmjR7fO50= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/controller-runtime v0.6.1 h1:LcK2+nk0kmaOnKGN+vBcWHqY5WDJNJNB/c5pW+sU8fc= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= diff --git a/internal/velero/serverstatusrequest.go b/internal/velero/serverstatusrequest.go new file mode 100644 index 000000000..e57ca2a32 --- /dev/null +++ b/internal/velero/serverstatusrequest.go @@ -0,0 +1,73 @@ +/* +Copyright 2020 the Velero contributors. + +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 velero + +import ( + "context" + + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/clock" + "sigs.k8s.io/controller-runtime/pkg/client" + + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/buildinfo" + "github.com/vmware-tanzu/velero/pkg/plugin/framework" +) + +// ServerStatus holds information for retrieving installed +// plugins and for updating the ServerStatusRequest timestamp. +type ServerStatus struct { + PluginRegistry PluginLister + Clock clock.Clock +} + +// PatchStatusProcessed patches status fields, including loading the plugin info, and updates +// the ServerStatusRequest.Status.Phase to ServerStatusRequestPhaseProcessed. +func (s *ServerStatus) PatchStatusProcessed(kbClient client.Client, req *velerov1api.ServerStatusRequest, ctx context.Context) error { + statusPatch := client.MergeFrom(req.DeepCopyObject()) + req.Status.ServerVersion = buildinfo.Version + req.Status.Phase = velerov1api.ServerStatusRequestPhaseProcessed + req.Status.ProcessedTimestamp = &metav1.Time{Time: s.Clock.Now()} + req.Status.Plugins = getInstalledPluginInfo(s.PluginRegistry) + + if err := kbClient.Status().Patch(ctx, req, statusPatch); err != nil { + return errors.WithStack(err) + } + + return nil +} + +type PluginLister interface { + // List returns all PluginIdentifiers for kind. + List(kind framework.PluginKind) []framework.PluginIdentifier +} + +func getInstalledPluginInfo(pluginLister PluginLister) []velerov1api.PluginInfo { + var plugins []velerov1api.PluginInfo + for _, v := range framework.AllPluginKinds() { + list := pluginLister.List(v) + for _, plugin := range list { + pluginInfo := velerov1api.PluginInfo{ + Name: plugin.Name, + Kind: plugin.Kind.String(), + } + plugins = append(plugins, pluginInfo) + } + } + return plugins +} diff --git a/pkg/serverstatusrequest/process_test.go b/internal/velero/serverstatusrequest_test.go similarity index 65% rename from pkg/serverstatusrequest/process_test.go rename to internal/velero/serverstatusrequest_test.go index bebc70796..ff9285ccb 100644 --- a/pkg/serverstatusrequest/process_test.go +++ b/internal/velero/serverstatusrequest_test.go @@ -1,5 +1,5 @@ /* -Copyright 2018 the Velero contributors. +Copyright 2020 the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package serverstatusrequest +package velero import ( "context" @@ -22,25 +22,26 @@ import ( "testing" "time" - "github.com/sirupsen/logrus" + . "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/clock" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/buildinfo" - "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake" + "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme" "github.com/vmware-tanzu/velero/pkg/plugin/framework" ) -func statusRequestBuilder() *builder.ServerStatusRequestBuilder { - return builder.ForServerStatusRequest(velerov1api.DefaultNamespace, "sr-1") +func statusRequestBuilder(resourceVersion string) *builder.ServerStatusRequestBuilder { + return builder.ForServerStatusRequest(velerov1api.DefaultNamespace, "sr-1", resourceVersion) } -func TestProcess(t *testing.T) { +func TestPatchStatusProcessed(t *testing.T) { // now will be used to set the fake clock's time; capture // it here so it can be referenced in the test case defs. now, err := time.Parse(time.RFC1123, time.RFC1123) @@ -54,11 +55,10 @@ func TestProcess(t *testing.T) { req *velerov1api.ServerStatusRequest reqPluginLister *fakePluginLister expected *velerov1api.ServerStatusRequest - expectedErrMsg string }{ { name: "server status request with empty phase gets processed", - req: statusRequestBuilder().Result(), + req: statusRequestBuilder("0").Result(), reqPluginLister: &fakePluginLister{ plugins: []framework.PluginIdentifier{ { @@ -67,7 +67,7 @@ func TestProcess(t *testing.T) { }, }, }, - expected: statusRequestBuilder(). + expected: statusRequestBuilder("1"). ServerVersion(buildinfo.Version). Phase(velerov1api.ServerStatusRequestPhaseProcessed). ProcessedTimestamp(now). @@ -81,7 +81,7 @@ func TestProcess(t *testing.T) { }, { name: "server status request with phase=New gets processed", - req: statusRequestBuilder(). + req: statusRequestBuilder("0"). Phase(velerov1api.ServerStatusRequestPhaseNew). Result(), reqPluginLister: &fakePluginLister{ @@ -96,7 +96,7 @@ func TestProcess(t *testing.T) { }, }, }, - expected: statusRequestBuilder(). + expected: statusRequestBuilder("1"). ServerVersion(buildinfo.Version). Phase(velerov1api.ServerStatusRequestPhaseProcessed). ProcessedTimestamp(now). @@ -113,65 +113,65 @@ func TestProcess(t *testing.T) { Result(), }, { - name: "server status request with phase=Processed gets deleted if expired", - req: statusRequestBuilder(). + name: "server status request with phase=Processed gets processed", + req: statusRequestBuilder("0"). Phase(velerov1api.ServerStatusRequestPhaseProcessed). - ProcessedTimestamp(now.Add(-61 * time.Second)). Result(), reqPluginLister: &fakePluginLister{ plugins: []framework.PluginIdentifier{ + { + Name: "velero.io/aws", + Kind: "ObjectStore", + }, { Name: "custom.io/myown", Kind: "VolumeSnapshotter", }, }, }, - expected: nil, - }, - { - name: "server status request with phase=Processed does not get deleted if not expired", - req: statusRequestBuilder(). + expected: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). Phase(velerov1api.ServerStatusRequestPhaseProcessed). - ProcessedTimestamp(now.Add(-59 * time.Second)). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "velero.io/aws", + Kind: "ObjectStore", + }, + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). Result(), - expected: statusRequestBuilder(). - Phase(velerov1api.ServerStatusRequestPhaseProcessed). - ProcessedTimestamp(now.Add(-59 * time.Second)). - Result(), - }, - { - name: "server status request with invalid phase returns an error", - req: statusRequestBuilder(). - Phase(velerov1api.ServerStatusRequestPhase("an-invalid-phase")). - Result(), - expected: statusRequestBuilder(). - Phase(velerov1api.ServerStatusRequestPhase("an-invalid-phase")). - Result(), - expectedErrMsg: "unexpected ServerStatusRequest phase \"an-invalid-phase\"", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - client := fake.NewSimpleClientset(tc.req) + g := NewWithT(t) - err := Process(tc.req, client.VeleroV1(), tc.reqPluginLister, clock.NewFakeClock(now), logrus.StandardLogger()) - if tc.expectedErrMsg == "" { - assert.Nil(t, err) - } else { - assert.EqualError(t, err, tc.expectedErrMsg) + serverStatusInfo := ServerStatus{ + PluginRegistry: tc.reqPluginLister, + Clock: clock.NewFakeClock(now), } - res, err := client.VeleroV1().ServerStatusRequests(tc.req.Namespace).Get(context.TODO(), tc.req.Name, metav1.GetOptions{}) + kbClient := fake.NewFakeClientWithScheme(scheme.Scheme, tc.req) + err := serverStatusInfo.PatchStatusProcessed(kbClient, tc.req, context.Background()) + assert.Nil(t, err) + + key := client.ObjectKey{Name: tc.req.Name, Namespace: tc.req.Namespace} + instance := &velerov1api.ServerStatusRequest{} + err = kbClient.Get(context.Background(), key, instance) + if tc.expected == nil { - assert.Nil(t, res) - assert.True(t, apierrors.IsNotFound(err)) + g.Expect(apierrors.IsNotFound(err)).To(BeTrue()) } else { sortPluginsByKindAndName(tc.expected.Status.Plugins) - sortPluginsByKindAndName(res.Status.Plugins) - assert.Equal(t, tc.expected.Status.Plugins, res.Status.Plugins) - assert.Equal(t, tc.expected, res) - assert.Nil(t, err) + sortPluginsByKindAndName(instance.Status.Plugins) + g.Expect(instance.Status.Plugins).To(BeEquivalentTo((tc.expected.Status.Plugins))) + g.Expect(instance).To(BeEquivalentTo((tc.expected))) + g.Expect(err).To(BeNil()) } }) } diff --git a/pkg/apis/velero/v1/server_status_request.go b/pkg/apis/velero/v1/server_status_request_types.go similarity index 79% rename from pkg/apis/velero/v1/server_status_request.go rename to pkg/apis/velero/v1/server_status_request_types.go index 027087cf0..a2dd0051b 100644 --- a/pkg/apis/velero/v1/server_status_request.go +++ b/pkg/apis/velero/v1/server_status_request_types.go @@ -1,5 +1,5 @@ /* -Copyright 2018 the Velero contributors. +Copyright 2020 the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,8 +20,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// TODO(2.0) After converting all resources to use the runttime-controller client, +// the genclient and k8s:deepcopy markers will no longer be needed and should be removed. // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:object:generate=true +// +kubebuilder:storageversion +// +kubebuilder:subresource:status // ServerStatusRequest is a request to access current status information about // the Velero server. @@ -81,7 +87,12 @@ type ServerStatusRequestStatus struct { Plugins []PluginInfo `json:"plugins,omitempty"` } +// TODO(2.0) After converting all resources to use the runttime-controller client, +// the k8s:deepcopy marker will no longer be needed and should be removed. // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:rbac:groups=velero.io,resources=serverstatusrequests,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=velero.io,resources=serverstatusrequests/status,verbs=get;update;patch // ServerStatusRequestList is a list of ServerStatusRequests. type ServerStatusRequestList struct { diff --git a/pkg/builder/server_status_request_builder.go b/pkg/builder/server_status_request_builder.go index 4b5e1a3c9..9dcf9cfb6 100644 --- a/pkg/builder/server_status_request_builder.go +++ b/pkg/builder/server_status_request_builder.go @@ -30,7 +30,7 @@ type ServerStatusRequestBuilder struct { } // ForServerStatusRequest is the constructor for for a ServerStatusRequestBuilder. -func ForServerStatusRequest(ns, name string) *ServerStatusRequestBuilder { +func ForServerStatusRequest(ns, name, resourceVersion string) *ServerStatusRequestBuilder { return &ServerStatusRequestBuilder{ object: &velerov1api.ServerStatusRequest{ TypeMeta: metav1.TypeMeta{ @@ -38,8 +38,9 @@ func ForServerStatusRequest(ns, name string) *ServerStatusRequestBuilder { Kind: "ServerStatusRequest", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: ns, - Name: name, + Namespace: ns, + Name: name, + ResourceVersion: resourceVersion, }, }, } diff --git a/pkg/cmd/cli/plugin/get.go b/pkg/cmd/cli/plugin/get.go index f43b49abe..daf0f0884 100644 --- a/pkg/cmd/cli/plugin/get.go +++ b/pkg/cmd/cli/plugin/get.go @@ -17,6 +17,7 @@ limitations under the License. package plugin import ( + "context" "fmt" "os" "time" @@ -30,9 +31,7 @@ import ( ) func NewGetCommand(f client.Factory, use string) *cobra.Command { - serverStatusGetter := &serverstatus.DefaultServerStatusGetter{ - Timeout: 5 * time.Second, - } + timeout := 5 * time.Second c := &cobra.Command{ Use: use, @@ -41,17 +40,18 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command { err := output.ValidateFlags(c) cmd.CheckError(err) - serverStatusGetter := &serverstatus.DefaultServerStatusGetter{ - Namespace: f.Namespace(), - Timeout: 5 * time.Second, - } - - client, err := f.Client() + kbClient, err := f.KubebuilderClient() cmd.CheckError(err) - veleroClient := client.VeleroV1() + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() - serverStatus, err := serverStatusGetter.GetServerStatus(veleroClient) + serverStatusGetter := &serverstatus.DefaultServerStatusGetter{ + Namespace: f.Namespace(), + Context: ctx, + } + + serverStatus, err := serverStatusGetter.GetServerStatus(kbClient) if err != nil { fmt.Fprintf(os.Stdout, "\n", err) return @@ -62,7 +62,7 @@ func NewGetCommand(f client.Factory, use string) *cobra.Command { }, } - c.Flags().DurationVar(&serverStatusGetter.Timeout, "timeout", serverStatusGetter.Timeout, "Maximum time to wait for plugin information to be reported.") + c.Flags().DurationVar(&timeout, "timeout", timeout, "maximum time to wait for plugin information to be reported. Default is 5 seconds.") output.BindFlagsSimple(c.Flags()) return c diff --git a/pkg/cmd/cli/serverstatus/server_status.go b/pkg/cmd/cli/serverstatus/server_status.go index 4835926a0..534fa4f59 100644 --- a/pkg/cmd/cli/serverstatus/server_status.go +++ b/pkg/cmd/cli/serverstatus/server_status.go @@ -1,5 +1,5 @@ /* -Copyright 2019 the Velero contributors. +Copyright 2020 the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,78 +21,53 @@ import ( "time" "github.com/pkg/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/controller-runtime/pkg/client" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" - velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" ) type ServerStatusGetter interface { - GetServerStatus(client velerov1client.ServerStatusRequestsGetter) (*velerov1api.ServerStatusRequest, error) + GetServerStatus(kbClient kbclient.Client) (*velerov1api.ServerStatusRequest, error) } type DefaultServerStatusGetter struct { Namespace string - Timeout time.Duration + Context context.Context } -func (g *DefaultServerStatusGetter) GetServerStatus(client velerov1client.ServerStatusRequestsGetter) (*velerov1api.ServerStatusRequest, error) { - req := builder.ForServerStatusRequest(g.Namespace, ""). - ObjectMeta( - builder.WithGenerateName("velero-cli-"), - ).Result() +func (g *DefaultServerStatusGetter) GetServerStatus(kbClient kbclient.Client) (*velerov1api.ServerStatusRequest, error) { + created := builder.ForServerStatusRequest(g.Namespace, "", "0").ObjectMeta(builder.WithGenerateName("velero-cli-")).Result() - created, err := client.ServerStatusRequests(g.Namespace).Create(context.TODO(), req, metav1.CreateOptions{}) - if err != nil { + if err := kbClient.Create(context.Background(), created, &kbclient.CreateOptions{}); err != nil { return nil, errors.WithStack(err) } - defer client.ServerStatusRequests(g.Namespace).Delete(context.TODO(), created.Name, metav1.DeleteOptions{}) - listOptions := metav1.ListOptions{ - // TODO: once the minimum supported Kubernetes version is v1.9.0, uncomment the following line. + ctx, cancel := context.WithCancel(g.Context) + defer cancel() + + key := client.ObjectKey{Name: created.Name, Namespace: g.Namespace} + checkFunc := func() { + updated := &velerov1api.ServerStatusRequest{} + if err := kbClient.Get(ctx, key, updated); err != nil { + return + } + + // TODO: once the minimum supported Kubernetes version is v1.9.0, remove the following check. // See http://issue.k8s.io/51046 for details. - //FieldSelector: "metadata.name=" + req.Name - ResourceVersion: created.ResourceVersion, - } - watcher, err := client.ServerStatusRequests(g.Namespace).Watch(context.TODO(), listOptions) - if err != nil { - return nil, errors.WithStack(err) - } - defer watcher.Stop() + if updated.Name != created.Name { + return + } - expired := time.NewTimer(g.Timeout) - defer expired.Stop() - -Loop: - for { - select { - case <-expired.C: - return nil, errors.New("timed out waiting for server status request to be processed") - case e := <-watcher.ResultChan(): - updated, ok := e.Object.(*velerov1api.ServerStatusRequest) - if !ok { - return nil, errors.Errorf("unexpected type %T", e.Object) - } - - // TODO: once the minimum supported Kubernetes version is v1.9.0, remove the following check. - // See http://issue.k8s.io/51046 for details. - if updated.Name != created.Name { - continue - } - - switch e.Type { - case watch.Deleted: - return nil, errors.New("server status request was unexpectedly deleted") - case watch.Modified: - if updated.Status.Phase == velerov1api.ServerStatusRequestPhaseProcessed { - req = updated - break Loop - } - } + if updated.Status.Phase == velerov1api.ServerStatusRequestPhaseProcessed { + created = updated + cancel() } } - return req, nil + wait.Until(checkFunc, 250*time.Millisecond, ctx.Done()) + + return created, nil } diff --git a/pkg/cmd/cli/version/version.go b/pkg/cmd/cli/version/version.go index 0017e066c..8c9275c10 100644 --- a/pkg/cmd/cli/version/version.go +++ b/pkg/cmd/cli/version/version.go @@ -17,51 +17,54 @@ limitations under the License. package version import ( + "context" "fmt" "io" "os" "time" "github.com/spf13/cobra" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/vmware-tanzu/velero/pkg/buildinfo" "github.com/vmware-tanzu/velero/pkg/client" "github.com/vmware-tanzu/velero/pkg/cmd" "github.com/vmware-tanzu/velero/pkg/cmd/cli/serverstatus" - velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" ) func NewCommand(f client.Factory) *cobra.Command { - clientOnly := false - serverStatusGetter := &serverstatus.DefaultServerStatusGetter{ - Namespace: f.Namespace(), - Timeout: 5 * time.Second, - } + var clientOnly bool + timeout := 5 * time.Second c := &cobra.Command{ Use: "version", Short: "Print the velero version and associated image", Run: func(c *cobra.Command, args []string) { - var veleroClient velerov1client.ServerStatusRequestsGetter - + var kbClient kbclient.Client if !clientOnly { - client, err := f.Client() + var err error + kbClient, err = f.KubebuilderClient() cmd.CheckError(err) - - veleroClient = client.VeleroV1() } - serverStatusGetter.Namespace = f.Namespace() - printVersion(os.Stdout, clientOnly, veleroClient, serverStatusGetter) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + serverStatusGetter := &serverstatus.DefaultServerStatusGetter{ + Namespace: f.Namespace(), + Context: ctx, + } + printVersion(os.Stdout, clientOnly, kbClient, serverStatusGetter) }, } - c.Flags().DurationVar(&serverStatusGetter.Timeout, "timeout", serverStatusGetter.Timeout, "Maximum time to wait for server version to be reported") - c.Flags().BoolVar(&clientOnly, "client-only", clientOnly, "Only get velero client version, not server version") + c.Flags().DurationVar(&timeout, "timeout", timeout, "maximum time to wait for server version to be reported. Default is 5 seconds.") + c.Flags().BoolVar(&clientOnly, "client-only", clientOnly, "only get velero client version, not server version") return c } -func printVersion(w io.Writer, clientOnly bool, client velerov1client.ServerStatusRequestsGetter, serverStatusGetter serverstatus.ServerStatusGetter) { +func printVersion(w io.Writer, clientOnly bool, kbClient kbclient.Client, serverStatusGetter serverstatus.ServerStatusGetter) { fmt.Fprintln(w, "Client:") fmt.Fprintf(w, "\tVersion: %s\n", buildinfo.Version) fmt.Fprintf(w, "\tGit commit: %s\n", buildinfo.FormattedGitSHA()) @@ -70,7 +73,7 @@ func printVersion(w io.Writer, clientOnly bool, client velerov1client.ServerStat return } - serverStatus, err := serverStatusGetter.GetServerStatus(client) + serverStatus, err := serverStatusGetter.GetServerStatus(kbClient) if err != nil { fmt.Fprintf(w, "\n", err) return diff --git a/pkg/cmd/cli/version/version_test.go b/pkg/cmd/cli/version/version_test.go index eb4928f17..40165dfbc 100644 --- a/pkg/cmd/cli/version/version_test.go +++ b/pkg/cmd/cli/version/version_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 the Velero contributors. +Copyright 2020 the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,12 +24,13 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" "github.com/vmware-tanzu/velero/pkg/buildinfo" - "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake" - v1 "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" + "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme" ) func TestPrintVersion(t *testing.T) { @@ -73,7 +74,7 @@ func TestPrintVersion(t *testing.T) { { name: "server status getter returns normally", clientOnly: false, - serverStatusRequest: builder.ForServerStatusRequest("velero", "ssr-1").ServerVersion("v1.0.1").Result(), + serverStatusRequest: builder.ForServerStatusRequest("velero", "ssr-1", "0").ServerVersion("v1.0.1").Result(), getterError: nil, want: clientVersion + "Server:\n\tVersion: v1.0.1\n", }, @@ -82,36 +83,37 @@ func TestPrintVersion(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { var ( + kbClient = fake.NewFakeClientWithScheme(scheme.Scheme) serverStatusGetter = new(mockServerStatusGetter) buf = new(bytes.Buffer) - client = fake.NewSimpleClientset() ) defer serverStatusGetter.AssertExpectations(t) // GetServerStatus should only be called when clientOnly = false if !tc.clientOnly { - serverStatusGetter.On("GetServerStatus", client.VeleroV1()).Return(tc.serverStatusRequest, tc.getterError) + serverStatusGetter.On("GetServerStatus", kbClient).Return(tc.serverStatusRequest, tc.getterError) } - printVersion(buf, tc.clientOnly, client.VeleroV1(), serverStatusGetter) + printVersion(buf, tc.clientOnly, kbClient, serverStatusGetter) assert.Equal(t, tc.want, buf.String()) }) } } -// serverStatusGetter is an autogenerated mock type for the serverStatusGetter type +// mockServerStatusGetter is an autogenerated mock type for the serverStatusGetter type +// Code generated by mockery v2.2.1. type mockServerStatusGetter struct { mock.Mock } -// GetServerStatus provides a mock function with given fields: client -func (_m *mockServerStatusGetter) GetServerStatus(client v1.ServerStatusRequestsGetter) (*velerov1.ServerStatusRequest, error) { - ret := _m.Called(client) +// GetServerStatus provides a mock function with given fields: mgr +func (_m *mockServerStatusGetter) GetServerStatus(kbClient kbclient.Client) (*velerov1.ServerStatusRequest, error) { + ret := _m.Called(kbClient) var r0 *velerov1.ServerStatusRequest - if rf, ok := ret.Get(0).(func(v1.ServerStatusRequestsGetter) *velerov1.ServerStatusRequest); ok { - r0 = rf(client) + if rf, ok := ret.Get(0).(func(kbclient.Client) *velerov1.ServerStatusRequest); ok { + r0 = rf(kbClient) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*velerov1.ServerStatusRequest) @@ -119,8 +121,8 @@ func (_m *mockServerStatusGetter) GetServerStatus(client v1.ServerStatusRequests } var r1 error - if rf, ok := ret.Get(1).(func(v1.ServerStatusRequestsGetter) error); ok { - r1 = rf(client) + if rf, ok := ret.Get(1).(func(kbclient.Client) error); ok { + r1 = rf(kbClient) } else { r1 = ret.Error(1) } diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index 34d71b242..a22d52049 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -34,6 +34,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/clock" kubeerrs "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -777,31 +778,19 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string } } - serverStatusRequestControllerRunInfo := func() controllerRunInfo { - serverStatusRequestController := controller.NewServerStatusRequestController( - s.logger, - s.veleroClient.VeleroV1(), - s.sharedInformerFactory.Velero().V1().ServerStatusRequests(), - s.pluginRegistry, - ) - - return controllerRunInfo{ - controller: serverStatusRequestController, - numWorkers: defaultControllerWorkers, - } - } - enabledControllers := map[string]func() controllerRunInfo{ - BackupSyncControllerKey: backupSyncControllerRunInfo, - BackupControllerKey: backupControllerRunInfo, - ScheduleControllerKey: scheduleControllerRunInfo, - GcControllerKey: gcControllerRunInfo, - BackupDeletionControllerKey: deletionControllerRunInfo, - RestoreControllerKey: restoreControllerRunInfo, - ResticRepoControllerKey: resticRepoControllerRunInfo, - DownloadRequestControllerKey: downloadrequestControllerRunInfo, - ServerStatusRequestControllerKey: serverStatusRequestControllerRunInfo, + BackupSyncControllerKey: backupSyncControllerRunInfo, + BackupControllerKey: backupControllerRunInfo, + ScheduleControllerKey: scheduleControllerRunInfo, + GcControllerKey: gcControllerRunInfo, + BackupDeletionControllerKey: deletionControllerRunInfo, + RestoreControllerKey: restoreControllerRunInfo, + ResticRepoControllerKey: resticRepoControllerRunInfo, + DownloadRequestControllerKey: downloadrequestControllerRunInfo, } + // Note: all runtime type controllers that can be disabled are grouped separately, below: + enabledRuntimeControllers := make(map[string]struct{}) + enabledRuntimeControllers[ServerStatusRequestControllerKey] = struct{}{} if s.config.restoreOnly { s.logger.Info("Restore only mode - not starting the backup, schedule, delete-backup, or GC controllers") @@ -819,7 +808,13 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string s.logger.Infof("Disabling controller: %s", controllerName) delete(enabledControllers, controllerName) } else { - s.logger.Fatalf("Invalid value for --disable-controllers flag provided: %s. Valid values are: %s", controllerName, strings.Join(disableControllerList, ",")) + // maybe it is a runtime type controllers, so attempt to remove that + if _, ok := enabledRuntimeControllers[controllerName]; ok { + s.logger.Infof("Disabling controller: %s", controllerName) + delete(enabledRuntimeControllers, controllerName) + } else { + s.logger.Fatalf("Invalid value for --disable-controllers flag provided: %s. Valid values are: %s", controllerName, strings.Join(disableControllerList, ",")) + } } } @@ -852,20 +847,36 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string s.logger.WithField("informer", informer).Info("Informer cache synced") } - storageLocationInfo := velero.StorageLocation{ - Client: s.mgr.GetClient(), - Ctx: s.ctx, - DefaultStorageLocation: s.config.defaultBackupLocation, - DefaultStoreValidationFrequency: s.config.storeValidationFrequency, - NewPluginManager: newPluginManager, - NewBackupStore: persistence.NewObjectBackupStore, + bslr := controller.BackupStorageLocationReconciler{ + Scheme: s.mgr.GetScheme(), + StorageLocation: velero.StorageLocation{ + Client: s.mgr.GetClient(), + Ctx: s.ctx, + DefaultStorageLocation: s.config.defaultBackupLocation, + DefaultStoreValidationFrequency: s.config.storeValidationFrequency, + NewPluginManager: newPluginManager, + NewBackupStore: persistence.NewObjectBackupStore, + }, + Log: s.logger, } - if err := (&controller.BackupStorageLocationReconciler{ - Scheme: s.mgr.GetScheme(), - StorageLocation: storageLocationInfo, - Log: s.logger, - }).SetupWithManager(s.mgr); err != nil { - s.logger.Fatal(err, "unable to create controller", "controller", "BackupStorageLocation") + if err := bslr.SetupWithManager(s.mgr); err != nil { + s.logger.Fatal(err, "unable to create controller", "controller", "backup-storage-location") + } + + if _, ok := enabledRuntimeControllers[ServerStatusRequestControllerKey]; ok { + r := controller.ServerStatusRequestReconciler{ + Scheme: s.mgr.GetScheme(), + Client: s.mgr.GetClient(), + Ctx: s.ctx, + ServerStatus: velero.ServerStatus{ + PluginRegistry: s.pluginRegistry, + Clock: clock.RealClock{}, + }, + Log: s.logger, + } + if err := r.SetupWithManager(s.mgr); err != nil { + s.logger.Fatal(err, "unable to create controller", "controller", ServerStatusRequestControllerKey) + } } // TODO(2.0): presuming all controllers and resources are converted to runtime-controller diff --git a/pkg/controller/server_status_request_controller.go b/pkg/controller/server_status_request_controller.go index c02186095..97bdf5ade 100644 --- a/pkg/controller/server_status_request_controller.go +++ b/pkg/controller/server_status_request_controller.go @@ -17,104 +17,105 @@ limitations under the License. package controller import ( + "context" "time" "github.com/pkg/errors" "github.com/sirupsen/logrus" apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/client-go/tools/cache" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "github.com/vmware-tanzu/velero/internal/velero" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" - velerov1informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1" - velerov1listers "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v1" - "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt" - "github.com/vmware-tanzu/velero/pkg/serverstatusrequest" - kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" + "github.com/vmware-tanzu/velero/pkg/plugin/framework" ) -const statusRequestResyncPeriod = 5 * time.Minute +const ( + ttl = time.Minute + statusRequestResyncPeriod = 5 * time.Minute +) -type statusRequestController struct { - *genericController - - client velerov1client.ServerStatusRequestsGetter - lister velerov1listers.ServerStatusRequestLister - pluginRegistry clientmgmt.Registry - clock clock.Clock +type PluginLister interface { + // List returns all PluginIdentifiers for kind. + List(kind framework.PluginKind) []framework.PluginIdentifier } -func NewServerStatusRequestController( - logger logrus.FieldLogger, - client velerov1client.ServerStatusRequestsGetter, - informer velerov1informers.ServerStatusRequestInformer, - pluginRegistry clientmgmt.Registry, -) *statusRequestController { - c := &statusRequestController{ - genericController: newGenericController("serverstatusrequest", logger), - client: client, - lister: informer.Lister(), - pluginRegistry: pluginRegistry, +// ServerStatusRequestReconciler reconciles a ServerStatusRequest object +type ServerStatusRequestReconciler struct { + Scheme *runtime.Scheme + Client client.Client + Ctx context.Context + ServerStatus velero.ServerStatus - clock: clock.RealClock{}, - } - - c.syncHandler = c.processItem - c.resyncFunc = c.enqueueAllItems - c.resyncPeriod = statusRequestResyncPeriod - - informer.Informer().AddEventHandler( - cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - req := obj.(*velerov1api.ServerStatusRequest) - key := kubeutil.NamespaceAndName(req) - - c.logger.WithFields(logrus.Fields{ - "serverStatusRequest": key, - "phase": req.Status.Phase, - }).Debug("Enqueueing server status request") - - c.queue.Add(key) - }, - }, - ) - - return c + Log logrus.FieldLogger } -func (c *statusRequestController) processItem(key string) error { - log := c.logger.WithField("key", key) - - log.Debug("Running processItem") - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return errors.Wrap(err, "error splitting queue key") - } +// +kubebuilder:rbac:groups=velero.io,resources=serverstatusrequests,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=velero.io,resources=serverstatusrequests/status,verbs=get;update;patch +func (r *ServerStatusRequestReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithFields(logrus.Fields{ + "controller": "serverstatusrequest", + "serverStatusRequest": req.NamespacedName, + }) + // Fetch the ServerStatusRequest instance. log.Debug("Getting ServerStatusRequest") - req, err := c.lister.ServerStatusRequests(ns).Get(name) - // server status request no longer exists - if apierrors.IsNotFound(err) { - log.WithError(err).Debug("ServerStatusRequest not found") - return nil - } - if err != nil { - return errors.Wrap(err, "error getting ServerStatusRequest") + statusRequest := &velerov1api.ServerStatusRequest{} + if err := r.Client.Get(r.Ctx, req.NamespacedName, statusRequest); err != nil { + if apierrors.IsNotFound(err) { + log.WithError(err).Error("ServerStatusRequest not found") + return ctrl.Result{}, nil + } + + log.WithError(err).Error("Error getting ServerStatusRequest") + // Error reading the object - requeue the request. + return ctrl.Result{}, err } - return serverstatusrequest.Process(req.DeepCopy(), c.client, c.pluginRegistry, c.clock, log) + log = r.Log.WithFields(logrus.Fields{ + "controller": "serverstatusrequest", + "serverStatusRequest": req.NamespacedName, + "phase": statusRequest.Status.Phase, + }) + + switch statusRequest.Status.Phase { + case "", velerov1api.ServerStatusRequestPhaseNew: + log.Info("Processing new ServerStatusRequest") + + if err := r.ServerStatus.PatchStatusProcessed(r.Client, statusRequest, r.Ctx); err != nil { + log.WithError(err).Error("Unable to update the request") + return ctrl.Result{RequeueAfter: statusRequestResyncPeriod}, err + } + case velerov1api.ServerStatusRequestPhaseProcessed: + log.Debug("Checking whether ServerStatusRequest has expired") + expiration := statusRequest.Status.ProcessedTimestamp.Add(ttl) + if expiration.After(r.ServerStatus.Clock.Now()) { + log.Debug("ServerStatusRequest has not expired") + return ctrl.Result{RequeueAfter: statusRequestResyncPeriod}, nil + } + + log.Debug("ServerStatusRequest has expired, deleting it") + if err := r.Client.Delete(r.Ctx, statusRequest); err != nil { + log.WithError(err).Error("Unable to delete the request") + return ctrl.Result{}, nil + } + default: + return ctrl.Result{}, errors.New("unexpected ServerStatusRequest phase") + } + + // Requeue is mostly to handle deleting any expired status requests that were not + // deleted as part of the normal client flow for whatever reason. + return ctrl.Result{RequeueAfter: statusRequestResyncPeriod}, nil } -func (c *statusRequestController) enqueueAllItems() { - items, err := c.lister.List(labels.Everything()) - if err != nil { - c.logger.WithError(err).Error("Error listing all server status requests") - return - } - - for _, req := range items { - c.enqueue(req) - } +func (r *ServerStatusRequestReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&velerov1api.ServerStatusRequest{}). + WithOptions(controller.Options{ + MaxConcurrentReconciles: 10, + }). + Complete(r) } diff --git a/pkg/controller/server_status_request_controller_test.go b/pkg/controller/server_status_request_controller_test.go new file mode 100644 index 000000000..668ccf672 --- /dev/null +++ b/pkg/controller/server_status_request_controller_test.go @@ -0,0 +1,270 @@ +/* +Copyright 2020 the Velero contributors. + +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 controller + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/clock" + "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/vmware-tanzu/velero/internal/velero" + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/builder" + "github.com/vmware-tanzu/velero/pkg/buildinfo" + "github.com/vmware-tanzu/velero/pkg/plugin/framework" + velerotest "github.com/vmware-tanzu/velero/pkg/test" +) + +func statusRequestBuilder(resourceVersion string) *builder.ServerStatusRequestBuilder { + return builder.ForServerStatusRequest(velerov1api.DefaultNamespace, "sr-1", resourceVersion) +} + +var _ = Describe("Server Status Request Reconciler", func() { + BeforeEach(func() {}) + AfterEach(func() {}) + + It("Should successfully patch a server status request object status phase", func() { + // now will be used to set the fake clock's time; capture + // it here so it can be referenced in the test case defs. + now, err := time.Parse(time.RFC1123, time.RFC1123) + Expect(err).To(BeNil()) + now = now.Local() + + tests := []struct { + req *velerov1api.ServerStatusRequest + reqPluginLister *fakePluginLister + expected *velerov1api.ServerStatusRequest + expectedRequeue ctrl.Result + expectedErrMsg string + }{ + { + // server status request with phase=empty will be processed + req: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + reqPluginLister: &fakePluginLister{ + plugins: []framework.PluginIdentifier{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }, + }, + expected: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseProcessed). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + expectedRequeue: ctrl.Result{Requeue: false, RequeueAfter: statusRequestResyncPeriod}, + }, + { + // server status request with phase=new will be processed + req: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseNew). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + reqPluginLister: &fakePluginLister{ + plugins: []framework.PluginIdentifier{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }, + }, + expected: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseProcessed). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + expectedRequeue: ctrl.Result{Requeue: false, RequeueAfter: statusRequestResyncPeriod}, + }, + { + // server status request with phase=Processed does not get deleted if not expired + req: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseProcessed). + ProcessedTimestamp(now). // not yet expired + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myotherown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + reqPluginLister: &fakePluginLister{ + plugins: []framework.PluginIdentifier{ + { + Name: "custom.io/myotherown", + Kind: "VolumeSnapshotter", + }, + }, + }, + expected: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseProcessed). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + expectedRequeue: ctrl.Result{Requeue: false, RequeueAfter: statusRequestResyncPeriod}, + }, + { + // server status request with phase=Processed gets deleted if expire + req: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase(velerov1api.ServerStatusRequestPhaseProcessed). + ProcessedTimestamp(now.Add(-61 * time.Second)). // expired + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myotherown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + reqPluginLister: &fakePluginLister{ + plugins: []framework.PluginIdentifier{ + { + Name: "custom.io/myotherown", + Kind: "VolumeSnapshotter", + }, + }, + }, + expected: nil, + expectedRequeue: ctrl.Result{Requeue: false, RequeueAfter: statusRequestResyncPeriod}, + }, + { + // server status request with invalid phase returns an error and does not requeue + req: statusRequestBuilder("1"). + ServerVersion(buildinfo.Version). + Phase("an-invalid-phase"). + ProcessedTimestamp(now). + Plugins([]velerov1api.PluginInfo{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }). + Result(), + reqPluginLister: &fakePluginLister{ + plugins: []framework.PluginIdentifier{ + { + Name: "custom.io/myown", + Kind: "VolumeSnapshotter", + }, + }, + }, + expectedErrMsg: "unexpected ServerStatusRequest phase", + expectedRequeue: ctrl.Result{Requeue: false, RequeueAfter: 0}, + }, + } + + for _, test := range tests { + // Setup reconciler + Expect(velerov1api.AddToScheme(scheme.Scheme)).To(Succeed()) + serverStatusInfo := velero.ServerStatus{ + PluginRegistry: test.reqPluginLister, + Clock: clock.NewFakeClock(now), + } + r := ServerStatusRequestReconciler{ + Client: fake.NewFakeClientWithScheme(scheme.Scheme, test.req), + ServerStatus: serverStatusInfo, + Ctx: context.Background(), + Log: velerotest.NewLogger(), + } + + actualResult, err := r.Reconcile(ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: velerov1api.DefaultNamespace, + Name: test.req.Name, + }, + }) + + Expect(actualResult).To(BeEquivalentTo(test.expectedRequeue)) + if test.expectedErrMsg == "" { + Expect(err).To(BeNil()) + } else { + Expect(err.Error()).To(BeEquivalentTo(test.expectedErrMsg)) + return + } + + instance := &velerov1api.ServerStatusRequest{} + err = r.Client.Get(ctx, kbclient.ObjectKey{Name: test.req.Name, Namespace: test.req.Namespace}, instance) + + // Assertions + if test.expected == nil { + Expect(apierrors.IsNotFound(err)).To(BeTrue()) + } else { + Expect(err).To(BeNil()) + Eventually(instance.Status.Phase == test.expected.Status.Phase, timeout).Should(BeTrue()) + } + } + }) +}) + +type fakePluginLister struct { + plugins []framework.PluginIdentifier +} + +func (l *fakePluginLister) List(kind framework.PluginKind) []framework.PluginIdentifier { + var plugins []framework.PluginIdentifier + for _, plugin := range l.plugins { + if plugin.Kind == kind { + plugins = append(plugins, plugin) + } + } + + return plugins +} diff --git a/pkg/serverstatusrequest/process.go b/pkg/serverstatusrequest/process.go deleted file mode 100644 index 76c57b038..000000000 --- a/pkg/serverstatusrequest/process.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2018 the Velero contributors. - -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 serverstatusrequest - -import ( - "context" - "encoding/json" - "time" - - jsonpatch "github.com/evanphx/json-patch" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/clock" - - velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - "github.com/vmware-tanzu/velero/pkg/buildinfo" - velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" - "github.com/vmware-tanzu/velero/pkg/plugin/framework" -) - -const ttl = time.Minute - -type PluginLister interface { - // List returns all PluginIdentifiers for kind. - List(kind framework.PluginKind) []framework.PluginIdentifier -} - -// Process fills out new ServerStatusRequest objects and deletes processed ones -// that have expired. -func Process(req *velerov1api.ServerStatusRequest, client velerov1client.ServerStatusRequestsGetter, pluginLister PluginLister, clock clock.Clock, log logrus.FieldLogger) error { - switch req.Status.Phase { - case "", velerov1api.ServerStatusRequestPhaseNew: - log.Info("Processing new ServerStatusRequest") - return errors.WithStack(patch(client, req, func(req *velerov1api.ServerStatusRequest) { - req.Status.ServerVersion = buildinfo.Version - req.Status.ProcessedTimestamp = &metav1.Time{Time: clock.Now()} - req.Status.Phase = velerov1api.ServerStatusRequestPhaseProcessed - req.Status.Plugins = plugins(pluginLister) - })) - case velerov1api.ServerStatusRequestPhaseProcessed: - log.Debug("Checking whether ServerStatusRequest has expired") - expiration := req.Status.ProcessedTimestamp.Add(ttl) - if expiration.After(clock.Now()) { - log.Debug("ServerStatusRequest has not expired") - return nil - } - - log.Debug("ServerStatusRequest has expired, deleting it") - if err := client.ServerStatusRequests(req.Namespace).Delete(context.TODO(), req.Name, metav1.DeleteOptions{}); err != nil { - return errors.WithStack(err) - } - - return nil - default: - return errors.Errorf("unexpected ServerStatusRequest phase %q", req.Status.Phase) - } -} - -func patch(client velerov1client.ServerStatusRequestsGetter, req *velerov1api.ServerStatusRequest, updateFunc func(*velerov1api.ServerStatusRequest)) error { - originalJSON, err := json.Marshal(req) - if err != nil { - return errors.WithStack(err) - } - - updateFunc(req) - - updatedJSON, err := json.Marshal(req) - if err != nil { - return errors.WithStack(err) - } - - patchBytes, err := jsonpatch.CreateMergePatch(originalJSON, updatedJSON) - if err != nil { - return errors.WithStack(err) - } - - _, err = client.ServerStatusRequests(req.Namespace).Patch(context.TODO(), req.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}) - if err != nil { - return errors.WithStack(err) - } - - return nil -} - -func plugins(pluginLister PluginLister) []velerov1api.PluginInfo { - var plugins []velerov1api.PluginInfo - for _, v := range framework.AllPluginKinds() { - list := pluginLister.List(v) - for _, plugin := range list { - pluginInfo := velerov1api.PluginInfo{ - Name: plugin.Name, - Kind: plugin.Kind.String(), - } - plugins = append(plugins, pluginInfo) - } - } - return plugins -}