diff --git a/LICENSES/vendor/github.com/Azure/azure-kusto-go/LICENSE b/LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE similarity index 86% rename from LICENSES/vendor/github.com/Azure/azure-kusto-go/LICENSE rename to LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE index b6af6844da..8081f4fc69 100644 --- a/LICENSES/vendor/github.com/Azure/azure-kusto-go/LICENSE +++ b/LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE @@ -1,4 +1,4 @@ -= vendor/github.com/Azure/azure-kusto-go licensed under: = += vendor/github.com/Azure/azure-kusto-go/azkustodata licensed under: = Copyright 2020 Microsoft Corporation @@ -13,4 +13,4 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -= vendor/github.com/Azure/azure-kusto-go/LICENSE 36453fb77bf995e1a92d5dd7fb118eee += vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE 36453fb77bf995e1a92d5dd7fb118eee diff --git a/LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE b/LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE new file mode 100644 index 0000000000..15d71e0d83 --- /dev/null +++ b/LICENSES/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE @@ -0,0 +1,16 @@ += vendor/github.com/Azure/azure-kusto-go/azkustoingest licensed under: = + +Copyright 2020 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. += vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE 36453fb77bf995e1a92d5dd7fb118eee diff --git a/LICENSES/vendor/github.com/Azure/azure-pipeline-go/LICENSE b/LICENSES/vendor/github.com/Azure/azure-pipeline-go/LICENSE deleted file mode 100644 index 570c03a216..0000000000 --- a/LICENSES/vendor/github.com/Azure/azure-pipeline-go/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -= vendor/github.com/Azure/azure-pipeline-go licensed under: = - - MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE -= vendor/github.com/Azure/azure-pipeline-go/LICENSE 261d8686a7cf1ce9570cdc99746659f8 diff --git a/LICENSES/vendor/github.com/mattn/go-ieproxy/LICENSE b/LICENSES/vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue/LICENSE similarity index 81% rename from LICENSES/vendor/github.com/mattn/go-ieproxy/LICENSE rename to LICENSES/vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue/LICENSE index 51188562fd..74f1cc6e42 100644 --- a/LICENSES/vendor/github.com/mattn/go-ieproxy/LICENSE +++ b/LICENSES/vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue/LICENSE @@ -1,10 +1,8 @@ -= vendor/github.com/mattn/go-ieproxy licensed under: = += vendor/github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue licensed under: = -MIT License +The MIT License (MIT) -Copyright (c) 2014 mattn -Copyright (c) 2017 oliverpool -Copyright (c) 2019 Adele Reed +Copyright (c) Microsoft Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -24,4 +22,4 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -= vendor/github.com/mattn/go-ieproxy/LICENSE 69c6c02bbe749fb6fcff63f4ff6b1599 += vendor/github.com/Azure/azure-sdk-for-go/LICENSE.txt 4f7454c9bcbb0acee6d9a971001befe2 diff --git a/LICENSES/vendor/github.com/Azure/azure-storage-queue-go/LICENSE b/LICENSES/vendor/github.com/Azure/azure-storage-queue-go/LICENSE deleted file mode 100644 index 42a818cef1..0000000000 --- a/LICENSES/vendor/github.com/Azure/azure-storage-queue-go/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -= vendor/github.com/Azure/azure-storage-queue-go licensed under: = - - MIT License - - Copyright (c) Microsoft Corporation. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE -= vendor/github.com/Azure/azure-storage-queue-go/LICENSE 261d8686a7cf1ce9570cdc99746659f8 diff --git a/LICENSES/vendor/github.com/Azure/go-autorest/autorest/to/LICENSE b/LICENSES/vendor/github.com/Azure/go-autorest/autorest/to/LICENSE deleted file mode 100644 index 4b1f7178d0..0000000000 --- a/LICENSES/vendor/github.com/Azure/go-autorest/autorest/to/LICENSE +++ /dev/null @@ -1,195 +0,0 @@ -= vendor/github.com/Azure/go-autorest/autorest/to licensed under: = - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2015 Microsoft Corporation - - 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. - -= vendor/github.com/Azure/go-autorest/LICENSE a250e5ac3848f2acadb5adcb9555c18b diff --git a/LICENSES/vendor/github.com/Azure/go-autorest/autorest/validation/LICENSE b/LICENSES/vendor/github.com/Azure/go-autorest/autorest/validation/LICENSE deleted file mode 100644 index 118bb29e11..0000000000 --- a/LICENSES/vendor/github.com/Azure/go-autorest/autorest/validation/LICENSE +++ /dev/null @@ -1,195 +0,0 @@ -= vendor/github.com/Azure/go-autorest/autorest/validation licensed under: = - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2015 Microsoft Corporation - - 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. - -= vendor/github.com/Azure/go-autorest/LICENSE a250e5ac3848f2acadb5adcb9555c18b diff --git a/go.mod b/go.mod index fefa19e024..355b9709c4 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.23.2 godebug winsymlink=0 require ( - github.com/Azure/azure-kusto-go v0.16.1 - github.com/Azure/azure-sdk-for-go v68.0.0+incompatible + github.com/Azure/azure-kusto-go/azkustodata v1.0.0-preview-5 + github.com/Azure/azure-kusto-go/azkustoingest v1.0.0-preview-5 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 @@ -57,7 +57,7 @@ require ( require ( cel.dev/expr v0.18.0 // indirect - github.com/Azure/azure-pipeline-go v0.2.3 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 // indirect @@ -65,14 +65,12 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/msi/armmsi v1.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 // indirect - github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect - github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 // indirect @@ -113,7 +111,6 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-ieproxy v0.0.11 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -124,7 +121,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.61.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.etcd.io/etcd/api/v3 v3.5.16 // indirect diff --git a/go.sum b/go.sum index fd2a1c490e..5463e8105d 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo= cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -github.com/Azure/azure-kusto-go v0.16.1 h1:vCBWcQghmC1qIErUUgVNWHxGhZVStu1U/hki6iBA14k= -github.com/Azure/azure-kusto-go v0.16.1/go.mod h1:9F2zvXH8B6eWzgI1S4k1ZXAIufnBZ1bv1cW1kB1n3D0= -github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= -github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= -github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +github.com/Azure/azure-kusto-go/azkustodata v1.0.0-preview-5 h1:FIjnJ9Vg/F6lDvESB2NYKIhjwaNj6mmz8QWHYaw6o+Q= +github.com/Azure/azure-kusto-go/azkustodata v1.0.0-preview-5/go.mod h1:6DsWhEvMdVf/mZS8dFUdtLrFQXnTI/SoWmDMuukXVz4= +github.com/Azure/azure-kusto-go/azkustoingest v1.0.0-preview-5 h1:A675REsEbnR/gi1cV1CKuFxFZYMrljcWs/BTfnDPOco= +github.com/Azure/azure-kusto-go/azkustoingest v1.0.0-preview-5/go.mod h1:mXzYGPwovGmz5rEvktvTb+thBzvKkZSMrtNVkJpFQQI= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= @@ -49,10 +49,10 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 h1:WLUI github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0/go.mod h1:hd8hTTIY3VmUVPRHNH7GVCHO3SHgXkJKZHReby/bnUQ= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 h1:eXnN9kaS8TiDwXjoie3hMRLuwdUBUMW9KRgOqB3mCaw= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0/go.mod h1:XIpam8wumeZ5rVMuhdDQLMfIPDf1WO3IzrCRO3e3e3o= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4= -github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe h1:HGuouUM1533rBXmMtR7qh5pYNSSjUZG90b/MgJAnb/A= -github.com/Azure/azure-storage-queue-go v0.0.0-20230531184854-c06a8eff66fe/go.mod h1:K6am8mT+5iFXgingS9LUc7TmbsW6XBw3nxaRyaMyWc8= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 h1:Be6KInmFEKV81c0pOAEbRYehLMwmmGI1exuFj248AMk= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0/go.mod h1:WCPBHsOXfBVnivScjs2ypRfimjEW0qPVLGgJkZlrIOA= +github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0 h1:lJwNFV+xYjHREUTHJKx/ZF6CJSt9znxmLw9DqSTvyRU= +github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0/go.mod h1:GfT0aGew8Qj5yiQVqOO5v7N8fanbJGyUoHqXg56qcVY= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -69,8 +69,6 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9A github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= @@ -81,8 +79,12 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 h1:gUDtaZk8het github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -91,8 +93,12 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -112,6 +118,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -120,6 +128,8 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -140,12 +150,14 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -166,6 +178,7 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -174,14 +187,17 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -196,9 +212,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo= -github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -206,12 +221,16 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= 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/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -219,6 +238,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -229,13 +249,14 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= @@ -249,6 +270,7 @@ github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8w github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -262,6 +284,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -307,6 +330,7 @@ go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qq go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= @@ -330,9 +354,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -353,7 +377,6 @@ golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -367,6 +390,7 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -375,7 +399,6 @@ golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -409,7 +432,6 @@ google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjr google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/dnaeon/go-vcr.v3 v3.2.0 h1:Rltp0Vf+Aq0u4rQXgmXgtgoRDStTnFN83cWgSGSoRzM= @@ -420,6 +442,7 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -441,6 +464,8 @@ k8s.io/component-helpers v0.32.0 h1:pQEEBmRt3pDJJX98cQvZshDgJFeKRM4YtYkMmfOlczw= k8s.io/component-helpers v0.32.0/go.mod h1:9RuClQatbClcokXOcDWSzFKQm1huIf0FzQlPRpizlMc= k8s.io/controller-manager v0.32.0 h1:tpQl1rvH4huFB6Avl1nhowZHtZoCNWqn6OYdZPl7Ybc= k8s.io/controller-manager v0.32.0/go.mod h1:JRuYnYCkKj3NgBTy+KNQKIUm/lJRoDAvGbfdEmk9LhY= +k8s.io/cri-api v0.32.0/go.mod h1:DCzMuTh2padoinefWME0G678Mc3QFbLMF2vEweGzBAI= +k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kms v0.32.0 h1:jwOfunHIrcdYl5FRcA+uUKKtg6qiqoPCwmS2T3XTYL4= diff --git a/pkg/provider/azure_instances_test.go b/pkg/provider/azure_instances_test.go index 9afb3640a9..dd6bc43bf4 100644 --- a/pkg/provider/azure_instances_test.go +++ b/pkg/provider/azure_instances_test.go @@ -30,7 +30,6 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2022-08-01/compute" "github.com/stretchr/testify/assert" @@ -928,7 +927,7 @@ func TestInstanceMetadata(t *testing.T) { expectedMetadata := cloudprovider.InstanceMetadata{ ProviderID: "azure:///subscriptions/subscription/resourceGroups/rg/providers/Microsoft.Compute/VirtualMachines/vm", - InstanceType: string(compute.BasicA0), + InstanceType: string(armcompute.VirtualMachineSizeTypesBasicA0), NodeAddresses: []v1.NodeAddress{ { Type: v1.NodeInternalIP, diff --git a/tests/e2e/utils/kustoIngest.go b/tests/e2e/utils/kustoIngest.go index 315c071bd8..ad40d47e13 100644 --- a/tests/e2e/utils/kustoIngest.go +++ b/tests/e2e/utils/kustoIngest.go @@ -24,8 +24,9 @@ import ( "os" "time" - "github.com/Azure/azure-kusto-go/kusto" - "github.com/Azure/azure-kusto-go/kusto/ingest" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustoingest" + "k8s.io/klog/v2" ) @@ -70,14 +71,8 @@ func KustoIngest(passed bool, labelFilter, clusterType, junitReportPath string) return err } - kustoConnStrBuilder := kusto.NewConnectionStringBuilder(ingestionURI).WithAadAppKey(clientID, clientSecret, tenantID) - kustoClient, err := kusto.New(kustoConnStrBuilder) - if err != nil { - return fmt.Errorf("failed to new kusto connection string builder: %w", err) - } - defer kustoClient.Close() - - in, err := ingest.New(kustoClient, database, table) + kustoConnStrBuilder := azkustodata.NewConnectionStringBuilder(ingestionURI).WithAadAppKey(clientID, clientSecret, tenantID) + in, err := azkustoingest.New(kustoConnStrBuilder, azkustoingest.WithDefaultDatabase(database), azkustoingest.WithDefaultTable(table)) if err != nil { return fmt.Errorf("failed to new ingestion: %w", err) } diff --git a/vendor/github.com/Azure/azure-kusto-go/LICENSE b/vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/LICENSE rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/LICENSE diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/client_details.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/client_details.go similarity index 96% rename from vendor/github.com/Azure/azure-kusto-go/kusto/client_details.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/client_details.go index b25b3eeb89..1385ce09f0 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/client_details.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/client_details.go @@ -1,9 +1,9 @@ -package kusto +package azkustodata import ( "fmt" - "github.com/Azure/azure-kusto-go/kusto/internal/version" - "github.com/Azure/azure-kusto-go/kusto/utils" + "github.com/Azure/azure-kusto-go/azkustodata/internal/version" + "github.com/Azure/azure-kusto-go/azkustodata/utils" "os" "os/user" "path/filepath" diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/cloudinfo.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/cloudinfo.go similarity index 96% rename from vendor/github.com/Azure/azure-kusto-go/kusto/cloudinfo.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/cloudinfo.go index 6e1a9ecf11..44492ee4db 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/cloudinfo.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/cloudinfo.go @@ -1,10 +1,10 @@ -package kusto +package azkustodata import ( "encoding/json" "fmt" - kustoErrors "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/utils" + kustoErrors "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/utils" "io" "net/http" "net/url" diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/conn.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/conn.go similarity index 75% rename from vendor/github.com/Azure/azure-kusto-go/kusto/conn.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/conn.go index 3b9d2439eb..26414c6934 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/conn.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/conn.go @@ -1,4 +1,4 @@ -package kusto +package azkustodata // Conn.go holds the connection to the Kusto server and provides methods to do queries // and receive Kusto frames back. @@ -16,12 +16,9 @@ import ( "sync/atomic" "unicode" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/internal/frames" - v1 "github.com/Azure/azure-kusto-go/kusto/internal/frames/v1" - v2 "github.com/Azure/azure-kusto-go/kusto/internal/frames/v2" - "github.com/Azure/azure-kusto-go/kusto/internal/response" - truestedEndpoints "github.com/Azure/azure-kusto-go/kusto/trustedendpoints" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/internal/response" + truestedEndpoints "github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints" "github.com/google/uuid" ) @@ -31,6 +28,8 @@ var bufferPool = sync.Pool{ }, } +// TODO - inspect this. Do we need this? can this be simplified? + // Conn provides connectivity to a Kusto instance. type Conn struct { endpoint string @@ -83,30 +82,13 @@ type connOptions struct { queryOptions *queryOptions } -// query makes a query for the purpose of extracting data from Kusto. Context can be used to set -// a timeout or cancel the query. Queries cannot take longer than 5 minutes. -func (c *Conn) query(ctx context.Context, db string, query Statement, options *queryOptions) (execResp, error) { - if strings.HasPrefix(strings.TrimSpace(query.String()), ".") { - return execResp{}, errors.ES(errors.OpQuery, errors.KClientArgs, "a Stmt to Query() cannot begin with a period(.), only Mgmt() calls can do that").SetNoRetry() - } - - return c.execute(ctx, execQuery, db, query, *options.requestProperties) -} - -// mgmt is used to do management queries to Kusto. -func (c *Conn) mgmt(ctx context.Context, db string, query Statement, options *queryOptions) (execResp, error) { - return c.execute(ctx, execMgmt, db, query, *options.requestProperties) -} - -func (c *Conn) queryToJson(ctx context.Context, db string, query Statement, options *queryOptions) (string, error) { - _, _, _, body, e := c.doRequest(ctx, execQuery, db, query, *options.requestProperties) +func (c *Conn) rawQuery(ctx context.Context, callType callType, db string, query Statement, options *queryOptions) (io.ReadCloser, error) { + _, _, _, body, e := c.doRequest(ctx, int(callType), db, query, *options.requestProperties) if e != nil { - return "", e + return nil, e } - defer body.Close() - all, e := io.ReadAll(body) - return string(all), e + return body, nil } const ( @@ -114,33 +96,6 @@ const ( execMgmt = 2 ) -type execResp struct { - reqHeader http.Header - respHeader http.Header - frameCh chan frames.Frame -} - -func (c *Conn) execute(ctx context.Context, execType int, db string, query Statement, properties requestProperties) (execResp, error) { - op, reqHeader, respHeader, body, e := c.doRequest(ctx, execType, db, query, properties) - if e != nil { - return execResp{}, e - } - - var dec frames.Decoder - switch execType { - case execMgmt: - dec = &v1.Decoder{} - case execQuery: - dec = &v2.Decoder{} - default: - return execResp{}, errors.ES(op, errors.KInternal, "unknown execution type was %v", execType).SetNoRetry() - } - - frameCh := dec.Decode(ctx, body, op) - - return execResp{reqHeader: reqHeader, respHeader: respHeader, frameCh: frameCh}, nil -} - func (c *Conn) doRequest(ctx context.Context, execType int, db string, query Statement, properties requestProperties) (errors.Op, http.Header, http.Header, io.ReadCloser, error) { var op errors.Op diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/conn_streaming_ingest.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/conn_streaming_ingest.go similarity index 96% rename from vendor/github.com/Azure/azure-kusto-go/kusto/conn_streaming_ingest.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/conn_streaming_ingest.go index 9be2f3bedf..ce0f71b858 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/conn_streaming_ingest.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/conn_streaming_ingest.go @@ -1,14 +1,13 @@ -package kusto +package azkustodata import ( "context" "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/google/uuid" "io" "net/url" "time" - - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/google/uuid" ) type DataFormatForStreaming interface { diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/doc.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/doc.go new file mode 100644 index 0000000000..31ce3eb761 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/doc.go @@ -0,0 +1,71 @@ +/* +Package azkustodata provides a client for querying and managing data in Azure Data Explorer (Kusto) clusters. + +The package supports running both Kusto Query Language (KQL) queries and management commands, with built-in support for +streaming responses and mapping results to Go structs. + +To start using this package, create an instance of the Client, passing in a connection string built using the +NewConnectionStringBuilder() function. The Client can be authenticated using various methods from the Azure Identity package. + +Example For Querying the Kusto cluster: + + kcsb := azkustodata.NewConnectionStringBuilder("https://help.kusto.windows.net/").WithDefaultAzureCredential() + client, err := azkustodata.New(kcsb) + + if err != nil { + panic(err) + } + + defer client.Close() // Always close the client when done. + + ctx := context.Background() + dataset, err := client.IterativeQuery(ctx, "Samples", kql.New("PopulationData")) + + // Don't forget to close the dataset when you're done. + defer dataset.Close() + + primaryResult := <-dataset.Tables() // The first table in the dataset will be the primary results. + + // Make sure to check for errors. + if primaryResult.Err() != nil { + panic("add error handling") + } + + for rowResult := range primaryResult.Table().Rows() { + if rowResult.Err() != nil { + panic("add error handling") + } + row := rowResult.Row() + + fmt.Println(row) // As a convenience, printing a *table.Row will output csv + // or Access the columns directly + fmt.Println(row.IntByName("EventId")) + fmt.Println(row.StringByIndex(1)) + } + +Example for Management/Administration commands: + + kcsb := azkustodata.NewConnectionStringBuilder("https://help.kusto.windows.net/").WithDefaultAzureCredential() + client, err := azkustodata.New(kcsb) + + if err != nil { + panic(err) + } + + defer client.Close() // Always close the client when done. + + ctx := context.Background() + dataset, err := client.Mgmt(ctx, "Samples", kql.New(".show tables")) + + table := dataset.Tables()[0] + + // convert the table to a struct + structs, err := query.ToStructs[myStruct](table) + +To handle results, the package provides utilities to directly stream rows, fetch tables into memory, and map results to structs. + +For complete documentation, please visit: +https://github.com/Azure/azure-kusto-go +https://pkg.go.dev/github.com/Azure/azure-kusto-go/azkustodata +*/ +package azkustodata diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/errors.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/errors.go similarity index 75% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/errors.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/errors.go index 6b25f78d75..b56aeb5cb8 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/errors.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/errors.go @@ -40,6 +40,7 @@ const ( OpFileIngest Op = 5 // OpFileIngest indicates the client is making a file ingestion call. OpCloudInfo Op = 6 // OpCloudInfo indicates an error fetching data from the cloud metadata. OpTokenProvider Op = 7 // OpTokenProvider indicates an error creating a token provider. + OpTableAccess Op = 8 // OpTableAccess indicates an error accessing a table. ) // Kind field classifies the error as one of a set of standard conditions. @@ -47,16 +48,19 @@ type Kind uint16 //go:generate stringer -type Kind const ( - KOther Kind = 0 // Other indicates the error kind was not defined. - KIO Kind = 1 // External I/O error such as network failure. - KInternal Kind = 2 // Internal error or inconsistency at the server. - KDBNotExist Kind = 3 // Database does not exist. - KTimeout Kind = 4 // The request timed out. - KLimitsExceeded Kind = 5 // The request was too large. - KClientArgs Kind = 6 // The client supplied some type of arg(s) that were invalid. - KHTTPError Kind = 7 // The HTTP client gave some type of error. This wraps the http library error types. - KBlobstore Kind = 8 // The Blobstore API returned some type of error. - KLocalFileSystem Kind = 9 // The local fileystem had an error. This could be permission, missing file, etc.... + KOther Kind = 0 // Other indicates the error kind was not defined. + KIO Kind = 1 // External I/O error such as network failure. + KInternal Kind = 2 // Internal error or inconsistency at the server. + KDBNotExist Kind = 3 // Database does not exist. + KTimeout Kind = 4 // The request timed out. + KLimitsExceeded Kind = 5 // The request was too large. + KClientArgs Kind = 6 // The client supplied some type of arg(s) that were invalid. + KHTTPError Kind = 7 // The HTTP client gave some type of error. This wraps the http library error types. + KBlobstore Kind = 8 // The Blobstore API returned some type of error. + KLocalFileSystem Kind = 9 // The local fileystem had an error. This could be permission, missing file, etc...., + KWrongTableKind Kind = 10 // The kind of the table requested did not match the kind of the table. + KWrongColumnType Kind = 11 // The type of the column requested did not match the type of the column. + KFailedToParse Kind = 12 // The client failed to parse the value. ) // Error is a core error for the Kusto package. @@ -223,7 +227,12 @@ func ES(o Op, k Kind, s string, args ...interface{}) *Error { // HTTP constructs an *Error from an *http.Response and a prefix to the error message. func HTTP(o Op, status string, statusCode int, body io.ReadCloser, prefix string) *HttpError { - defer body.Close() + defer func(body io.ReadCloser) { + err := body.Close() + if err != nil { + // TODO: Handle this when we have a logger. + } + }(body) bodyBytes, err := io.ReadAll(body) if err != nil { bodyBytes = []byte(fmt.Sprintf("Failed to read body: %v", err)) @@ -295,86 +304,6 @@ func W(inner error, outer error) *Error { return o } -// OneToErr translates what we think is a Kusto OneApiError into an Error. If we don't recognize it, we return nil. -// This tries to wrap the internal errors, but the errors that are generated are some type of early draft of OneApiError, -// not the current spec. Because the errors we see don't conform to the current OneAPIError spec, had to take guesses on -// what we will receive. The spec says we shouldn't get a list of errors, but we do(we should get an embedded error). -// So I'm taking the guess that these are supposed to be wrapped errors. -func OneToErr(m map[string]interface{}, op Op) *Error { - if m == nil { - return nil - } - - if _, ok := m["OneApiErrors"]; ok { - var topErr *Error - if oneErrors, ok := m["OneApiErrors"].([]interface{}); ok { - var bottomErr *Error - for _, oneErr := range oneErrors { - if errMap, ok := oneErr.(map[string]interface{}); ok { - e := oneToErr(errMap, bottomErr, op) - if e == nil { - continue - } - if topErr == nil { - topErr = e - bottomErr = e - continue - } - bottomErr = e - } - } - return topErr - } - } - return nil -} - -func oneToErr(m map[string]interface{}, err *Error, op Op) *Error { - errJSON, ok := m["error"] - if !ok { - return nil - } - errMap, ok := errJSON.(map[string]interface{}) - if !ok { - return nil - } - - var msg string - msgInter, ok := errMap["message"] - if !ok { - return nil - } - - if msg, ok = msgInter.(string); !ok { - return nil - } - - var code string - - codeInter, ok := errMap["code"] - if ok { - codeStr, ok := codeInter.(string) - if ok { - code = codeStr - } - } - - var kind Kind - switch code { - case "LimitsExceeded": - kind = KLimitsExceeded - msg = msg + ";See https://docs.microsoft.com/en-us/azure/kusto/concepts/querylimits" - } - - if err == nil { - return ES(op, kind, msg) - } - - err = W(ES(op, kind, msg), err) - - return err -} - func (e *HttpError) IsThrottled() bool { return e != nil && (e.StatusCode == http.StatusTooManyRequests) } @@ -404,7 +333,7 @@ type CombinedError struct { Errors []error } -func (c CombinedError) Error() string { +func (c *CombinedError) Error() string { result := "" for _, err := range c.Errors { result += fmt.Sprintf("'%s';", err.Error()) @@ -412,6 +341,51 @@ func (c CombinedError) Error() string { return result } -func GetCombinedError(errs ...error) *CombinedError { - return &CombinedError{Errors: errs} +func NewCombinedError() *CombinedError { + return &CombinedError{ + Errors: []error{}, + } +} + +func (c *CombinedError) AddError(e error) bool { + if e == nil { + return false + } + + var c2 *CombinedError + if errors.As(e, &c2) { + for _, err := range c2.Errors { + if c.AddError(err) { + return true + } + } + return false + } + + for _, err := range c.Errors { + if err.Error() == e.Error() { + return false + } + } + c.Errors = append(c.Errors, e) + return true +} + +func (c *CombinedError) Unwrap() error { + if len(c.Errors) == 0 { + return nil + } + if len(c.Errors) == 1 { + return c.Errors[0] + } + + return c +} + +func CombineErrors(errs ...error) error { + combined := NewCombinedError() + for _, err := range errs { + combined.AddError(err) + } + return combined.Unwrap() } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/kind_string.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/kind_string.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/kind_string.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/kind_string.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/op_string.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/op_string.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/errors/op_string.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/errors/op_string.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/response/response.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/response/response.go similarity index 95% rename from vendor/github.com/Azure/azure-kusto-go/kusto/internal/response/response.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/response/response.go index 1c0ecc66d6..b9f8818e5d 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/response/response.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/response/response.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - "github.com/Azure/azure-kusto-go/kusto/data/errors" + "github.com/Azure/azure-kusto-go/azkustodata/errors" ) type originalCloser struct { diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/version/version.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/version/version.go similarity index 84% rename from vendor/github.com/Azure/azure-kusto-go/kusto/internal/version/version.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/version/version.go index 41b70be3ee..cf741a1e49 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/version/version.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/internal/version/version.go @@ -2,4 +2,4 @@ package version // Kusto is the version of this client package that is communicated to the server. -const Kusto = "0.16.1" +const Kusto = "1.0.0-preview-5" diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/kcsb.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kcsb.go similarity index 88% rename from vendor/github.com/Azure/azure-kusto-go/kusto/kcsb.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/kcsb.go index e7b922348a..bae6bccc63 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/kcsb.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kcsb.go @@ -1,4 +1,4 @@ -package kusto +package azkustodata import ( "fmt" @@ -6,7 +6,7 @@ import ( "strconv" "strings" - kustoErrors "github.com/Azure/azure-kusto-go/kusto/data/errors" + kustoErrors "github.com/Azure/azure-kusto-go/azkustodata/errors" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" ) @@ -28,14 +28,17 @@ type ConnectionStringBuilder struct { MsiAuthentication bool WorkloadAuthentication bool FederationTokenFilePath string - ManagedServiceIdentity string - InteractiveLogin bool - RedirectURL string - DefaultAuth bool - ClientOptions *azcore.ClientOptions - ApplicationForTracing string - UserForTracing string - TokenCredential azcore.TokenCredential + // Deprecated: Use ManagedServiceIdentityClientId or ManagedServiceIdentityResourceId instead + ManagedServiceIdentity string + ManagedServiceIdentityClientId string + ManagedServiceIdentityResourceId string + InteractiveLogin bool + RedirectURL string + DefaultAuth bool + ClientOptions *azcore.ClientOptions + ApplicationForTracing string + UserForTracing string + TokenCredential azcore.TokenCredential } const ( @@ -164,6 +167,8 @@ func (kcsb *ConnectionStringBuilder) resetConnectionString() { kcsb.MsiAuthentication = false kcsb.WorkloadAuthentication = false kcsb.ManagedServiceIdentity = "" + kcsb.ManagedServiceIdentityClientId = "" + kcsb.ManagedServiceIdentityResourceId = "" kcsb.InteractiveLogin = false kcsb.RedirectURL = "" kcsb.ClientOptions = nil @@ -183,8 +188,8 @@ func (kcsb *ConnectionStringBuilder) WithAadUserPassAuth(uname string, pswrd str return kcsb } -// WitAadUserToken Creates a Kusto Connection string builder that will authenticate with AAD user token -func (kcsb *ConnectionStringBuilder) WitAadUserToken(usertoken string) *ConnectionStringBuilder { +// WithAadUserToken Creates a Kusto Connection string builder that will authenticate with AAD user token +func (kcsb *ConnectionStringBuilder) WithAadUserToken(usertoken string) *ConnectionStringBuilder { requireNonEmpty(dataSource, kcsb.DataSource) requireNonEmpty(userToken, usertoken) kcsb.resetConnectionString() @@ -254,13 +259,30 @@ func (kcsb *ConnectionStringBuilder) WithAzCli() *ConnectionStringBuilder { return kcsb } +// Deprecated: use WithUserManagedIdentityClientId or WithUserManagedIdentityResourceId instead // WithUserManagedIdentity Creates a Kusto Connection string builder that will authenticate with AAD application, using // an application token obtained from a Microsoft Service Identity endpoint using user assigned id. func (kcsb *ConnectionStringBuilder) WithUserManagedIdentity(clientID string) *ConnectionStringBuilder { + return kcsb.WithUserAssignedIdentityClientId(clientID) +} + +// WithUserAssignedIdentityClientId Creates a Kusto Connection string builder that will authenticate with AAD application, using +// an application token obtained from a Microsoft Service Identity endpoint using user assigned id. +func (kcsb *ConnectionStringBuilder) WithUserAssignedIdentityClientId(clientID string) *ConnectionStringBuilder { + requireNonEmpty(dataSource, kcsb.DataSource) + kcsb.resetConnectionString() + kcsb.MsiAuthentication = true + kcsb.ManagedServiceIdentityClientId = clientID + return kcsb +} + +// WithUserAssignedIdentityResourceId Creates a Kusto Connection string builder that will authenticate with AAD application, using +// an application token obtained from a Microsoft Service Identity endpoint using an MSI's resourceID. +func (kcsb *ConnectionStringBuilder) WithUserAssignedIdentityResourceId(resourceID string) *ConnectionStringBuilder { requireNonEmpty(dataSource, kcsb.DataSource) kcsb.resetConnectionString() kcsb.MsiAuthentication = true - kcsb.ManagedServiceIdentity = clientID + kcsb.ManagedServiceIdentityResourceId = resourceID return kcsb } @@ -410,8 +432,17 @@ func (kcsb *ConnectionStringBuilder) newTokenProvider() (*TokenProvider, error) case kcsb.MsiAuthentication: init = func(ci *CloudInfo, cliOpts *azcore.ClientOptions, appClientId string) (azcore.TokenCredential, error) { opts := &azidentity.ManagedIdentityCredentialOptions{ClientOptions: *cliOpts} + // legacy kcsb.ManagedServiceIdentity field takes precedence over + // new kcsb.ManagedServiceIdentityClientId field which takes precedence over + // new kcsb.ManagedServiceIdentityResourceId field + // if no client id is provided, the logic falls back to set up + // the system assigned identity if !isEmpty(kcsb.ManagedServiceIdentity) { opts.ID = azidentity.ClientID(kcsb.ManagedServiceIdentity) + } else if !isEmpty(kcsb.ManagedServiceIdentityClientId) { + opts.ID = azidentity.ClientID(kcsb.ManagedServiceIdentityClientId) + } else if !isEmpty(kcsb.ManagedServiceIdentityResourceId) { + opts.ID = azidentity.ResourceID(kcsb.ManagedServiceIdentityResourceId) } cred, err := azidentity.NewManagedIdentityCredential(opts) diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/kql/builder.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/builder.go similarity index 60% rename from vendor/github.com/Azure/azure-kusto-go/kusto/kql/builder.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/builder.go index cc90e7f67d..3a120ba384 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/kql/builder.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/builder.go @@ -3,7 +3,7 @@ package kql import ( "errors" "fmt" - "github.com/Azure/azure-kusto-go/kusto/data/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" "github.com/google/uuid" "github.com/shopspring/decimal" "strings" @@ -43,6 +43,11 @@ func (b *Builder) addBase(value fmt.Stringer) *Builder { return b } +func (b *Builder) AddValue(v value.Kusto) *Builder { + b.builder.WriteString(QuoteValue(v)) + return b +} + // AddUnsafe enables unsafe actions on a Builder - adds a string as is, no validation checking or escaping. // This turns off safety features that could allow a service client to compromise your data store. // USE AT YOUR OWN RISK! @@ -55,44 +60,48 @@ func (b *Builder) AddLiteral(value stringConstant) *Builder { return b.addBase(value) } -func (b *Builder) AddBool(value bool) *Builder { - return b.addBase(newValue(value, types.Bool)) +func (b *Builder) AddBool(v bool) *Builder { + return b.AddValue(value.NewBool(v)) +} + +func (b *Builder) AddDateTime(v time.Time) *Builder { + return b.AddValue(value.NewDateTime(v)) } -func (b *Builder) AddDateTime(value time.Time) *Builder { - return b.addBase(newValue(value, types.DateTime)) +func (b *Builder) AddDynamic(v interface{}) *Builder { + return b.AddValue(value.DynamicFromInterface(v)) } -func (b *Builder) AddDynamic(value interface{}) *Builder { - return b.addBase(newValue(value, types.Dynamic)) +func (b *Builder) AddSerializedDynamic(v []byte) *Builder { + return b.AddValue(value.NewDynamic(v)) } -func (b *Builder) AddGUID(value uuid.UUID) *Builder { - return b.addBase(newValue(value, types.GUID)) +func (b *Builder) AddGUID(v uuid.UUID) *Builder { + return b.AddValue(value.NewGUID(v)) } -func (b *Builder) AddInt(value int32) *Builder { - return b.addBase(newValue(value, types.Int)) +func (b *Builder) AddInt(v int32) *Builder { + return b.AddValue(value.NewInt(v)) } -func (b *Builder) AddLong(value int64) *Builder { - return b.addBase(newValue(value, types.Long)) +func (b *Builder) AddLong(v int64) *Builder { + return b.AddValue(value.NewLong(v)) } -func (b *Builder) AddReal(value float64) *Builder { - return b.addBase(newValue(value, types.Real)) +func (b *Builder) AddReal(v float64) *Builder { + return b.AddValue(value.NewReal(v)) } -func (b *Builder) AddString(value string) *Builder { - return b.addBase(newValue(value, types.String)) +func (b *Builder) AddString(v string) *Builder { + return b.AddValue(value.NewString(v)) } -func (b *Builder) AddTimespan(value time.Duration) *Builder { - return b.addBase(newValue(value, types.Timespan)) +func (b *Builder) AddTimespan(v time.Duration) *Builder { + return b.AddValue(value.NewTimespan(v)) } -func (b *Builder) AddDecimal(value decimal.Decimal) *Builder { - return b.addBase(newValue(value, types.Decimal)) +func (b *Builder) AddDecimal(v decimal.Decimal) *Builder { + return b.AddValue(value.NewDecimal(v)) } func (b *Builder) GetParameters() (map[string]string, error) { diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/kql/identifier.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/identifier.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/kql/identifier.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/identifier.go diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/query_parameters.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/query_parameters.go new file mode 100644 index 0000000000..6f632c3df7 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/query_parameters.go @@ -0,0 +1,111 @@ +package kql + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/value" + "github.com/google/uuid" + "github.com/shopspring/decimal" + "strings" + "time" +) + +type Parameters struct { + parameters map[string]value.Kusto +} + +func NewParameters() *Parameters { + return &Parameters{parameters: make(map[string]value.Kusto)} +} + +func (q *Parameters) Count() int { + return len(q.parameters) +} +func (q *Parameters) AddValue(key string, v value.Kusto) *Parameters { + if RequiresQuoting(key) { + panic("Invalid parameter values. make sure to adhere to KQL entity name conventions and escaping rules.") + } + q.parameters[key] = v + return q +} + +func (q *Parameters) AddBool(key string, v bool) *Parameters { + return q.AddValue(key, value.NewBool(v)) +} + +func (q *Parameters) AddDateTime(key string, v time.Time) *Parameters { + return q.AddValue(key, value.NewDateTime(v)) +} + +func (q *Parameters) AddDynamic(key string, v interface{}) *Parameters { + return q.AddValue(key, value.DynamicFromInterface(v)) +} + +func (q *Parameters) AddSerializedDynamic(key string, v []byte) *Parameters { + return q.AddValue(key, value.NewDynamic(v)) +} + +func (q *Parameters) AddGUID(key string, v uuid.UUID) *Parameters { + return q.AddValue(key, value.NewGUID(v)) +} + +func (q *Parameters) AddInt(key string, v int32) *Parameters { + return q.AddValue(key, value.NewInt(v)) +} + +func (q *Parameters) AddLong(key string, v int64) *Parameters { + return q.AddValue(key, value.NewLong(v)) +} + +func (q *Parameters) AddReal(key string, v float64) *Parameters { + return q.AddValue(key, value.NewReal(v)) +} + +func (q *Parameters) AddString(key string, v string) *Parameters { + return q.AddValue(key, value.NewString(v)) +} + +func (q *Parameters) AddTimespan(key string, v time.Duration) *Parameters { + return q.AddValue(key, value.NewTimespan(v)) +} + +func (q *Parameters) AddDecimal(key string, v decimal.Decimal) *Parameters { + return q.AddValue(key, value.NewDecimal(v)) +} + +func (q *Parameters) ToDeclarationString() string { + const ( + declare = "declare query_parameters(" + closeStmt = ");" + ) + var build = strings.Builder{} + + if len(q.parameters) == 0 { + return "" + } + + build.WriteString(declare) + + comma := len(q.parameters) + for key, paramVals := range q.parameters { + build.WriteString(key) + build.WriteString(":") + build.WriteString(string(paramVals.GetType())) + if comma > 1 { + build.WriteString(", ") + } + comma-- + } + build.WriteString(closeStmt) + return build.String() +} +func (q *Parameters) ToParameterCollection() map[string]string { + var parameters = make(map[string]string) + for key, paramVals := range q.parameters { + parameters[key] = QuoteValue(paramVals) + } + return parameters +} + +// Reset resets the parameters map +func (q *Parameters) Reset() { + q.parameters = make(map[string]value.Kusto) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/kql/string_utils.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/string_utils.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/kql/string_utils.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/string_utils.go diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/value.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/value.go new file mode 100644 index 0000000000..f954868b6a --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kql/value.go @@ -0,0 +1,43 @@ +package kql + +import ( + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "github.com/google/uuid" + "github.com/shopspring/decimal" + "time" +) + +func QuoteValue(v value.Kusto) string { + val := v.GetValue() + t := v.GetType() + if val == nil { + return fmt.Sprintf("%v(null)", t) + } + + switch t { + case types.String: + return QuoteString(v.String(), false) + case types.DateTime: + val = FormatDatetime(*val.(*time.Time)) + case types.Timespan: + val = FormatTimespan(*val.(*time.Duration)) + case types.Dynamic: + val = string(val.([]byte)) + case types.Bool: + val = *val.(*bool) + case types.Int: + val = *val.(*int32) + case types.Long: + val = *val.(*int64) + case types.Real: + val = *val.(*float64) + case types.Decimal: + val = *val.(*decimal.Decimal) + case types.GUID: + val = *val.(*uuid.UUID) + } + + return fmt.Sprintf("%v(%v)", t, val) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/kusto.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kusto.go new file mode 100644 index 0000000000..7b544b9ed3 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/kusto.go @@ -0,0 +1,300 @@ +package azkustodata + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata/kql" + "github.com/Azure/azure-kusto-go/azkustodata/query" + v1 "github.com/Azure/azure-kusto-go/azkustodata/query/v1" + queryv2 "github.com/Azure/azure-kusto-go/azkustodata/query/v2" + "io" + "net/http" + "time" + + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +type Statement = *kql.Builder + +// queryer provides for getting a stream of Kusto frames. Exists to allow fake Kusto streams in tests. +type queryer interface { + io.Closer + rawQuery(ctx context.Context, callType callType, db string, query Statement, options *queryOptions) (io.ReadCloser, error) +} + +// Authorization provides the TokenProvider needed to acquire the auth token. +type Authorization struct { + // Token provider that can be used to get the access token. + TokenProvider *TokenProvider +} + +const ( + defaultMgmtTimeout = time.Hour + defaultQueryTimeout = 4 * time.Minute + clientServerDelta = 30 * time.Second +) + +// Client is a client to a Kusto instance. +type Client struct { + conn queryer + endpoint string + auth Authorization + http *http.Client + clientDetails *ClientDetails +} + +// Option is an optional argument type for New(). +type Option func(c *Client) + +// New returns a new Client. +func New(kcsb *ConnectionStringBuilder, options ...Option) (*Client, error) { + tkp, err := kcsb.newTokenProvider() + if err != nil { + return nil, err + } + auth := &Authorization{ + TokenProvider: tkp, + } + endpoint := kcsb.DataSource + + client := &Client{auth: *auth, endpoint: endpoint, clientDetails: NewClientDetails(kcsb.ApplicationForTracing, kcsb.UserForTracing)} + for _, o := range options { + o(client) + } + + if client.http == nil { + client.http = &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + } + + conn, err := NewConn(endpoint, *auth, client.http, client.clientDetails) + if err != nil { + return nil, err + } + client.conn = conn + + return client, nil +} + +func WithHttpClient(client *http.Client) Option { + return func(c *Client) { + c.http = client + } +} + +// QueryOption is an option type for a call to Query(). +type QueryOption func(q *queryOptions) error + +// Auth returns the Authorization passed to New(). +func (c *Client) Auth() Authorization { + return c.auth +} + +// Endpoint returns the endpoint passed to New(). +func (c *Client) Endpoint() string { + return c.endpoint +} + +type callType int8 + +const ( + queryCall = 1 + mgmtCall = 2 +) + +func (c *Client) Mgmt(ctx context.Context, db string, kqlQuery Statement, options ...QueryOption) (v1.Dataset, error) { + ctx, cancel := contextSetup(ctx) + + opQuery := errors.OpMgmt + call := mgmtCall + opts, err := setQueryOptions(ctx, opQuery, kqlQuery, call, options...) + if err != nil { + return nil, err + } + + conn, err := c.getConn(callType(call), connOptions{queryOptions: opts}) + if err != nil { + return nil, err + } + + res, err := conn.rawQuery(ctx, callType(call), db, kqlQuery, opts) + + if err != nil { + cancel() + return nil, err + } + + return v1.NewDatasetFromReader(ctx, opQuery, res) +} + +func (c *Client) Query(ctx context.Context, db string, kqlQuery Statement, options ...QueryOption) (query.Dataset, error) { + ds, err := c.IterativeQuery(ctx, db, kqlQuery, options...) + if err != nil { + return nil, err + } + + return ds.ToDataset() +} + +func (c *Client) IterativeQuery(ctx context.Context, db string, kqlQuery Statement, options ...QueryOption) (query.IterativeDataset, error) { + options = append(options, V2NewlinesBetweenFrames()) + options = append(options, V2FragmentPrimaryTables()) + options = append(options, ResultsErrorReportingPlacement(ResultsErrorReportingPlacementEndOfTable)) + + opts, res, err := c.rawV2(ctx, db, kqlQuery, options) + if err != nil { + return nil, err + } + + frameCapacity := queryv2.DefaultIoCapacity + if opts.v2IoCapacity != -1 { + frameCapacity = opts.v2IoCapacity + } + + rowCapacity := queryv2.DefaultRowCapacity + if opts.v2RowCapacity != -1 { + rowCapacity = opts.v2RowCapacity + } + + fragmentCapacity := queryv2.DefaultTableCapacity + if opts.v2TableCapacity != -1 { + fragmentCapacity = opts.v2TableCapacity + } + + return queryv2.NewIterativeDataset(ctx, res, frameCapacity, rowCapacity, fragmentCapacity) +} + +func (c *Client) RawV2(ctx context.Context, db string, kqlQuery Statement, options []QueryOption) (io.ReadCloser, error) { + + _, res, err := c.rawV2(ctx, db, kqlQuery, options) + + return res, err + +} + +func (c *Client) rawV2(ctx context.Context, db string, kqlQuery Statement, options []QueryOption) (*queryOptions, io.ReadCloser, error) { + ctx, cancel := contextSetup(ctx) + opQuery := errors.OpQuery + opts, err := setQueryOptions(ctx, opQuery, kqlQuery, queryCall, options...) + if err != nil { + return nil, nil, err + } + + conn, err := c.getConn(queryCall, connOptions{queryOptions: opts}) + if err != nil { + return nil, nil, err + } + + res, err := conn.rawQuery(ctx, queryCall, db, kqlQuery, opts) + + if err != nil { + cancel() + return nil, nil, err + } + return opts, res, nil +} + +func (c *Client) QueryToJson(ctx context.Context, db string, query Statement, options ...QueryOption) (string, error) { + _, res, err := c.rawV2(ctx, db, query, options) + if err != nil { + return "", err + } + + all, err := io.ReadAll(res) + if err != nil { + return "", err + } + + return string(all), nil +} + +func setQueryOptions(ctx context.Context, op errors.Op, query Statement, queryType int, options ...QueryOption) (*queryOptions, error) { + opt := &queryOptions{ + requestProperties: &requestProperties{ + Options: map[string]interface{}{}, + }, + v2IoCapacity: -1, + v2RowCapacity: -1, + v2TableCapacity: -1, + } + + for _, o := range options { + if err := o(opt); err != nil { + return nil, errors.ES(op, errors.KClientArgs, "QueryValues in the the Stmt were incorrect: %s", err).SetNoRetry() + } + } + + CalculateTimeout(ctx, opt, queryType) + + if query.SupportsInlineParameters() { + if opt.requestProperties.QueryParameters.Count() != 0 { + return nil, errors.ES(op, errors.KClientArgs, "kusto.Stmt does not support the QueryParameters option. Construct your query using `kql.New`").SetNoRetry() + } + params, err := query.GetParameters() + if err != nil { + return nil, errors.ES(op, errors.KClientArgs, "Parameter validation error: %s", err).SetNoRetry() + } + + opt.requestProperties.Parameters = params + } + return opt, nil +} + +func CalculateTimeout(ctx context.Context, opt *queryOptions, queryType int) { + // If the user has specified a timeout, use that. + if val, ok := opt.requestProperties.Options[NoRequestTimeoutValue]; ok && val.(bool) { + return + } + if _, ok := opt.requestProperties.Options[ServerTimeoutValue]; ok { + return + } + + // Otherwise use the context deadline, if it exists. If it doesn't, use the default timeout. + if deadline, ok := ctx.Deadline(); ok { + opt.requestProperties.Options[ServerTimeoutValue] = deadline.Sub(time.Now()) + return + } + + var timeout time.Duration + switch queryType { + case queryCall: + timeout = defaultQueryTimeout + case mgmtCall: + timeout = defaultMgmtTimeout + } + opt.requestProperties.Options[ServerTimeoutValue] = timeout + clientServerDelta +} + +func (c *Client) getConn(callType callType, options connOptions) (queryer, error) { + switch callType { + case queryCall: + return c.conn, nil + case mgmtCall: + delete(options.queryOptions.requestProperties.Options, "results_progressive_enabled") + return c.conn, nil + default: + return nil, errors.ES(errors.OpServConn, errors.KInternal, "an unknown calltype was passed to getConn()") + } +} + +func contextSetup(ctx context.Context) (context.Context, context.CancelFunc) { + return context.WithCancel(ctx) +} + +func (c *Client) HttpClient() *http.Client { + return c.http +} + +func (c *Client) ClientDetails() *ClientDetails { + return c.clientDetails +} + +func (c *Client) Close() error { + var err error + if c.conn != nil { + err = c.conn.Close() + } + return err +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column.go new file mode 100644 index 0000000000..146bdacb02 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column.go @@ -0,0 +1,15 @@ +package query + +import "github.com/Azure/azure-kusto-go/azkustodata/types" + +// Column represents a column in a table. +type Column interface { + // Ordinal returns the column's index in the table. + Index() int + // Name returns the column's name. + Name() string + // Type returns the column's kusto data type. + Type() types.Column +} + +type Columns []Column diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column_impl.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column_impl.go new file mode 100644 index 0000000000..fe2fefad13 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/column_impl.go @@ -0,0 +1,32 @@ +package query + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/types" +) + +// column is a basic implementation of Column, to be used by specific implementations. +type column struct { + index int + name string + kustoType types.Column +} + +func (c column) Index() int { + return c.index +} + +func (c column) Name() string { + return c.name +} + +func (c column) Type() types.Column { + return c.kustoType +} + +func NewColumn(ordinal int, name string, kustoType types.Column) Column { + return &column{ + index: ordinal, + name: name, + kustoType: kustoType, + } +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset.go new file mode 100644 index 0000000000..b79fd8ee63 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset.go @@ -0,0 +1,29 @@ +package query + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +// BaseDataset represents a result from kusto - a set of tables with metadata +// This basic interface is implemented by all dataset types - both v1 and v2 +// for specific +type BaseDataset interface { + Context() context.Context + Op() errors.Op + + PrimaryResultKind() string +} + +type Dataset interface { + BaseDataset + Tables() []Table +} + +// IterativeDataset represents an iterative result from kusto - where the tables are streamed as they are received from the service. +type IterativeDataset interface { + BaseDataset + Tables() <-chan TableResult + ToDataset() (Dataset, error) + Close() error +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset_impl.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset_impl.go new file mode 100644 index 0000000000..7e87e504e5 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/dataset_impl.go @@ -0,0 +1,49 @@ +package query + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +// baseDataset is a basic implementation of BaseDataset, to be used by specific implementations. +type baseDataset struct { + ctx context.Context + op errors.Op + primaryResultsKind string +} + +func (d *baseDataset) Context() context.Context { + return d.ctx +} + +func (d *baseDataset) Op() errors.Op { + return d.op +} + +func (d *baseDataset) PrimaryResultKind() string { + return d.primaryResultsKind +} + +func NewBaseDataset(ctx context.Context, op errors.Op, primaryResultsKind string) BaseDataset { + return &baseDataset{ + ctx: ctx, + op: op, + primaryResultsKind: primaryResultsKind, + } +} + +type dataset struct { + BaseDataset + tables []Table +} + +func NewDataset(base BaseDataset, tables []Table) Dataset { + return &dataset{ + BaseDataset: base, + tables: tables, + } +} + +func (d *dataset) Tables() []Table { + return d.tables +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/from_kusto.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/from_kusto.go new file mode 100644 index 0000000000..beaec3d935 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/from_kusto.go @@ -0,0 +1,74 @@ +package query + +import ( + kustoErrors "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "reflect" + "strings" + "sync" +) + +type fieldMap struct { + colNameToFieldName map[string]string +} + +var typeMapper = map[reflect.Type]fieldMap{} +var typeMapperLock = sync.RWMutex{} + +// decodeToStruct takes a list of columns and a row to decode into "p" which will be a pointer +// to a struct (enforce in the decoder). +func decodeToStruct(cols []Column, row value.Values, p interface{}) error { + t := reflect.TypeOf(p) + v := reflect.ValueOf(p) + fields := newFields(t) + + for i, col := range cols { + if err := fields.convert(col, row[i], v); err != nil { + return err + } + } + return nil +} + +// newFields takes in the Columns from our row and the reflect.Type of our *struct. +func newFields(ptr reflect.Type) fieldMap { + typeMapperLock.RLock() + f, ok := typeMapper[ptr] + typeMapperLock.RUnlock() + if ok { + return f + } else { + typeMapperLock.Lock() + defer typeMapperLock.Unlock() + nFields := fieldMap{colNameToFieldName: make(map[string]string, ptr.Elem().NumField())} + for i := 0; i < ptr.Elem().NumField(); i++ { + field := ptr.Elem().Field(i) + if tag := field.Tag.Get("kusto"); strings.TrimSpace(tag) != "" { + nFields.colNameToFieldName[tag] = field.Name + } else { + nFields.colNameToFieldName[field.Name] = field.Name + } + } + typeMapper[ptr] = nFields + return nFields + } +} + +// convert converts a KustoValue that is for Column col into "v" reflect.Value with reflect.Type "t". +func (f fieldMap) convert(col Column, k value.Kusto, v reflect.Value) error { + fieldName, ok := f.colNameToFieldName[col.Name()] + if !ok { + return nil + } + + if fieldName == "-" { + return nil + } + + err := k.Convert(v.Elem().FieldByName(fieldName)) + if err != nil { + return kustoErrors.ES(kustoErrors.OpTableAccess, kustoErrors.KWrongColumnType, "column %s could not store in struct.%s: %s", col.Name(), fieldName, err.Error()) + } + + return nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row.go new file mode 100644 index 0000000000..3ade08dea0 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row.go @@ -0,0 +1,58 @@ +package query + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/value" + "github.com/google/uuid" + "github.com/shopspring/decimal" + "time" +) + +// Row is an interface that represents a row in a table. +// It provides methods to access and manipulate the data in the row. +type Row interface { + // Index returns the index of the row. + Index() int + + // Columns returns the columns of the table that the row belongs to. + Columns() Columns + + // Values returns all the values in the row. + Values() value.Values + + // Value returns the value at the specified index. + Value(i int) (value.Kusto, error) + + ValueByColumn(c Column) (value.Kusto, error) + + // ValueByName returns the value with the specified column name. + ValueByName(name string) (value.Kusto, error) + + // ToStruct converts the row into a struct and assigns it to the provided pointer. + // It returns an error if the conversion fails. + ToStruct(p interface{}) error + + // String returns a string representation of the row. + String() string + + BoolByIndex(i int) (*bool, error) + IntByIndex(i int) (*int32, error) + LongByIndex(i int) (*int64, error) + RealByIndex(i int) (*float64, error) + DecimalByIndex(i int) (*decimal.Decimal, error) + StringByIndex(i int) (string, error) + DynamicByIndex(i int) ([]byte, error) + DateTimeByIndex(i int) (*time.Time, error) + TimespanByIndex(i int) (*time.Duration, error) + GuidByIndex(i int) (*uuid.UUID, error) + + BoolByName(name string) (*bool, error) + IntByName(name string) (*int32, error) + LongByName(name string) (*int64, error) + RealByName(name string) (*float64, error) + DecimalByName(name string) (*decimal.Decimal, error) + StringByName(name string) (string, error) + DynamicByName(name string) ([]byte, error) + DateTimeByName(name string) (*time.Time, error) + TimespanByName(name string) (*time.Duration, error) + GuidByName(name string) (*uuid.UUID, error) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_impl.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_impl.go new file mode 100644 index 0000000000..b06d5606ba --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_impl.go @@ -0,0 +1,297 @@ +package query + +import ( + "encoding/csv" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "github.com/google/uuid" + "github.com/shopspring/decimal" + "reflect" + "strings" + "time" +) + +type row struct { + columns Columns + columnByName func(string) Column + values value.Values + ordinal int +} + +func NewRow(t BaseTable, ordinal int, values value.Values) Row { + return NewRowFromParts(t.Columns(), t.ColumnByName, ordinal, values) +} + +func NewRowFromParts(c Columns, columnByName func(string) Column, ordinal int, values value.Values) Row { + return &row{ + columns: c, + columnByName: columnByName, + ordinal: ordinal, + values: values, + } +} + +func (r *row) Columns() Columns { + return r.columns +} + +func (r *row) Index() int { + return r.ordinal +} + +func (r *row) Values() value.Values { + return r.values +} + +func (r *row) Value(i int) (value.Kusto, error) { + if i < 0 || i >= len(r.values) { + return nil, errors.ES(errors.OpTableAccess, errors.KClientArgs, "index %d out of range", i) + } + + return r.values[i], nil +} + +func (r *row) ValueByColumn(c Column) (value.Kusto, error) { + return r.Value(c.Index()) +} + +func (r *row) ValueByName(name string) (value.Kusto, error) { + col := r.columnByName(name) + if col == nil { + return nil, columnNotFoundError(name) + } + return r.Value(col.Index()) +} + +// ToStruct fetches the columns in a row into the fields of a struct. p must be a pointer to struct. +// The rules for mapping a row's columns into a struct's exported fields are: +// +// 1. If a field has a `kusto: "column_name"` tag, then decode column +// 'column_name' into the field. A special case is the `column_name: "-"` +// tag, which instructs ToStruct to ignore the field during decoding. +// +// 2. Otherwise, if the name of a field matches the name of a column (ignoring case), +// decode the column into the field. +// +// Slice and pointer fields will be set to nil if the source column is a null value, and a +// non-nil value if the column is not NULL. To decode NULL values of other types, use +// one of the kusto types (Int, Long, Dynamic, ...) as the type of the destination field. +// You can check the .Valid field of those types to see if the value was set. +func (r *row) ToStruct(p interface{}) error { + // Check if p is a pointer to a struct + if t := reflect.TypeOf(p); t == nil || t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { + return errors.ES(errors.OpTableAccess, errors.KClientArgs, "type %T is not a pointer to a struct", p) + } + if len(r.Columns()) != len(r.Values()) { + return errors.ES(errors.OpTableAccess, errors.KClientArgs, "row does not have the correct number of values(%d) for the number of columns(%d)", len(r.Values()), len(r.Columns())) + } + + return decodeToStruct(r.Columns(), r.Values(), p) +} + +// String implements fmt.Stringer for a Row. This simply outputs a CSV version of the row. +func (r *row) String() string { + var line []string + for _, v := range r.Values() { + line = append(line, v.String()) + } + b := &strings.Builder{} + w := csv.NewWriter(b) + err := w.Write(line) + if err != nil { + return "" + } + w.Flush() + return b.String() +} + +func conversionError(from string, to string) error { + return errors.ES(errors.OpTableAccess, errors.KOther, "cannot convert %s to %s", from, to) +} + +func columnNotFoundError(name string) error { + return errors.ES(errors.OpTableAccess, errors.KOther, "column %s not found", name) +} + +// contains all types *bool, etc +type kustoTypeGeneric interface { + *bool | *int32 | *int64 | *float64 | *decimal.Decimal | string | interface{} | *time.Time | *time.Duration +} + +func byIndex[T kustoTypeGeneric](r *row, colType types.Column, i int, defaultValue T) (T, error) { + val, err := r.Value(i) + if err != nil { + return defaultValue, err + } + if val.GetType() != colType { + return defaultValue, conversionError(string(val.GetType()), string(colType)) + } + + return val.GetValue().(T), nil +} + +func byName[T kustoTypeGeneric](r *row, colType types.Column, name string, defaultValue T) (T, error) { + col := r.columnByName(name) + if col == nil { + return defaultValue, columnNotFoundError(name) + } + return byIndex(r, colType, col.Index(), defaultValue) +} + +func (r *row) BoolByIndex(i int) (*bool, error) { + return byIndex(r, types.Bool, i, (*bool)(nil)) +} + +func (r *row) IntByIndex(i int) (*int32, error) { + return byIndex(r, types.Int, i, (*int32)(nil)) +} + +func (r *row) LongByIndex(i int) (*int64, error) { + return byIndex(r, types.Long, i, (*int64)(nil)) +} + +func (r *row) RealByIndex(i int) (*float64, error) { + return byIndex(r, types.Real, i, (*float64)(nil)) +} + +func (r *row) DecimalByIndex(i int) (*decimal.Decimal, error) { + return byIndex(r, types.Decimal, i, (*decimal.Decimal)(nil)) +} + +func (r *row) StringByIndex(i int) (string, error) { + return byIndex(r, types.String, i, "") +} + +func (r *row) DynamicByIndex(i int) ([]byte, error) { + return byIndex[[]byte](r, types.Dynamic, i, nil) +} + +func (r *row) DateTimeByIndex(i int) (*time.Time, error) { + return byIndex(r, types.DateTime, i, (*time.Time)(nil)) +} + +func (r *row) TimespanByIndex(i int) (*time.Duration, error) { + return byIndex(r, types.Timespan, i, (*time.Duration)(nil)) +} + +func (r *row) GuidByIndex(i int) (*uuid.UUID, error) { + return byIndex(r, types.GUID, i, (*uuid.UUID)(nil)) +} + +func (r *row) BoolByName(name string) (*bool, error) { + return byName(r, types.Bool, name, (*bool)(nil)) +} + +func (r *row) IntByName(name string) (*int32, error) { + return byName(r, types.Int, name, (*int32)(nil)) +} + +func (r *row) LongByName(name string) (*int64, error) { + return byName(r, types.Long, name, (*int64)(nil)) +} + +func (r *row) RealByName(name string) (*float64, error) { + return byName(r, types.Real, name, (*float64)(nil)) +} + +func (r *row) DecimalByName(name string) (*decimal.Decimal, error) { + return byName(r, types.Decimal, name, (*decimal.Decimal)(nil)) +} + +func (r *row) StringByName(name string) (string, error) { + return byName(r, types.String, name, "") +} + +func (r *row) DynamicByName(name string) ([]byte, error) { + return byName[[]byte](r, types.Dynamic, name, nil) +} + +func (r *row) DateTimeByName(name string) (*time.Time, error) { + return byName(r, types.DateTime, name, (*time.Time)(nil)) +} + +func (r *row) TimespanByName(name string) (*time.Duration, error) { + return byName(r, types.Timespan, name, (*time.Duration)(nil)) +} + +func (r *row) GuidByName(name string) (*uuid.UUID, error) { + return byName(r, types.GUID, name, (*uuid.UUID)(nil)) +} + +// ToStructs converts a table, a non-iterative dataset or a slice of rows into a slice of structs. +// If a dataset is provided, it should contain exactly one table. +func ToStructs[T any](data interface{}) ([]T, error) { + var rows []Row + var errs error + + switch v := data.(type) { + case Table: + rows = v.Rows() + case IterativeTable: + full, err := v.ToTable() + if err != nil { + return nil, err + } + rows = full.Rows() + case []Row: + rows = v + case Row: + rows = []Row{v} + case Dataset: + tables := v.Tables() + if len(tables) == 0 { + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "dataset does not contain any tables") + } + if !tables[0].IsPrimaryResult() { + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "dataset contains no primary results") + } + rows = tables[0].Rows() + default: + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "invalid data type - expected Dataset, Table, BaseTable or []Row") + } + + if rows == nil || len(rows) == 0 { + return nil, errs + } + + out := make([]T, len(rows)) + for i, r := range rows { + if err := r.ToStruct(&out[i]); err != nil { + out = out[:i] + if len(out) == 0 { + out = nil + } + return out, err + } + } + + return out, errs +} + +type StructResult[T any] struct { + Out T + Err error +} + +func ToStructsIterative[T any](tb IterativeTable) chan StructResult[T] { + out := make(chan StructResult[T]) + + go func() { + defer close(out) + for rowResult := range tb.Rows() { + if rowResult.Err() != nil { + out <- StructResult[T]{Err: rowResult.Err()} + } else { + var s T + if err := rowResult.Row().ToStruct(&s); err != nil { + out <- StructResult[T]{Err: err} + } else { + out <- StructResult[T]{Out: s} + } + } + } + }() + + return out +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_result.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_result.go new file mode 100644 index 0000000000..ec72dc33ba --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/row_result.go @@ -0,0 +1,33 @@ +package query + +type rowResult struct { + row Row + err error +} + +func (r rowResult) Row() Row { + return r.row +} + +func (r rowResult) Err() error { + return r.err +} + +func RowResultSuccess(row Row) RowResult { + return rowResult{ + row: row, + } +} + +func RowResultError(err error) RowResult { + return rowResult{ + err: err, + } +} + +// RowResult is a single streamed row from a table. +// It can contain either a row or an error. +type RowResult interface { + Row() Row + Err() error +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table.go new file mode 100644 index 0000000000..664661493d --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table.go @@ -0,0 +1,27 @@ +package query + +import "github.com/Azure/azure-kusto-go/azkustodata/errors" + +type BaseTable interface { + Id() string + Index() int64 + Name() string + Columns() []Column + Kind() string + ColumnByName(name string) Column + Op() errors.Op + IsPrimaryResult() bool +} + +type Table interface { + BaseTable + Rows() []Row +} + +// IterativeTable is a table that returns rows one at a time. +type IterativeTable interface { + BaseTable + // Rows returns a channel that will be populated with rows as they are read. + Rows() <-chan RowResult + ToTable() (Table, error) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_impl.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_impl.go new file mode 100644 index 0000000000..306679b638 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_impl.go @@ -0,0 +1,87 @@ +package query + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +type baseTable struct { + dataSet BaseDataset + index int64 + id string + name string + kind string + columns []Column + columnsByName map[string]Column +} + +func NewBaseTable(ds BaseDataset, index int64, id string, name string, kind string, columns []Column) BaseTable { + b := &baseTable{ + dataSet: ds, + index: index, + id: id, + name: name, + kind: kind, + columns: columns, + } + b.columnsByName = make(map[string]Column) + for _, c := range columns { + b.columnsByName[c.Name()] = c + } + + return b +} + +func (t *baseTable) Id() string { + return t.id +} + +func (t *baseTable) Index() int64 { + return t.index +} + +func (t *baseTable) Name() string { + return t.name +} + +func (t *baseTable) Columns() []Column { + return t.columns +} + +func (t *baseTable) Kind() string { + return t.kind +} + +func (t *baseTable) ColumnByName(name string) Column { + if c, ok := t.columnsByName[name]; ok { + return c + } + return nil +} + +func (t *baseTable) IsPrimaryResult() bool { + return t.Kind() == t.dataSet.PrimaryResultKind() +} + +func (t *baseTable) Op() errors.Op { + set := t.dataSet + if set == nil { + return errors.OpUnknown + } + return set.Op() +} + +type table struct { + BaseTable + rows []Row +} + +func NewTable(base BaseTable, rows []Row) Table { + return &table{ + BaseTable: base, + rows: rows, + } +} + +func (t *table) Rows() []Row { + return t.rows +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_result.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_result.go new file mode 100644 index 0000000000..e9569be745 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/table_result.go @@ -0,0 +1,37 @@ +package query + +type TableResult interface { + Table() IterativeTable + Err() error +} + +// TableResult is a structure that holds the result of a table operation. +// It contains a Table and an error, if any occurred during the operation. +type tableResult struct { + // Table is the result of the operation. + table IterativeTable + // Err is the error that occurred during the operation, if any. + err error +} + +// Table returns the table that was the result of the operation. +func (t *tableResult) Table() IterativeTable { + return t.table +} + +// Err returns the error that occurred during the operation, if any. +func (t *tableResult) Err() error { + return t.err +} + +func TableResultSuccess(table IterativeTable) TableResult { + return &tableResult{ + table: table, + } +} + +func TableResultError(err error) TableResult { + return &tableResult{ + err: err, + } +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/dataset.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/dataset.go new file mode 100644 index 0000000000..8fcbb38c20 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/dataset.go @@ -0,0 +1,169 @@ +package v1 + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/google/uuid" + "io" + "time" +) + +type TableIndexRow struct { + Ordinal int64 + Kind string + Name string + Id string + PrettyName string +} + +const PrimaryResultKind = "QueryResult" + +var primaryResultIndexRow = &TableIndexRow{ + Ordinal: 0, + Kind: "QueryResult", + Name: PrimaryResultKind, + Id: "00000000-0000-0000-0000-000000000000", + PrettyName: "", +} + +type QueryStatus struct { + Timestamp time.Time + Severity int32 + SeverityName string + StatusCode int32 + StatusDescription string + Count int32 + RequestId uuid.UUID + ActivityId uuid.UUID + SubActivityId uuid.UUID + ClientActivityId string +} + +type QueryProperties struct { + Value string +} + +type dataset struct { + query.BaseDataset + results []query.Table + index []TableIndexRow + status []QueryStatus + info []QueryProperties +} + +func NewDatasetFromReader(ctx context.Context, op errors.Op, reader io.ReadCloser) (Dataset, error) { + defer reader.Close() + v1, err := decodeV1(reader) + if err != nil { + return nil, err + } + + return NewDataset(ctx, op, *v1) +} + +func NewDataset(ctx context.Context, op errors.Op, v1 V1) (Dataset, error) { + d := &dataset{ + BaseDataset: query.NewBaseDataset(ctx, op, PrimaryResultKind), + } + + if len(v1.Tables) == 0 { + return nil, errors.ES(d.Op(), errors.KInternal, "kusto query failed: no tables returned") + } + + // Special case - if there is only one table, it is the primary result + if len(v1.Tables) == 1 { + if v1.Exceptions != nil { + return nil, errors.ES(d.Op(), errors.KInternal, "exceptions: %v", v1.Exceptions) + } + + table, err := NewTable(d, &v1.Tables[0], primaryResultIndexRow) + if err != nil { + return nil, err + } + + d.results = append(d.results, table) + + return d, err + } + + // index is always the last table + lastTable := &v1.Tables[len(v1.Tables)-1] + + index, err := parseTable[TableIndexRow](lastTable, d, nil) + if err != nil { + return nil, err + } + + d.index = index + + for i, r := range index { + if r.Kind == "QueryStatus" { + queryStatus, err := parseTable[QueryStatus](&v1.Tables[i], d, &r) + if err != nil { + return nil, err + } + d.status = queryStatus + } else if r.Kind == "QueryProperties" { + queryInfo, err := parseTable[QueryProperties](&v1.Tables[i], d, &r) + if err != nil { + return nil, err + } + d.info = queryInfo + } else if r.Kind == "QueryResult" { + table, err := NewTable(d, &v1.Tables[i], &r) + if err != nil { + return nil, err + } + + d.results = append(d.results, table) + } + } + + err = nil + + if v1.Exceptions != nil { + err = errors.ES(d.Op(), errors.KInternal, "exceptions: %v", v1.Exceptions) + } + + return d, err +} + +func parseTable[T any](rawTable *RawTable, d *dataset, index *TableIndexRow) ([]T, error) { + table, err := NewTable(d, rawTable, index) + if err != nil { + return nil, err + } + + indexRows := table.Rows() + + rows, err := query.ToStructs[T](indexRows) + if err != nil { + return nil, err + } + + return rows, nil +} + +func (d *dataset) Tables() []query.Table { + return d.results +} + +func (d *dataset) Index() []TableIndexRow { + return d.index +} + +func (d *dataset) Status() []QueryStatus { + return d.status +} + +func (d *dataset) Info() []QueryProperties { + return d.info +} + +type Dataset interface { + query.Dataset + Index() []TableIndexRow + Status() []QueryStatus + Info() []QueryProperties +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/decode.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/decode.go new file mode 100644 index 0000000000..3951a1a83c --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/decode.go @@ -0,0 +1,94 @@ +package v1 + +import ( + "bufio" + "bytes" + "encoding/json" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "io" +) + +type RawRow struct { + Row []interface{} + Errors []string +} + +func newDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + // This option uses the json.Number type for all numbers, instead of float64. + // This allows us to parse numbers that are too large for a float64, like uint64 or decimal. + dec.UseNumber() + return dec +} + +// UnmarshalJSON implements the json.Unmarshaler interface, to decode a RawRow from JSON. +// It needs special handling, because the field may be a Row or a list of Errors. +func (r *RawRow) UnmarshalJSON(data []byte) error { + var row []interface{} + var errs struct { + Errors []string `json:"Exceptions"` + } + + var err error + + reader := bytes.NewReader(data) + dec := newDecoder(reader) + + if err = dec.Decode(&row); err != nil { + _, err := reader.Seek(0, io.SeekStart) + if err != nil { + return err + } + + if err = dec.Decode(&errs); err != nil { + return err + } + r.Errors = errs.Errors + r.Row = nil + return nil + } + r.Row = row + r.Errors = nil + return nil +} + +type RawColumn struct { + ColumnName string `json:"ColumnName"` + DataType string `json:"DataType"` + ColumnType string `json:"ColumnType"` +} + +type RawTable struct { + TableName string `json:"TableName"` + Columns []RawColumn `json:"Columns"` + Rows []RawRow `json:"Rows"` +} + +type V1 struct { + Tables []RawTable `json:"Tables"` + Exceptions []string `json:"Exceptions"` +} + +func decodeV1(data io.ReadCloser) (*V1, error) { + var v1 V1 + br := bufio.NewReader(data) + peek, err := br.Peek(1) + if err != nil { + return nil, err + } + if peek[0] != '{' { + all, err := io.ReadAll(br) + if err != nil { + return nil, err + } + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "Got error: %v", string(all)) + } + + dec := newDecoder(br) + err = dec.Decode(&v1) + if err != nil { + return nil, err + } + + return &v1, nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/table.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/table.go new file mode 100644 index 0000000000..38a32d6bf8 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v1/table.go @@ -0,0 +1,77 @@ +package v1 + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "strings" +) + +func NewTable(d query.BaseDataset, dt *RawTable, index *TableIndexRow) (query.Table, error) { + var id string + var kind string + var name string + var ordinal int64 + + if index != nil { + id = index.Id + kind = index.Kind + name = index.Name + ordinal = index.Ordinal + } else { + // this case exists for the index table itself + id = "" + kind = "" + name = dt.TableName + ordinal = 0 + } + + op := d.Op() + + columns := make([]query.Column, len(dt.Columns)) + + for i, c := range dt.Columns { + // ColumnType should always be available, but in rare cases there are still commands that don't provide it. + if c.ColumnType == "" { + c.ColumnType = strings.ToLower(c.DataType) + } + normal := types.NormalizeColumn(c.ColumnType) + if normal == "" { + return nil, errors.ES(op, errors.KClientArgs, "column[%d] is of type %q, which is not valid", i, c.ColumnType) + } + + columns[i] = query.NewColumn(i, c.ColumnName, normal) + } + + baseTable := query.NewBaseTable(d, ordinal, id, name, kind, columns) + + rows := make([]query.Row, 0, len(dt.Rows)) + + for i, r := range dt.Rows { + if r.Errors != nil && len(r.Errors) > 0 { + for _, e := range r.Errors { + err := errors.ES(op, errors.KInternal, "row %d has an error: %s", i, e) + return nil, err + } + } + + if r.Row == nil { + continue + } + + values := make(value.Values, len(r.Row)) + for j, v := range r.Row { + parsed := value.Default(columns[j].Type()) + if v != nil { + err := parsed.Unmarshal(v) + if err != nil { + return nil, errors.ES(op, errors.KInternal, "unable to unmarshal column %s into a %s value: %s", columns[j].Name(), columns[j].Type(), err) + } + } + values[j] = parsed + } + rows = append(rows, query.NewRowFromParts(baseTable.Columns(), baseTable.ColumnByName, i, values)) + } + return query.NewTable(baseTable, rows), nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/error_frames.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/error_frames.go new file mode 100644 index 0000000000..8b6a44501f --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/error_frames.go @@ -0,0 +1,47 @@ +package v2 + +import "fmt" + +type OneApiError struct { + ErrorMessage ErrorMessage `json:"error"` +} + +func (e *OneApiError) Error() string { + return e.String() +} + +type ErrorMessage struct { + Code string `json:"code"` + Message string `json:"message"` + Description string `json:"@message"` + Type string `json:"@type"` + Context ErrorContext `json:"@context"` + IsPermanent bool `json:"@permanent"` +} + +type ErrorContext struct { + Timestamp string `json:"timestamp"` + ServiceAlias string `json:"serviceAlias"` + MachineName string `json:"machineName"` + ProcessName string `json:"processName"` + ProcessId int `json:"processId"` + ThreadId int `json:"threadId"` + ClientRequestId string `json:"clientRequestId"` + ActivityId string `json:"activityId"` + SubActivityId string `json:"subActivityId"` + ActivityType string `json:"activityType"` + ParentActivityId string `json:"parentActivityId"` + ActivityStack string `json:"activityStack"` +} + +func (e *OneApiError) String() string { + return fmt.Sprintf("OneApiError(Error=%#v)", e.ErrorMessage) +} + +func (e *ErrorMessage) String() string { + return fmt.Sprintf("ErrorMessage(Code=%s, Message=%s, Type=%s, ErrorContext=%v, IsPermanent=%t)", e.Code, e.Message, e.Type, e.Context, e.IsPermanent) +} + +func (e *ErrorContext) String() string { + return fmt.Sprintf("ErrorContext(Timestamp=%s, ServiceAlias=%s, MachineName=%s, ProcessName=%s, ProcessId=%d, ThreadId=%d, ClientRequestId=%s, ActivityId=%s, SubActivityId=%s, ActivityType=%s, ParentActivityId=%s, ActivityStack=%s)", e.Timestamp, e.ServiceAlias, e.MachineName, e.ProcessName, e.ProcessId, e.ThreadId, e.ClientRequestId, e.ActivityId, e.SubActivityId, e.ActivityType, e.ParentActivityId, e.ActivityStack) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json.go new file mode 100644 index 0000000000..5e4e50ee9f --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json.go @@ -0,0 +1,320 @@ +package v2 + +import ( + "bytes" + "encoding/json" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "io" +) + +func newDecoder(r io.Reader) *json.Decoder { + dec := json.NewDecoder(r) + // This option uses the json.Number type for all numbers, instead of float64. + // This allows us to parse numbers that are too large for a float64, like uint64 or decimal. + dec.UseNumber() + return dec +} + +// UnmarshalJSON implements the json.Unmarshaler interface for TableFragment. +// See decodeTableFragment for further explanation. +func (t *TableFragment) UnmarshalJSON(b []byte) error { + decoder := newDecoder(bytes.NewReader(b)) + + rows, err := decodeTableFragment(b, decoder, t.Columns, t.PreviousIndex) + if err != nil { + return err + } + t.Rows = rows + + return nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface for DataTable. +// A DataTable is "just" a TableHeader and TableFragment, so we can reuse the existing functions. +func (q *DataTable) UnmarshalJSON(b []byte) error { + decoder := newDecoder(bytes.NewReader(b)) + + err := decodeHeader(decoder, &q.Header, DataTableFrameType) + if err != nil { + return err + } + + rows, err := decodeTableFragment(b, decoder, q.Header.Columns, 0) + if err != nil { + return err + } + q.Rows = rows + + return nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface for DataSetHeader. +// We need to decode this manually to set the correct Columns, in order to save on allocations later on. +func (t *TableHeader) UnmarshalJSON(b []byte) error { + decoder := newDecoder(bytes.NewReader(b)) + + err := decodeHeader(decoder, t, TableHeaderFrameType) + if err != nil { + return err + } + + return nil +} + +// decodeHeader decodes the header of a table, which is the same for TableHeader and DataTable. +// It assumes the order of the properties in the JSON is fixed. +func decodeHeader(decoder *json.Decoder, t *TableHeader, frameType FrameType) error { + err := assertToken(decoder, json.Delim('{')) + if err != nil { + return err + } + + err = assertStringProperty(decoder, "FrameType", string(frameType)) + if err != nil { + return err + } + + t.TableId, err = getIntProperty(decoder, "TableId") + if err != nil { + return err + } + + t.TableKind, err = getStringProperty(decoder, "TableKind") + if err != nil { + return err + } + + t.TableName, err = getStringProperty(decoder, "TableName") + if err != nil { + return err + } + + err = assertToken(decoder, json.Token("Columns")) + if err != nil { + return err + } + + t.Columns, err = decodeColumns(decoder) + if err != nil { + return err + } + return nil +} + +// decodeTableFragment decodes the common part of a TableFragment and DataTable - the rows. +func decodeTableFragment(b []byte, decoder *json.Decoder, columns []query.Column, previousIndex int) ([]query.Row, error) { + + // skip properties until we reach the Rows property (guaranteed to be the last one) + for { + tok, err := decoder.Token() + if err != nil { + return nil, err + } + if tok == json.Token("Rows") { + break + } + } + + rows, err := decodeRows(b, decoder, columns, previousIndex) + if err != nil { + return nil, err + } + + return rows, nil +} + +// decodeColumns decodes the columns of a table from the JSON. +// Columns is an array of the form [ { "ColumnName": "name", "ColumnType": "type" }, ... ] +// 1. We need to set the ColumnIndex, which is not present in the JSON +// 2. We need to normalize the column type - in rare cases, kusto has type aliases like "date" instead of "datetime", and we need to normalize them +// 3. We need to validate the column type - if it's not a valid type, we should return an error +func decodeColumns(decoder *json.Decoder) ([]query.Column, error) { + cols := make([]query.Column, 0) + + err := assertToken(decoder, json.Delim('[')) + if err != nil { + return nil, err + } + + for i := 0; decoder.More(); i++ { + col := FrameColumn{ + ColumnIndex: i, + } + decoder.Decode(&col) + // Normalize the column type - error is an empty string + col.ColumnType = string(types.NormalizeColumn(col.ColumnType)) + if col.ColumnType == "" { + return nil, errors.ES(errors.OpTableAccess, errors.KClientArgs, "column[%d] is of type %s, which is not valid", i, col.ColumnType) + } + cols = append(cols, col) + } + + if err := assertToken(decoder, json.Delim(']')); err != nil { + return nil, err + } + + return cols, nil +} + +// decodeRows decodes the rows of a table from the JSON. +// Rows is an array of the form [ [value1, value2, ...], ... ] +// In V2 Fragmented, it's guaranteed that no errors will appear in the middle of the array, only at the end of the table. +// This function: +// 1. Creates a cached map of column names to columns for faster lookup +// 2. Decodes the rows into a slice of query.Rows +func decodeRows(b []byte, decoder *json.Decoder, cols []query.Column, startIndex int) ([]query.Row, error) { + const RowArrayAllocSize = 10 + var rows = make([]query.Row, 0, RowArrayAllocSize) + + columnsByName := make(map[string]query.Column, len(cols)) + for _, c := range cols { + columnsByName[c.Name()] = c + } + + err := assertToken(decoder, json.Delim('[')) + if err != nil { + return nil, err + } + + for i := startIndex; decoder.More(); i++ { + rowValues, err := decodeRow(b, decoder, cols) + if err != nil { + return nil, err + } + + row := query.NewRowFromParts(cols, func(name string) query.Column { return columnsByName[name] }, i, rowValues) + rows = append(rows, row) + } + + if err := assertToken(decoder, json.Delim(']')); err != nil { + return nil, err + } + return rows, nil +} + +// decodeRow decodes a single row from the JSON. +// A row is an array of values of the types from kusto, as indicated by the columns. +// For dynamic values, they can appear as nested arrays or objects, so we need to handle them. +// Otherwise, we just unmarshal the value into the correct type. +func decodeRow( + buffer []byte, + decoder *json.Decoder, + cols []query.Column) (value.Values, error) { + + err := assertToken(decoder, json.Delim('[')) + if err != nil { + return nil, err + } + + values := make([]value.Kusto, 0, len(cols)) + + field := 0 + + for ; decoder.More(); field++ { + t, err := decoder.Token() + if err != nil { + return nil, err + } + + // Handle nested values + if t == json.Delim('[') || t == json.Delim('{') { + t, err = decodeNestedValue(decoder, buffer) + if err != nil { + return nil, err + } + } + + // Create a new value of the correct type + kustoValue := value.Default(cols[field].Type()) + + // Unmarshal the value + err = kustoValue.Unmarshal(t) + if err != nil { + return nil, err + } + + values = append(values, kustoValue) + } + + err = assertToken(decoder, json.Delim(']')) + if err != nil { + return nil, err + } + + return values, nil +} + +// decodeNestedValue decodes a nested value from the JSON into a byte array inside a json.Token. +// How it works: +// 1. We need the original buffer to be able to extract the nested value from the offsets. +// 2. We get the starting offset of the nested value. +// 3. We get the next tokens, we ignore all of them unless they start a new nested value. +// 4. If we find a nested value, we increase the nesting level, and decrease it when we find the closing token. +// 5. At the end, we're guaranteed to be at the end of original the nested value. +// 6. We get the final offset of the nested value. +// 7. We return a json.Token that points to the entire byte range of the nested value. +func decodeNestedValue(decoder *json.Decoder, buffer []byte) (json.Token, error) { + nest := 1 + initialOffset := decoder.InputOffset() - 1 + for { + for decoder.More() { + t, err := decoder.Token() + if err != nil { + return nil, err + } + if t == json.Delim('[') || t == json.Delim('{') { + nest++ + } + } + t, err := decoder.Token() + if err != nil { + return nil, err + } + if t == json.Delim(']') || t == json.Delim('}') { + nest-- + } + if nest == 0 { + break + } + } + finalOffset := decoder.InputOffset() + + return json.Token(buffer[initialOffset:finalOffset]), nil +} + +// validateDataSetHeader makes sure the dataset header is valid for V2 Fragmented Query. +func validateDataSetHeader(dec *json.Decoder) error { + const HeaderVersion = "v2.0" + const NotProgressive = false + const IsFragmented = true + const ErrorReportingEndOfTable = "EndOfTable" + + if err := assertToken(dec, json.Delim('{')); err != nil { + return err + } + + if err := assertStringProperty(dec, "FrameType", json.Token(string(DataSetHeaderFrameType))); err != nil { + return err + } + + if err := assertStringProperty(dec, "IsProgressive", json.Token(NotProgressive)); err != nil { + return err + } + + if err := assertStringProperty(dec, "Version", json.Token(HeaderVersion)); err != nil { + return err + } + + if err := assertStringProperty(dec, "IsFragmented", json.Token(IsFragmented)); err != nil { + return err + } + + if err := assertStringProperty(dec, "ErrorReportingPlacement", json.Token(ErrorReportingEndOfTable)); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json_utils.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json_utils.go new file mode 100644 index 0000000000..5f056b8e2f --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/fast_json_utils.go @@ -0,0 +1,63 @@ +package v2 + +import ( + "encoding/json" + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +// assertToken asserts that the next token in the decoder is the expected token. +func assertToken(dec *json.Decoder, expected json.Token) error { + t, err := dec.Token() + if err != nil { + return err + } + if t != expected { + return errors.ES(errors.OpUnknown, errors.KInternal, "Expected %v, got %v", expected, t) + } + return nil +} + +// assertStringProperty asserts that the next token in the decoder is a string property with the expected name and value. +func assertStringProperty(dec *json.Decoder, name string, value json.Token) error { + if err := assertToken(dec, json.Token(name)); err != nil { + return err + } + if err := assertToken(dec, value); err != nil { + return err + } + return nil +} + +// getStringProperty reads a string property from the decoder, validating the name and returning the value. +func getStringProperty(dec *json.Decoder, name string) (string, error) { + if err := assertToken(dec, json.Token(name)); err != nil { + return "", err + } + t, err := dec.Token() + if err != nil { + return "", err + } + if s, ok := t.(string); ok { + return s, nil + } + return "", errors.ES(errors.OpUnknown, errors.KInternal, "Expected string, got %v", t) +} + +// getIntProperty reads an int property from the decoder, validating the name and returning the value. +func getIntProperty(dec *json.Decoder, name string) (int, error) { + if err := assertToken(dec, json.Token(name)); err != nil { + return 0, err + } + t, err := dec.Token() + if err != nil { + return 0, err + } + if s, ok := t.(json.Number); ok { + i, err := s.Int64() + if err != nil { + return 0, err + } + return int(i), nil + } + return 0, errors.ES(errors.OpUnknown, errors.KInternal, "Expected string, got %v", t) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_reader.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_reader.go new file mode 100644 index 0000000000..2a84f34913 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_reader.go @@ -0,0 +1,98 @@ +package v2 + +import ( + "bufio" + "context" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "io" +) + +// frameReader reads frame-by-frame from a Kusto response. +// It is specifically designed for the FragmentedV2 protocol: +// 1. The response is a JSON array of frames, but separated by newlines. +// 2. We convert it into a proper JsonLines format by stripping the first byte of each line. +// 3. We then read each line as a separate frame. +// 4. When we reach the end of the array, it means we have reached the end of the response, and we return io.EOF. +// 5. For every line we read, we check if the context has been cancelled, and if so, return the error. +type frameReader struct { + orig io.ReadCloser + reader bufio.Reader + ctx context.Context +} + +func newFrameReader(r io.ReadCloser, ctx context.Context) (*frameReader, error) { + br := bufio.NewReader(r) + + err := validateJsonResponse(br) + if err != nil { + return nil, err + } + + return &frameReader{orig: r, reader: *br, ctx: ctx}, nil +} + +// validateJsonResponse reads the first byte of the response to determine if it is in fact valid JSON. +// Kusto may return an error message that is not JSON, and instead will just be a plain string with an error message. +// If the first byte is not '[', then we assume it is an error message and return an error. +func validateJsonResponse(br *bufio.Reader) error { + first, err := br.Peek(1) + if err != nil { + return err + } + if len(first) == 0 { + return errors.ES(errors.OpUnknown, errors.KInternal, "No data") + } + + if first[0] != '[' { + all, err := io.ReadAll(br) + if err != nil { + return err + } + return errors.ES(errors.OpUnknown, errors.KInternal, "Got error: %v", string(all)) + } + return nil +} + +// advance reads the next frame from the response. +func (fr *frameReader) advance() ([]byte, error) { + // Check if the context has been cancelled, so we won't keep reading after the response is cancelled. + if fr.ctx.Err() != nil { + return nil, fr.ctx.Err() + } + + // Read until the end of the current line, which is the entire frame. + line, err := fr.reader.ReadBytes('\n') + if err != nil { + return nil, err + } + + // If the first character is ']', then we have reached the end of the response. + if len(line) > 0 && line[0] == ']' { + return nil, io.EOF + } + + // Trim newline + line = line[:len(line)-1] + + if len(line) > 0 && line[len(line)-1] == '\r' { + line = line[:len(line)-1] + } + + if len(line) < 2 { + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "Got EOF while reading frame") + } + + // We skip the first byte of the line, as it is a comma, or the start of the array. + if line[0] != '[' && line[0] != ',' { + return nil, errors.ES(errors.OpUnknown, errors.KInternal, "Expected comma or start array, got '%c'", line[0]) + } + + line = line[1:] + + return line, nil +} + +// Close closes the underlying reader. +func (fr *frameReader) close() error { + return fr.orig.Close() +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_utils.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_utils.go new file mode 100644 index 0000000000..2489b4f719 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frame_utils.go @@ -0,0 +1,28 @@ +package v2 + +import ( + "bytes" + "github.com/Azure/azure-kusto-go/azkustodata/errors" +) + +// peekFrameType reads the line directly, so it can be used to determine the frame type without parsing the entire frame. +// We do it by parsing the first json property, which is the frame type. +// We look for a : and then the value between two quotes. +func peekFrameType(line []byte) (FrameType, error) { + colon := bytes.IndexByte(line, ':') + + if colon == -1 { + return "", errors.ES(errors.OpUnknown, errors.KInternal, "Missing colon in frame") + } + + firstQuote := bytes.IndexByte(line[colon+1:], '"') + if firstQuote == -1 { + return "", errors.ES(errors.OpUnknown, errors.KInternal, "Missing quote in frame") + } + secondQuote := bytes.IndexByte(line[colon+1+firstQuote+1:], '"') + if secondQuote == -1 { + return "", errors.ES(errors.OpUnknown, errors.KInternal, "Missing quote in frame") + } + + return FrameType(line[colon+1+firstQuote+1 : colon+1+firstQuote+1+secondQuote]), nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frames_defs.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frames_defs.go new file mode 100644 index 0000000000..fbd3caaf08 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/frames_defs.go @@ -0,0 +1,72 @@ +package v2 + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/Azure/azure-kusto-go/azkustodata/types" +) + +type FrameColumn struct { + ColumnIndex int `json:"-"` + ColumnName string `json:"ColumnName"` + ColumnType string `json:"ColumnType"` +} + +func (f FrameColumn) Index() int { + return f.ColumnIndex +} + +func (f FrameColumn) Name() string { + return f.ColumnName +} + +func (f FrameColumn) Type() types.Column { + return types.Column(f.ColumnType) +} + +type DataTable struct { + Header TableHeader + Rows []query.Row +} + +type FrameType string + +const ( + DataSetHeaderFrameType FrameType = "DataSetHeader" + DataTableFrameType FrameType = "DataTable" + TableHeaderFrameType FrameType = "TableHeader" + TableFragmentFrameType FrameType = "TableFragment" + TableCompletionFrameType FrameType = "TableCompletion" + DataSetCompletionFrameType FrameType = "DataSetCompletion" +) + +type DataSetHeader struct { + IsProgressive bool + Version string + IsFragmented bool + ErrorReportingPlacement string +} + +type TableHeader struct { + TableId int + TableKind string + TableName string + Columns []query.Column +} + +type TableFragment struct { + Columns []query.Column + Rows []query.Row + PreviousIndex int +} + +type TableCompletion struct { + TableId int + RowCount int + OneApiErrors []OneApiError +} + +type DataSetCompletion struct { + HasErrors bool + Cancelled bool + OneApiErrors []OneApiError +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_dataset.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_dataset.go new file mode 100644 index 0000000000..5b45b3e567 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_dataset.go @@ -0,0 +1,415 @@ +package v2 + +import ( + "bytes" + "context" + "encoding/json" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "io" +) + +// DefaultIoCapacity is the default capacity of the channel that receives frames from the Kusto service. Lower capacity means less memory usage, but might cause the channel to block if the frames are not consumed fast enough. +const DefaultIoCapacity = 1 + +const DefaultRowCapacity = 1000 + +const DefaultTableCapacity = 1 + +const PrimaryResultTableKind = "PrimaryResult" + +// iterativeDataset contains the main logic of parsing a v2 dataset. +// v2 is made from a series of frames, which are decoded by turn. +type iterativeDataset struct { + query.BaseDataset + + // results is a channel that sends the parsed results as they are decoded. + results chan query.TableResult + + // rowCapacity is the amount of rows to buffer per table. + rowCapacity int + + // cancel is a function to cancel the reading of the dataset, and is called when the dataset is closed. + cancel context.CancelFunc + + // currentTable is the table that is currently being read, as it can contain multiple fragments. + currentTable *iterativeTable + + // queryProperties is a table that contains the query properties, and is sent after the primary results. + queryProperties query.IterativeTable + + // jsonData is a channel that receives the raw JSON data from the Kusto service. + jsonData chan interface{} +} + +// NewIterativeDataset creates a new IterativeDataset from a ReadCloser. +// ioCapacity is the amount of buffered rows to keep in memory. +// tableCapacity is the amount of tables to buffer. +// rowCapacity is the amount of rows to buffer per table. +func NewIterativeDataset(ctx context.Context, r io.ReadCloser, ioCapacity int, rowCapacity int, tableCapacity int) (query.IterativeDataset, error) { + + ctx, cancel := context.WithCancel(ctx) + + d := &iterativeDataset{ + BaseDataset: query.NewBaseDataset(ctx, errors.OpQuery, PrimaryResultTableKind), + results: make(chan query.TableResult, tableCapacity), + rowCapacity: rowCapacity, + cancel: cancel, + currentTable: nil, + queryProperties: nil, + jsonData: make(chan interface{}, ioCapacity), + } + + // This ctor will fail if we get a non-json response + // In this case, we want to return it immediately + reader, err := newFrameReader(r, ctx) + if err != nil { + cancel() + return nil, err + } + + // Spin up two goroutines - one to parse the dataset, and one to read the frames. + go parseRoutine(d, cancel) + go readRoutine(reader, d) + + return d, nil +} + +// readRoutine reads the frames from the Kusto service and sends them to the buffered channel. +// This is so we could keep up if the IO is faster than the consumption of the frames. +func readRoutine(reader *frameReader, d *iterativeDataset) { + loop := true + + for loop { + line, err := reader.advance() + if err != nil { + if err != io.EOF { + select { + case <-d.Context().Done(): + // When we send data, we always make sure that the context isn't cancelled, so we don't block forever. + case d.jsonData <- err: + } + } + loop = false + } else { + select { + case <-d.Context().Done(): + loop = false + case d.jsonData <- line: + } + } + } + + if err := reader.close(); err != nil { + select { + case <-d.Context().Done(): + case d.jsonData <- err: + } + } + + close(d.jsonData) +} + +// parseRoutine reads the frames from the buffered channel and parses them. +func parseRoutine(d *iterativeDataset, cancel context.CancelFunc) { + + err := readDataSet(d) + if err != nil { + select { + case d.results <- query.TableResultError(err): + case <-d.Context().Done(): + } + cancel() + } + + if d.currentTable != nil { + d.currentTable.finishTable([]OneApiError{}, err) + } + + cancel() + close(d.results) +} + +func readDataSet(d *iterativeDataset) error { + + var err error + + // The first frame should be a DataSetHeader. We don't need to save it - just validate it. + if header, _, err := nextFrame(d); err == nil { + if err = validateDataSetHeader(header); err != nil { + return err + } + } else { + return err + } + + // Next up, we expect the QueryProperties table, which is a DataTable. + // We save it and send it after the primary results. + if decoder, frameType, err := nextFrame(d); err == nil { + if frameType != DataTableFrameType { + return errors.ES(errors.OpQuery, errors.KInternal, "unexpected frame type %s, expected DataTable", frameType) + } + + if err = handleDataTable(d, decoder); err != nil { + return err + } + } else { + return err + } + + // We then iterate over the primary tables. + // If we get a TableHeader, we read the table. + // If we get a DataTable, it means we have reached QueryCompletionInformation + // If we get a DataSetCompletion, we are done. + for decoder, frameType, err := nextFrame(d); err == nil; decoder, frameType, err = nextFrame(d) { + if frameType == DataTableFrameType { + if err = handleDataTable(d, decoder); err != nil { + return err + } + continue + } + + if frameType == TableHeaderFrameType { + if err = readPrimaryTable(d, decoder); err != nil { + return err + } + continue + } + + if frameType == DataSetCompletionFrameType { + err = readDataSetCompletion(decoder) + if err != nil { + return err + } + return nil + } + + return errors.ES(errors.OpQuery, errors.KInternal, "unexpected frame type %s, expected DataTable, TableHeader, or DataSetCompletion", frameType) + } + + return err +} + +// nextFrame reads the next frame from the buffered channel. +// It doesn't parse the frame yet, but peeks the frame type to determine how to handle it. +func nextFrame(d *iterativeDataset) (*json.Decoder, FrameType, error) { + var line []byte + select { + case <-d.Context().Done(): + return nil, "", errors.ES(errors.OpQuery, errors.KInternal, "context cancelled") + case val := <-d.jsonData: + if val == nil { + return nil, "", errors.ES(errors.OpQuery, errors.KInternal, "nil value received from channel") + } + if err, ok := val.(error); ok { + return nil, "", err + } + line = val.([]byte) + } + + frameType, err := peekFrameType(line) + if err != nil { + return nil, "", err + } + + return json.NewDecoder(bytes.NewReader(line)), frameType, nil +} + +// readDataSetCompletion reads the DataSetCompletion frame, and returns any errors it might contain. +func readDataSetCompletion(dec *json.Decoder) error { + completion := DataSetCompletion{} + err := dec.Decode(&completion) + if err != nil { + return err + } + if completion.HasErrors { + return combineOneApiErrors(completion.OneApiErrors) + } + return nil +} + +// combineOneApiErrors combines multiple OneApiErrors into a single error, de-duping them if needed. +func combineOneApiErrors(errs []OneApiError) error { + c := errors.NewCombinedError() + for _, e := range errs { + c.AddError(&e) + } + return c.Unwrap() +} + +// readPrimaryTable reads a primary table from the dataset. +// A primary table consists of: +// - A TableHeader - describes the structure of the table and its columns. +// - A series of TableFragment - contains the rows of the table. +// - A TableCompletion - signals the end of the table, and contains any errors that might have occurred. +func readPrimaryTable(d *iterativeDataset, dec *json.Decoder) error { + header := TableHeader{} + err := dec.Decode(&header) + if err != nil { + return err + } + + if err := handleTableHeader(d, header); err != nil { + return err + } + + for i := 0; ; { + dec, frameType, err := nextFrame(d) + if err != nil { + return err + } + if frameType == TableFragmentFrameType { + fragment := TableFragment{Columns: header.Columns, PreviousIndex: i} + err = dec.Decode(&fragment) + if err != nil { + return err + } + i += len(fragment.Rows) + if err = handleTableFragment(d, fragment); err != nil { + return err + } + continue + } + + if frameType == TableCompletionFrameType { + completion := TableCompletion{} + err = dec.Decode(&completion) + if err != nil { + return err + } + + if err = handleTableCompletion(d, completion); err != nil { + return err + } + + break + } + + return errors.ES(errors.OpQuery, errors.KInternal, "unexpected frame type %s, expected TableFragment or TableCompletion", frameType) + } + + return nil +} + +// handleDataTable reads a DataTable frame from the dataset, which aren't iterative. +// In Fragmented V2, these are only the metadata tables - QueryProperties and QueryCompletionInformation. +func handleDataTable(d *iterativeDataset, dec *json.Decoder) error { + var dt DataTable + if err := dec.Decode(&dt); err != nil { + return err + } + + if dt.Header.TableKind == PrimaryResultTableKind { + return errors.ES(d.Op(), errors.KInternal, "received a DataTable frame for a primary result table") + } + switch dt.Header.TableKind { + case QueryPropertiesKind: + // When we get this, we want to store it and not send it to the user immediately. + // We will wait until after the primary results (when we get the QueryCompletionInformation table) and then send it. + res, err := newTable(d, dt) + if err != nil { + return err + } + d.queryProperties = iterativeWrapper{res} + case QueryCompletionInformationKind: + if d.queryProperties != nil { + d.sendTable(d.queryProperties) + } + + res, err := newTable(d, dt) + if err != nil { + return err + } + d.sendTable(iterativeWrapper{res}) + + default: + return errors.ES(d.Op(), errors.KInternal, "unknown secondary table - %s %s", dt.Header.TableName, dt.Header.TableKind) + } + + return nil +} + +func handleTableCompletion(d *iterativeDataset, tc TableCompletion) error { + if d.currentTable == nil { + return errors.ES(d.Op(), errors.KInternal, "received a TableCompletion frame while no streaming table was open") + } + if int(d.currentTable.Index()) != tc.TableId { + return errors.ES(d.Op(), errors.KInternal, "received a TableCompletion frame for table %d while table %d was open", tc.TableId, int((d.currentTable).Index())) + } + + d.currentTable.finishTable(tc.OneApiErrors, nil) + + d.currentTable = nil + + return nil +} + +func handleTableFragment(d *iterativeDataset, tf TableFragment) error { + if d.currentTable == nil { + return errors.ES(d.Op(), errors.KInternal, "received a TableFragment frame while no streaming table was open") + } + + d.currentTable.addRawRows(tf.Rows) + + return nil +} + +func handleTableHeader(d *iterativeDataset, th TableHeader) error { + if d.currentTable != nil { + return errors.ES(d.Op(), errors.KInternal, "received a TableHeader frame while a streaming table was still open") + } + + // Read the table header, set it as the current table, and send it to the user (so they can start reading rows) + + t, err := NewIterativeTable(d, th) + if err != nil { + return err + } + + d.currentTable = t.(*iterativeTable) + d.sendTable(d.currentTable) + + return nil +} + +// sendTable sends a table to results channel for the user, or cancels if the context is done. +func (d *iterativeDataset) sendTable(tb query.IterativeTable) { + select { + case <-d.Context().Done(): + return + case d.results <- query.TableResultSuccess(tb): + return + } +} + +// Tables returns a channel that sends the tables as they are parsed. +func (d *iterativeDataset) Tables() <-chan query.TableResult { + return d.results +} + +// Close closes the dataset, cancelling the context and closing the results channel. +func (d *iterativeDataset) Close() error { + d.cancel() + return nil +} + +// ToDataset reads the entire iterative dataset, converting it to a regular dataset. +func (d *iterativeDataset) ToDataset() (query.Dataset, error) { + tables := make([]query.Table, 0, len(d.results)) + + defer d.Close() + + for tb := range d.Tables() { + if tb.Err() != nil { + return nil, tb.Err() + } + + table, err := tb.Table().ToTable() + if err != nil { + return nil, err + } + tables = append(tables, table) + } + + return query.NewDataset(d, tables), nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_table.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_table.go new file mode 100644 index 0000000000..ff406bfd99 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/iterative_table.go @@ -0,0 +1,101 @@ +package v2 + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "sync/atomic" +) + +// iterativeTable represents a table that is streamed from the service. +// It is used by the iterative dataset. +// The rows are received from the service via the rawRows channel, and are parsed and sent to the rows channel. +type iterativeTable struct { + query.BaseTable + // a channel of rows and errors, exposed to the user + rows chan query.RowResult + // the number of rows in the table, updated as rows are received + rowCount atomic.Uint32 + // a context for the table + ctx context.Context +} + +// addRawRows is called by the dataset to add rows to the table. +// It will add the rows to the table, unless the table is already skipped. +func (t *iterativeTable) addRawRows(rows []query.Row) { + for _, row := range rows { + if !t.reportRow(row) { + return + } + t.rowCount.Add(1) + } +} + +// RowCount returns the current number of rows in the table. +func (t *iterativeTable) RowCount() int { + return int(t.rowCount.Load()) +} + +func (t *iterativeTable) setRowCount(rowCount int) { + t.rowCount.Store(uint32(rowCount)) +} + +func NewIterativeTable(dataset *iterativeDataset, th TableHeader) (query.IterativeTable, error) { + baseTable, err := newBaseTableFromHeader(dataset, th) + if err != nil { + return nil, err + } + + t := &iterativeTable{ + BaseTable: baseTable, + ctx: dataset.Context(), + rows: make(chan query.RowResult, dataset.rowCapacity), + } + + return t, nil +} + +func (t *iterativeTable) finishTable(errs []OneApiError, cancelError error) { + if cancelError != nil { + t.reportError(cancelError) + } else if errs != nil { + t.reportError(combineOneApiErrors(errs)) + } + close(t.rows) +} + +func (t *iterativeTable) reportRow(row query.Row) bool { + select { + case t.rows <- query.RowResultSuccess(row): + return true + case <-t.ctx.Done(): + return false + } +} + +func (t *iterativeTable) reportError(err error) bool { + select { + case t.rows <- query.RowResultError(err): + return true + case <-t.ctx.Done(): + return false + } +} + +// Rows returns a channel of rows and errors. +func (t *iterativeTable) Rows() <-chan query.RowResult { + return t.rows +} + +// ToTable reads the entire table, converting it from an iterative table to a regular table. +func (t *iterativeTable) ToTable() (query.Table, error) { + var rows []query.Row + for r := range t.rows { + if r.Err() != nil { + return nil, r.Err() + } else { + rows = append(rows, r.Row()) + } + } + + return query.NewTable(t.BaseTable, rows), nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/secondary.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/secondary.go new file mode 100644 index 0000000000..7b6d95abda --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/secondary.go @@ -0,0 +1,52 @@ +package v2 + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/google/uuid" + "time" +) + +// This file handles the parsing of the known secondary tables in v2 datasets. + +// QueryProperties represents the query properties table, which arrives before the first result. +type QueryProperties struct { + TableId int + Key string + Value map[string]interface{} +} + +// QueryCompletionInformation represents the query completion information table, which arrives after the last result. +type QueryCompletionInformation struct { + Timestamp time.Time + ClientRequestId string + ActivityId uuid.UUID + SubActivityId uuid.UUID + ParentActivityId uuid.UUID + Level int + LevelName string + StatusCode int + StatusCodeName string + EventType int + EventTypeName string + Payload string +} + +const QueryPropertiesKind = "QueryProperties" +const QueryCompletionInformationKind = "QueryCompletionInformation" + +func AsQueryProperties(table query.BaseTable) ([]QueryProperties, error) { + if table.Kind() != QueryPropertiesKind { + return nil, errors.ES(errors.OpQuery, errors.KWrongTableKind, "expected QueryProperties table, got %s", table.Kind()) + } + + return query.ToStructs[QueryProperties](table) +} + +func AsQueryCompletionInformation(table query.BaseTable) ([]QueryCompletionInformation, error) { + if table.Kind() != QueryCompletionInformationKind { + return nil, errors.ES(errors.OpQuery, errors.KWrongTableKind, "expected QueryCompletionInformation table, got %s", table.Kind()) + } + + return query.ToStructs[QueryCompletionInformation](table) +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/table.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/table.go new file mode 100644 index 0000000000..053755ff5d --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/query/v2/table.go @@ -0,0 +1,59 @@ +package v2 + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "strconv" +) + +func newBaseTable(dataset query.BaseDataset, id int, name string, kind string, columns []query.Column) (query.BaseTable, error) { + return query.NewBaseTable(dataset, int64(id), strconv.Itoa(id), name, kind, columns), nil +} + +func newBaseTableFromHeader(dataset query.BaseDataset, th TableHeader) (query.BaseTable, error) { + return newBaseTable(dataset, th.TableId, th.TableName, th.TableKind, th.Columns) +} + +func newTable(dataset query.BaseDataset, dt DataTable) (query.Table, error) { + base, err := newBaseTable(dataset, dt.Header.TableId, dt.Header.TableName, dt.Header.TableKind, dt.Header.Columns) + if err != nil { + return nil, err + } + + return query.NewTable(base, dt.Rows), nil +} + +type iterativeWrapper struct { + table query.Table +} + +func (f iterativeWrapper) Id() string { return f.table.Id() } + +func (f iterativeWrapper) Index() int64 { return f.table.Index() } + +func (f iterativeWrapper) Name() string { return f.table.Name() } + +func (f iterativeWrapper) Columns() []query.Column { return f.table.Columns() } + +func (f iterativeWrapper) Kind() string { return f.table.Kind() } + +func (f iterativeWrapper) ColumnByName(name string) query.Column { + return f.table.ColumnByName(name) +} + +func (f iterativeWrapper) Op() errors.Op { return f.table.Op() } + +func (f iterativeWrapper) IsPrimaryResult() bool { return f.table.IsPrimaryResult() } + +func (f iterativeWrapper) ToTable() (query.Table, error) { return f.table, nil } + +func (f iterativeWrapper) Rows() <-chan query.RowResult { + ch := make(chan query.RowResult, len(f.table.Rows())) + go func() { + defer close(ch) + for _, row := range f.table.Rows() { + ch <- query.RowResultSuccess(row) + } + }() + return ch +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/queryopts.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/queryopts.go similarity index 89% rename from vendor/github.com/Azure/azure-kusto-go/kusto/queryopts.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/queryopts.go index 655ff893ef..0bfb2092a4 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/queryopts.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/queryopts.go @@ -1,13 +1,13 @@ -package kusto +package azkustodata // queryopts.go holds the varying QueryOption constructors as the list is so long that // it clogs up the main kusto.go file. import ( - "github.com/Azure/azure-kusto-go/kusto/kql" + "github.com/Azure/azure-kusto-go/azkustodata/kql" "time" - "github.com/Azure/azure-kusto-go/kusto/data/value" + "github.com/Azure/azure-kusto-go/azkustodata/value" ) // requestProperties is a POD used by clients to describe specific needs from the service. @@ -25,6 +25,9 @@ type requestProperties struct { type queryOptions struct { requestProperties *requestProperties queryIngestion bool + v2IoCapacity int + v2RowCapacity int + v2TableCapacity int } const ResultsProgressiveEnabledValue = "results_progressive_enabled" @@ -75,10 +78,71 @@ const RequestReadonlyValue = "request_readonly" const RequestRemoteEntitiesDisabledValue = "request_remote_entities_disabled" const RequestSandboxedExecutionDisabledValue = "request_sandboxed_execution_disabled" const RequestUserValue = "request_user" -const TruncationMaxRecordsValue = "truncation_max_records" -const TruncationMaxSizeValue = "truncation_max_size" +const TruncationMaxRecordsValue = "truncationmaxrecords" +const TruncationMaxSizeValue = "truncationmaxsize" const ValidatePermissionsValue = "validate_permissions" +const V2NewlinesBetweenFramesValue = "results_v2_newlines_between_frames" + +const V2FragmentPrimaryTablesValue = "results_v2_fragment_primary_tables" + +const ResultsErrorReportingPlacementValue = "results_error_reporting_placement" + +const ResultsErrorReportingPlacementInData = "in_data" +const ResultsErrorReportingPlacementEndOfTable = "end_of_table" +const ResultsErrorReportingPlacementEndOfDataset = "end_of_dataset" + +// V2IoCapacity sets the size of the buffer, in frames, when reading from the network. +func V2IoCapacity(i int) QueryOption { + return func(q *queryOptions) error { + q.v2IoCapacity = i + return nil + } +} + +// V2RowCapacity sets the capacity of the buffer of data rows per table. +func V2RowCapacity(i int) QueryOption { + return func(q *queryOptions) error { + q.v2RowCapacity = i + return nil + } +} + +// V2TableCapacity sets the capacity of the buffer of data fragments in the result set. +func V2TableCapacity(i int) QueryOption { + return func(q *queryOptions) error { + q.v2TableCapacity = i + return nil + } +} + +// V2NewlinesBetweenFrames Adds new lines between frames in the results, in order to make it easier to parse them. +func V2NewlinesBetweenFrames() QueryOption { + return func(q *queryOptions) error { + q.requestProperties.Options[V2NewlinesBetweenFramesValue] = true + return nil + } +} + +// V2FragmentPrimaryTables Causes primary tables to be sent in multiple fragments, each containing a subset of the rows. +func V2FragmentPrimaryTables() QueryOption { + return func(q *queryOptions) error { + q.requestProperties.Options[V2FragmentPrimaryTablesValue] = true + return nil + } +} + +// ResultsErrorReportingPlacement Decides the placement of errors in the result set: +// 1. "in_data" (default) - errors are placed in the table or table fragment, within the array of data rows. +// 2. "end_of_table" - errors are placed in the table completion frame, after the array of data rows. Only applies to queries that are progressive or fragmented. +// 3. "end_of_dataset" - errors are placed in the dataset completion frame. +func ResultsErrorReportingPlacement(s string) QueryOption { + return func(q *queryOptions) error { + q.requestProperties.Options[ResultsErrorReportingPlacementValue] = s + return nil + } +} + // ClientRequestID sets the x-ms-client-request-id header, and can be used to identify the request in the `.show queries` output. func ClientRequestID(clientRequestID string) QueryOption { return func(q *queryOptions) error { @@ -139,7 +203,7 @@ func ResultsProgressiveEnabled() QueryOption { // ServerTimeout overrides the default request timeout. func ServerTimeout(d time.Duration) QueryOption { return func(q *queryOptions) error { - q.requestProperties.Options[ServerTimeoutValue] = value.Timespan{Valid: true, Value: d}.Marshal() + q.requestProperties.Options[ServerTimeoutValue] = value.TimespanString(d) return nil } } @@ -416,7 +480,7 @@ func QueryResultsApplyGetschema() QueryOption { // QueryResultsCacheMaxAge If positive, controls the maximum age of the cached query results the service is allowed to return func QueryResultsCacheMaxAge(d time.Duration) QueryOption { return func(q *queryOptions) error { - q.requestProperties.Options[QueryResultsCacheMaxAgeValue] = value.Timespan{Value: d, Valid: true}.Marshal() + q.requestProperties.Options[QueryResultsCacheMaxAgeValue] = value.TimespanString(d) return nil } } @@ -566,12 +630,3 @@ func ValidatePermissions() QueryOption { return nil } } - -// IngestionEndpoint will instruct the Mgmt call to connect to the ingest-[endpoint] instead of [endpoint]. -// This is not often used by end users and can only be used with a Mgmt() call. -func IngestionEndpoint() QueryOption { - return func(m *queryOptions) error { - m.queryIngestion = true - return nil - } -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/tokenprovider.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/tokenprovider.go similarity index 98% rename from vendor/github.com/Azure/azure-kusto-go/kusto/tokenprovider.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/tokenprovider.go index b1fa76498f..238669dfd7 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/tokenprovider.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/tokenprovider.go @@ -1,4 +1,4 @@ -package kusto +package azkustodata import ( "context" @@ -7,7 +7,7 @@ import ( "strings" "sync/atomic" - "github.com/Azure/azure-kusto-go/kusto/utils" + "github.com/Azure/azure-kusto-go/azkustodata/utils" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/trustedendpoints/trusted_endpoints.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints/trusted_endpoints.go similarity index 98% rename from vendor/github.com/Azure/azure-kusto-go/kusto/trustedendpoints/trusted_endpoints.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints/trusted_endpoints.go index c993496cea..9a116ba101 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/trustedendpoints/trusted_endpoints.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints/trusted_endpoints.go @@ -1,4 +1,4 @@ -package trustedendpoints +package trustedEndpoints import ( _ "embed" @@ -8,7 +8,7 @@ import ( "net/url" "strings" - "github.com/Azure/azure-kusto-go/kusto/data/errors" + "github.com/Azure/azure-kusto-go/azkustodata/errors" "github.com/samber/lo" ) diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/trustedendpoints/well_known_kusto_endpoints.json b/vendor/github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints/well_known_kusto_endpoints.json similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/trustedendpoints/well_known_kusto_endpoints.json rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/trusted_endpoints/well_known_kusto_endpoints.json diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/types/types.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/types/types.go similarity index 67% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/types/types.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/types/types.go index 389185c340..a0c60de021 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/types/types.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/types/types.go @@ -7,9 +7,8 @@ do discovery on table columns, if trying to do some type of dynamic discovery. # Column -Column represents a Column type. A user should never try to implemenet these. Instead they should use -the constants defined in this package, such as types.Bool, types.DateTime, ... Any other value that these -will not pass the Column.Valid() method and will be rejected by the API. +Column represents a Column type. A user should never try to implement these. Instead they should use +the constants defined in this package, such as types.Bool, types.DateTime. */ package types @@ -17,9 +16,14 @@ package types // For more information, please see: https://docs.microsoft.com/en-us/azure/kusto/query/scalar-data-types/ type Column string -// Valid returns true if the Column is a valid value. -func (c Column) Valid() bool { - return valid[c] +// NormalizeColumn checks if the column is a valid column type and returns the normalized column type. +// If the column is not valid, it returns an empty string. +func NormalizeColumn(c string) Column { + if mapped, ok := mappedNames[c]; ok { + return mapped + } + + return "" } // These constants represent the value type stored in a Column. @@ -46,15 +50,31 @@ const ( Decimal Column = "decimal" // We have NOT written a conversion ) -var valid = map[Column]bool{ - Bool: true, - DateTime: true, - Dynamic: true, - GUID: true, - Int: true, - Long: true, - Real: true, - String: true, - Timespan: true, - Decimal: true, +var mappedNames = map[string]Column{ + string(Bool): Bool, + "boolean": Bool, + + string(DateTime): DateTime, + "date": DateTime, + + string(Dynamic): Dynamic, + + string(GUID): GUID, + "uuid": GUID, + "uniqueid": GUID, + + string(Int): Int, + "int32": Int, + + string(Long): Long, + "int64": Long, + + string(Real): Real, + "double": Real, + + string(String): String, + string(Timespan): Timespan, + "time": Timespan, + + string(Decimal): Decimal, } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/utils/once.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/utils/once.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/utils/once.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/utils/once.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/utils/transporter.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/utils/transporter.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/utils/transporter.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/utils/transporter.go diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/bool.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/bool.go new file mode 100644 index 0000000000..05e253aac4 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/bool.go @@ -0,0 +1,59 @@ +package value + +import ( + "encoding/json" + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "reflect" +) + +// Bool represents a Kusto boolean type. Bool implements Kusto. +type Bool struct { + pointerValue[bool] +} + +func NewBool(v bool) *Bool { + return &Bool{newPointerValue[bool](&v)} +} + +func NewNullBool() *Bool { + return &Bool{newPointerValue[bool](nil)} +} + +// Convert Bool into reflect value. +func (bo *Bool) Convert(v reflect.Value) error { + return Convert[bool](*bo, &bo.pointerValue, v) +} + +func (bo *Bool) Unmarshal(i interface{}) error { + if i == nil { + bo.value = nil + return nil + } + + // Boolean may sometimes be represented as an integer, 0 means false, 1 means true. + if num, ok := i.(json.Number); ok { + num, err := num.Int64() + if err != nil { + return parseError(bo, i, err) + } + + bo.value = new(bool) + + if num == 0 { + *bo.value = false + } else if num == 1 { + *bo.value = true + } else { + return parseError(bo, i, fmt.Errorf("expected 0 or 1, got %d", num)) + } + return nil + } + + return bo.pointerValue.Unmarshal(i) +} + +// GetType returns the type of the value. +func (bo *Bool) GetType() types.Column { + return types.Bool +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/datetime.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/datetime.go new file mode 100644 index 0000000000..d80c2bf936 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/datetime.go @@ -0,0 +1,70 @@ +package value + +import ( + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "reflect" + "time" +) + +// DateTime represents a Kusto datetime type. DateTime implements Kusto. +type DateTime struct { + pointerValue[time.Time] +} + +// NewDateTime creates a new DateTime. +func NewDateTime(v time.Time) *DateTime { + return &DateTime{newPointerValue[time.Time](&v)} +} + +// NewNullDateTime creates a new null DateTime. +func NewNullDateTime() *DateTime { + return &DateTime{newPointerValue[time.Time](nil)} +} + +// String implements fmt.Stringer. +func (d *DateTime) String() string { + if d.value == nil { + return "" + } + return fmt.Sprint(d.value.Format(time.RFC3339Nano)) +} + +// Marshal marshals the DateTime into a Kusto compatible string. +func (d *DateTime) Marshal() string { + if d.value == nil { + return time.Time{}.Format(time.RFC3339Nano) + } + + return d.value.Format(time.RFC3339Nano) +} + +// Unmarshal unmarshals i into DateTime. i must be a string representing RFC3339Nano or nil. +func (d *DateTime) Unmarshal(i interface{}) error { + if i == nil { + d.value = nil + return nil + } + + str, ok := i.(string) + if !ok { + return convertError(d, i) + } + + t, err := time.Parse(time.RFC3339Nano, str) + if err != nil { + return parseError(d, i, err) + } + d.value = &t + return nil +} + +// Convert DateTime into reflect value. +func (d *DateTime) Convert(v reflect.Value) error { + return Convert[time.Time](*d, &d.pointerValue, v) +} + +// GetType returns the type of the value. +func (d *DateTime) GetType() types.Column { + return types.DateTime +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/decimal.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/decimal.go new file mode 100644 index 0000000000..2de315ea4b --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/decimal.go @@ -0,0 +1,87 @@ +package value + +import ( + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/shopspring/decimal" + "math/big" + "reflect" +) + +// Decimal represents a Kusto decimal type. Decimal implements Kusto. +type Decimal struct { + pointerValue[decimal.Decimal] +} + +func NewDecimal(v decimal.Decimal) *Decimal { + return &Decimal{newPointerValue[decimal.Decimal](&v)} +} + +func NewNullDecimal() *Decimal { + return &Decimal{newPointerValue[decimal.Decimal](nil)} +} + +func DecimalFromFloat(f float64) *Decimal { + return NewDecimal(decimal.NewFromFloat(f)) +} + +func DecimalFromString(s string) *Decimal { + dec, err := decimal.NewFromString(s) + if err != nil { + return NewNullDecimal() + } + return NewDecimal(dec) +} + +func (*Decimal) isKustoVal() {} + +// ParseFloat provides builtin support for Go's *big.Float conversion where that type meets your needs. +func (d *Decimal) ParseFloat(base int, prec uint, mode big.RoundingMode) (f *big.Float, b int, err error) { + if d.value == nil { + return nil, 0, parseError(d, nil, fmt.Errorf("nil value")) + } + return big.ParseFloat(d.value.String(), base, prec, mode) +} + +// Unmarshal unmarshals i into Decimal. i must be a string representing a decimal type or nil. +func (d *Decimal) Unmarshal(i interface{}) error { + if i == nil { + d.value = nil + return nil + } + + v, ok := i.(string) + if !ok { + return convertError(d, i) + } + + dec, err := decimal.NewFromString(v) + if err != nil { + return parseError(d, i, err) + } + + d.value = &dec + + return nil +} + +// Convert Decimal into reflect value. +func (d *Decimal) Convert(v reflect.Value) error { + if TryConvert[decimal.Decimal](*d, &d.pointerValue, v) { + return nil + } + + if v.Type().Kind() == reflect.String { + if d.value != nil { + v.SetString(d.value.String()) + } + return nil + } + + return convertError(d, v) +} + +// GetType returns the type of the value. +func (d *Decimal) GetType() types.Column { + return types.Decimal +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/dynamic.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/dynamic.go similarity index 70% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/value/dynamic.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/value/dynamic.go index e78ea38997..6d76b9ca67 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/dynamic.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/dynamic.go @@ -3,69 +3,84 @@ package value import ( "encoding/json" "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" "reflect" ) // Dynamic represents a Kusto dynamic type. Dynamic implements Kusto. type Dynamic struct { - // Value holds the value of the type. Value []byte - // Valid indicates if this value was set. - Valid bool } -func (Dynamic) isKustoVal() {} +// NewDynamic creates a new Dynamic. +func NewDynamic(v []byte) *Dynamic { return &Dynamic{v} } -// String implements fmt.Stringer. -func (d Dynamic) String() string { - if !d.Valid { +// NewNullDynamic creates a new null Dynamic. +func NewNullDynamic() *Dynamic { return &Dynamic{nil} } + +func (d *Dynamic) GetValue() interface{} { + return d.Value +} + +func (d *Dynamic) String() string { + if d.Value == nil { return "" } - return string(d.Value) } +func DynamicFromInterface(v interface{}) *Dynamic { + marshal, err := json.Marshal(v) + if err != nil { + return NewNullDynamic() + } + + return NewDynamic(marshal) +} + +func (*Dynamic) isKustoVal() {} + // Unmarshal unmarshal's i into Dynamic. i must be a string, []byte, map[string]interface{}, []interface{}, other JSON serializable value or nil. // If []byte or string, must be a JSON representation of a value. func (d *Dynamic) Unmarshal(i interface{}) error { if i == nil { d.Value = nil - d.Valid = false return nil } switch v := i.(type) { case []byte: d.Value = v - d.Valid = true return nil case string: d.Value = []byte(v) - d.Valid = true return nil } b, err := json.Marshal(i) if err != nil { - return fmt.Errorf("Column with type 'dynamic' was a %T that could not be JSON encoded: %s", i, err) + return parseError(d, i, err) } d.Value = b - d.Valid = true return nil } // Convert Dynamic into reflect value. -func (d Dynamic) Convert(v reflect.Value) error { +func (d *Dynamic) Convert(v reflect.Value) error { t := v.Type() if t.Kind() == reflect.Ptr { t = t.Elem() } + if d.Value == nil { + return nil + } + var valueToSet reflect.Value switch { case t.ConvertibleTo(reflect.TypeOf(Dynamic{})): - valueToSet = reflect.ValueOf(d) + valueToSet = reflect.ValueOf(*d) case t.ConvertibleTo(reflect.TypeOf([]byte{})): if t.Kind() == reflect.String { s := string(d.Value) @@ -74,9 +89,6 @@ func (d Dynamic) Convert(v reflect.Value) error { valueToSet = reflect.ValueOf(d.Value) } case t.Kind() == reflect.Slice || t.Kind() == reflect.Map: - if !d.Valid { - return nil - } ptr := reflect.New(t) if err := json.Unmarshal([]byte(d.Value), ptr.Interface()); err != nil { @@ -106,3 +118,8 @@ func (d Dynamic) Convert(v reflect.Value) error { } return nil } + +// GetType returns the type of the value. +func (d *Dynamic) GetType() types.Column { + return types.Dynamic +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/guid.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/guid.go new file mode 100644 index 0000000000..fb2263678f --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/guid.go @@ -0,0 +1,48 @@ +package value + +import ( + "github.com/Azure/azure-kusto-go/azkustodata/types" + "reflect" + + "github.com/google/uuid" +) + +// GUID represents a Kusto GUID type. GUID implements Kusto. +type GUID struct { + pointerValue[uuid.UUID] +} + +// NewGUID creates a new GUID. +func NewGUID(v uuid.UUID) *GUID { return &GUID{newPointerValue[uuid.UUID](&v)} } + +// NewNullGUID creates a new null GUID. +func NewNullGUID() *GUID { return &GUID{newPointerValue[uuid.UUID](nil)} } + +// Unmarshal unmarshals i into GUID. i must be a string representing a GUID or nil. +func (g *GUID) Unmarshal(i interface{}) error { + if i == nil { + g.value = nil + return nil + } + str, ok := i.(string) + if !ok { + return convertError(g, i) + } + u, err := uuid.Parse(str) + if err != nil { + return parseError(g, i, err) + } + + g.value = &u + return nil +} + +// Convert GUID into reflect value. +func (g *GUID) Convert(v reflect.Value) error { + return Convert[uuid.UUID](*g, &g.pointerValue, v) +} + +// GetType returns the type of the value. +func (g *GUID) GetType() types.Column { + return types.GUID +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/int.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/int.go new file mode 100644 index 0000000000..c4d8f77c28 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/int.go @@ -0,0 +1,77 @@ +package value + +import ( + "encoding/json" + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "math" + "reflect" +) + +// Int represents a Kusto boolean type. Bool implements Kusto. +type Int struct { + pointerValue[int32] +} + +func NewInt(v int32) *Int { + return &Int{newPointerValue[int32](&v)} +} + +func NewNullInt() *Int { + return &Int{newPointerValue[int32](nil)} +} + +// Convert Int into reflect value. +func (in *Int) Convert(v reflect.Value) error { + if TryConvert[int32](*in, &in.pointerValue, v) { + return nil + } + + if v.Type().Kind() == reflect.Int { + if in.value != nil { + v.SetInt(int64(*in.value)) + } + return nil + } + + return convertError(in, v) +} + +// GetType returns the type of the value. +func (in *Int) GetType() types.Column { + return types.Int +} + +func (in *Int) Unmarshal(i interface{}) error { + if i == nil { + in.value = nil + return nil + } + + var myInt int64 + + switch v := i.(type) { + case json.Number: + var err error + myInt, err = v.Int64() + if err != nil { + return parseError(in, i, err) + } + case float64: + if v != math.Trunc(v) { + return parseError(in, i, fmt.Errorf("float64 value was not an integer")) + } + myInt = int64(v) + case int: + myInt = int64(v) + default: + return convertError(in, i) + } + + if myInt > math.MaxInt32 { + return parseError(in, i, fmt.Errorf("value was too large for int32")) + } + val := int32(myInt) + in.value = &val + return nil +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/long.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/long.go new file mode 100644 index 0000000000..55d5d18d92 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/long.go @@ -0,0 +1,68 @@ +package value + +import ( + "encoding/json" + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "math" + "reflect" +) + +// Long represents a Kusto long type, which is an int64. Long implements Kusto. +type Long struct { + pointerValue[int64] +} + +func NewLong(i int64) *Long { return &Long{newPointerValue[int64](&i)} } + +func NewNullLong() *Long { return &Long{newPointerValue[int64](nil)} } + +// Unmarshal unmarshals i into Long. i must be an int64 or nil. +func (l *Long) Unmarshal(i interface{}) error { + if i == nil { + l.value = nil + return nil + } + + var myInt int64 + + switch v := i.(type) { + case json.Number: + var err error + myInt, err = v.Int64() + if err != nil { + return parseError(l, i, err) + } + case float64: + if v != math.Trunc(v) { + return parseError(l, i, fmt.Errorf("float64 value was not an integer")) + } + myInt = int64(v) + case int: + myInt = int64(v) + default: + return convertError(l, i) + } + + l.value = &myInt + return nil +} + +// Convert Long into reflect value. +func (l *Long) Convert(v reflect.Value) error { + if TryConvert[int64](*l, &l.pointerValue, v) { + return nil + } + + if v.Type().Kind() == reflect.Int || v.Type().Kind() == reflect.Int32 { + if l.value != nil { + v.SetInt(*l.value) + } + return nil + } + + return convertError(l, v) +} + +// GetType returns the type of the value. +func (l *Long) GetType() types.Column { return types.Long } diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/real.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/real.go new file mode 100644 index 0000000000..5b069eaa66 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/real.go @@ -0,0 +1,73 @@ +package value + +import ( + "encoding/json" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "reflect" + "strconv" +) + +// Real represents a Kusto real type. Real implements Kusto. +type Real struct { + pointerValue[float64] +} + +func NewReal(i float64) *Real { + return &Real{newPointerValue[float64](&i)} +} +func NewNullReal() *Real { + return &Real{newPointerValue[float64](nil)} +} + +// Unmarshal unmarshals i into Real. i must be a json.Number(that is a float64), float64 or nil. +func (r *Real) Unmarshal(i interface{}) error { + if i == nil { + r.value = nil + return nil + } + + var myFloat float64 + + switch v := i.(type) { + case json.Number: + var err error + myFloat, err = v.Float64() + if err != nil { + return parseError(r, i, err) + } + case float64: + myFloat = v + case string: + var err error + myFloat, err = strconv.ParseFloat(v, 64) + if err != nil { + return parseError(r, i, err) + } + default: + return convertError(r, i) + } + + r.value = &myFloat + return nil +} + +// Convert Real into reflect value. +func (r *Real) Convert(v reflect.Value) error { + if TryConvert[float64](*r, &r.pointerValue, v) { + return nil + } + + if v.Type().Kind() == reflect.Int || v.Type().Kind() == reflect.Int32 { + if r.value != nil { + v.SetInt(int64(*r.value)) + } + return nil + } + + return convertError(r, v) +} + +// GetType returns the type of the value. +func (r *Real) GetType() types.Column { + return types.Real +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/string.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/string.go similarity index 61% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/value/string.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/value/string.go index 8eb51e3a2a..af586f27f7 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/string.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/string.go @@ -2,6 +2,7 @@ package value import ( "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" "reflect" ) @@ -9,17 +10,14 @@ import ( type String struct { // Value holds the value of the type. Value string - // Valid indicates if this value was set. - Valid bool } -func (String) isKustoVal() {} +func NewString(v string) *String { + return &String{Value: v} +} // String implements fmt.Stringer. -func (s String) String() string { - if !s.Valid { - return "" - } +func (s *String) String() string { return s.Value } @@ -27,41 +25,45 @@ func (s String) String() string { func (s *String) Unmarshal(i interface{}) error { if i == nil { s.Value = "" - s.Valid = false return nil } v, ok := i.(string) if !ok { - return fmt.Errorf("Column with type 'string' had type %T", i) + return convertError(s, i) } s.Value = v - s.Valid = true return nil } // Convert String into reflect value. -func (s String) Convert(v reflect.Value) error { +func (s *String) Convert(v reflect.Value) error { t := v.Type() switch { case t.Kind() == reflect.String: - if s.Valid { - v.Set(reflect.ValueOf(s.Value)) - } + v.Set(reflect.ValueOf(s.Value)) return nil case t.ConvertibleTo(reflect.TypeOf(new(string))): - if s.Valid { - i := &s.Value - v.Set(reflect.ValueOf(i)) - } + i := &s.Value + v.Set(reflect.ValueOf(i)) return nil case t.ConvertibleTo(reflect.TypeOf(String{})): - v.Set(reflect.ValueOf(s)) + v.Set(reflect.ValueOf(*s)) return nil case t.ConvertibleTo(reflect.TypeOf(&String{})): - v.Set(reflect.ValueOf(&s)) + v.Set(reflect.ValueOf(s)) return nil } return fmt.Errorf("Column was type Kusto.String, receiver had base Kind %s ", t.Kind()) } + +// GetValue returns the value of the type. +func (s *String) GetValue() interface{} { + return s.Value +} + +// GetType returns the type of the value. +func (s *String) GetType() types.Column { + return types.String +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/timespan.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/timespan.go similarity index 80% rename from vendor/github.com/Azure/azure-kusto-go/kusto/data/value/timespan.go rename to vendor/github.com/Azure/azure-kusto-go/azkustodata/value/timespan.go index 25d85b2334..a3acd255f5 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/timespan.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/timespan.go @@ -2,6 +2,7 @@ package value import ( "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/types" "reflect" "strconv" "strings" @@ -12,30 +13,34 @@ const tick = 100 * time.Nanosecond // Timespan represents a Kusto timespan type. Timespan implements Kusto. type Timespan struct { - // Value holds the value of the type. - Value time.Duration - // Valid indicates if this value was set. - Valid bool + pointerValue[time.Duration] } -func (Timespan) isKustoVal() {} +func NewTimespan(v time.Duration) *Timespan { + return &Timespan{newPointerValue[time.Duration](&v)} +} + +func NewNullTimespan() *Timespan { + return &Timespan{newPointerValue[time.Duration](nil)} +} -// String implements fmt.Stringer. -func (t Timespan) String() string { - if !t.Valid { - return "" +func TimespanFromString(s string) (*Timespan, error) { + t := &Timespan{} + err := t.Unmarshal(s) + if err != nil { + return nil, err } - return t.Value.String() + return t, nil } // Marshal marshals the Timespan into a Kusto compatible string. The string is the contant invariant(c) // format. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings . -func (t Timespan) Marshal() string { +func (t *Timespan) Marshal() string { const ( day = 24 * time.Hour ) - if !t.Valid { + if t.value == nil { return "00:00:00" } @@ -43,12 +48,12 @@ func (t Timespan) Marshal() string { // For example, after we write to our string the number of days that value had, we remove those days // from the duration. We continue doing this until val only holds values < 10 millionth of a second (tick) // as that is the lowest precision in our string representation. - val := t.Value + val := *t.value sb := strings.Builder{} // Add a - sign if we have a negative value. Convert our value to positive for easier processing. - if t.Value < 0 { + if val < 0 { sb.WriteString("-") val = val * -1 } @@ -95,14 +100,13 @@ func (t *Timespan) Unmarshal(i interface{}) error { ) if i == nil { - t.Value = 0 - t.Valid = false + t.value = nil return nil } v, ok := i.(string) if !ok { - return fmt.Errorf("Column with type 'timespan' had type %T", i) + return convertError(t, i) } negative := false @@ -115,26 +119,26 @@ func (t *Timespan) Unmarshal(i interface{}) error { sp := strings.Split(v, ":") if len(sp) != 3 { - return fmt.Errorf("value to unmarshal into Timespan does not seem to fit format '00:00:00', where values are decimal(%s)", v) + return parseError(v, sp, fmt.Errorf("value to unmarshal into Timespan does not seem to fit format '00:00:00', where values are decimal(%s)", v)) } var sum time.Duration d, err := t.unmarshalDaysHours(sp[hoursIndex]) if err != nil { - return err + return parseError(v, sp, err) } sum += d d, err = t.unmarshalMinutes(sp[minutesIndex]) if err != nil { - return err + return parseError(v, sp, err) } sum += d d, err = t.unmarshalSeconds(sp[secondsIndex]) if err != nil { - return err + return parseError(v, sp, err) } sum += d @@ -143,8 +147,7 @@ func (t *Timespan) Unmarshal(i interface{}) error { sum = sum * time.Duration(-1) } - t.Value = sum - t.Valid = true + t.value = &sum return nil } @@ -241,26 +244,35 @@ func (t *Timespan) unmarshalSeconds(s string) (time.Duration, error) { } // Convert Timespan into reflect value. -func (ts Timespan) Convert(v reflect.Value) error { - t := v.Type() +func (t *Timespan) Convert(v reflect.Value) error { + pt := v.Type() switch { - case t.AssignableTo(reflect.TypeOf(time.Duration(0))): - if ts.Valid { - v.Set(reflect.ValueOf(ts.Value)) + case pt.AssignableTo(reflect.TypeOf(time.Duration(0))): + if t.value != nil { + v.Set(reflect.ValueOf(*t.value)) } return nil - case t.ConvertibleTo(reflect.TypeOf(new(time.Duration))): - if ts.Valid { - t := &ts.Value - v.Set(reflect.ValueOf(t)) + case pt.ConvertibleTo(reflect.TypeOf(new(time.Duration))): + if t.value != nil { + pt := t.value + v.Set(reflect.ValueOf(pt)) } return nil - case t.ConvertibleTo(reflect.TypeOf(Timespan{})): - v.Set(reflect.ValueOf(ts)) + case pt.ConvertibleTo(reflect.TypeOf(Timespan{})): + v.Set(reflect.ValueOf(*t)) return nil - case t.ConvertibleTo(reflect.TypeOf(&Timespan{})): - v.Set(reflect.ValueOf(&ts)) + case pt.ConvertibleTo(reflect.TypeOf(&Timespan{})): + v.Set(reflect.ValueOf(t)) return nil } - return fmt.Errorf("Column was type Kusto.Timespan, receiver had base Kind %s ", t.Kind()) + return convertError(t, v) +} + +func TimespanString(d time.Duration) string { + return NewTimespan(d).Marshal() +} + +// GetType returns the type of the value. +func (t *Timespan) GetType() types.Column { + return types.Timespan } diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/value.go b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/value.go new file mode 100644 index 0000000000..ef0d56ff3b --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustodata/value/value.go @@ -0,0 +1,170 @@ +/* +Package value holds Kusto data value representations. All types provide a Kusto that +stores the native value and Valid which indicates if the value was set or was null. + +# Kusto Value + +A value.Kusto can hold types that represent Kusto Scalar types that define column data. +We represent that with an interface: + + type Kusto interface + +This interface can hold the following values: + + value.Bool + value.Int + value.Long + value.Real + value.Decimal + value.String + value.Dynamic + value.DateTime + value.Timespan + +Each type defined above has at minimum two fields: + + .Value - The type specific value + .Valid - True if the value was non-null in the Kusto table + +Each provides at minimum the following two methods: + + .String() - Returns the string representation of the value. + .Unmarshal() - Unmarshals the value into a standard Go type. + +The Unmarshal() is for internal use, it should not be needed by an end user. Use .Value or table.Row.ToStruct() instead. +*/ +package value + +import ( + "fmt" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "reflect" +) + +type pointerValue[T any] struct { + value *T +} + +func newPointerValue[T any](v *T) pointerValue[T] { + return pointerValue[T]{value: v} +} + +func (p *pointerValue[T]) String() string { + if p.value == nil { + return "" + } + return fmt.Sprintf("%v", *p.value) +} + +func (p *pointerValue[T]) GetValue() interface{} { + return p.value +} + +func (p *pointerValue[T]) Ptr() *T { + return p.value +} + +func convertError(expected interface{}, actual interface{}) error { + if ref, ok := actual.(reflect.Value); ok { + return errors.ES(errors.OpTableAccess, errors.KWrongColumnType, "column with type '%T' had value that was %v", expected, ref.Type()) + } + return errors.ES(errors.OpTableAccess, errors.KWrongColumnType, "column with type '%T' had value that was %T", expected, actual) +} + +func parseError(expected interface{}, actual interface{}, err error) error { + return errors.ES(errors.OpTableAccess, errors.KFailedToParse, "column with type '%T' had value %s which did not parse: %s", expected, actual, err) +} + +func (p *pointerValue[T]) Unmarshal(i interface{}) error { + if i == nil { + p.value = nil + return nil + } + + v, ok := i.(T) + if !ok { + return convertError(p, i) + } + + p.value = &v + return nil +} + +func TryConvert[T any](holder interface{}, p *pointerValue[T], v reflect.Value) bool { + t := v.Type() + + if holder == nil || p.value == nil { + v.Set(reflect.Zero(t)) + return true + } + + if reflect.TypeOf(*p.value).ConvertibleTo(t) { + v.Set(reflect.ValueOf(*p.value).Convert(t)) + return true + } + + if reflect.TypeOf(p.value).ConvertibleTo(t) { + v.Set(reflect.ValueOf(p.value).Convert(t)) + return true + } + + if reflect.TypeOf(holder).ConvertibleTo(t) { + v.Set(reflect.ValueOf(holder).Convert(t)) + return true + } + + if reflect.TypeOf(&holder).ConvertibleTo(t) { + v.Set(reflect.ValueOf(&holder).Convert(t)) + return true + } + + return false +} + +func Convert[T any](holder interface{}, p *pointerValue[T], v reflect.Value) error { + if !TryConvert[T](holder, p, v) { + return convertError(holder, v) + } + + return nil +} + +// Kusto represents a Kusto value. +type Kusto interface { + fmt.Stringer + Convert(v reflect.Value) error + GetValue() interface{} + GetType() types.Column + Unmarshal(interface{}) error +} + +func Default(t types.Column) Kusto { + switch t { + case types.Bool: + return NewNullBool() + case types.Int: + return NewNullInt() + case types.Long: + return NewNullLong() + case types.Real: + return NewNullReal() + case types.Decimal: + return NewNullDecimal() + case types.String: + return NewString("") + case types.Dynamic: + return NewNullDynamic() + case types.DateTime: + return NewNullDateTime() + case types.Timespan: + return NewNullTimespan() + case types.GUID: + return NewNullGUID() + default: + return nil + } +} + +// Values is a list of Kusto values, usually an ordered row. +type Values []Kusto diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/.gitignore b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/.gitignore similarity index 94% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/.gitignore rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/.gitignore index 7c8c59b4d4..8e26cff44d 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/.gitignore +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/.gitignore @@ -1,2 +1,2 @@ -config.json +config.json *.csv \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE new file mode 100644 index 0000000000..7d9fcaf819 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustoingest/doc.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/doc.go new file mode 100644 index 0000000000..116d78b93e --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/doc.go @@ -0,0 +1,35 @@ +/* +Package azkustoingest provides a client for ingesting data into Azure Data Explorer (Kusto) clusters. + +This package enables users to use different ingestion methods including queued, streaming, and managed ingestion from +various sources such as local files, Azure Blob Storage urls, streams, or any `io.Reader`. + +To start using this package, create an instance of the Ingestor, passing in a connection string built using the +NewConnectionStringBuilder() function from the azkustodata package. + +Example FromFile usage: + + kcsb := azkustodata.NewConnectionStringBuilder(`endpoint`).WithAadAppKey("clientID", "clientSecret", "tenentID") + ingestor, err := azkustoingest.New(kcsb, azkustoingest.WithDefaultDatabase("database"), azkustoingest.WithDefaultTable("table")) + + if err != nil { + // Handle error + } + + defer ingestor.Close() // Always close the ingestor when done. + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + + _, err = ingestor.FromFile(ctx, "/path/to/file", azkustoingest.DeleteSource()) + + ... // Handle any errors and status + +The package supports advanced features such as status reporting to Kusto tables, file deletion after ingestion, and handling of +retryable errors. + +For complete documentation, please visit: +https://github.com/Azure/azure-kusto-go +https://pkg.go.dev/github.com/Azure/azure-kusto-go/azkustoingest +*/ +package azkustoingest diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/file_options.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/file_options.go similarity index 97% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/file_options.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/file_options.go index 4bbcd92527..cc3739f933 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/file_options.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/file_options.go @@ -1,14 +1,14 @@ -package ingest +package azkustoingest import ( "encoding/json" "fmt" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/cenkalti/backoff/v4" "time" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/cenkalti/backoff/v4" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" ) type SourceScope uint @@ -255,7 +255,7 @@ func IngestionMapping(mapping interface{}, format DataFormat) FileOption { return errors.ES( errors.OpUnknown, errors.KClientArgs, - "IngestMapping option was passed to an Ingest.Ingestion call that was not a string, []byte or could be JSON encoded: %s", err, + "IngestMapping option was passed to an azkustoingest.Ingestion call that was not a string, []byte or could be JSON encoded: %s", err, ).SetNoRetry() } j = string(b) diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/ingest.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingest.go similarity index 64% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/ingest.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingest.go index d14fbd7bf0..828e793484 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/ingest.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingest.go @@ -1,19 +1,15 @@ -package ingest +package azkustoingest import ( - "bytes" "context" "fmt" - "io" - "sync" - - "github.com/Azure/azure-kusto-go/kusto" - - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/queued" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/resources" "github.com/google/uuid" + "io" ) type Ingestor interface { @@ -32,49 +28,50 @@ type Ingestion struct { fs queued.Queued - connMu sync.Mutex - streamConn streamIngestor - bufferSize int maxBuffers int - applicationForTracing string - clientVersionForTracing string + withoutEndpointCorrection bool + customIngestConnectionString *azkustodata.ConnectionStringBuilder + applicationForTracing string + clientVersionForTracing string } -// Option is an optional argument to New(). -type Option func(s *Ingestion) +// New is a constructor for Ingestion. +func New(kcsb *azkustodata.ConnectionStringBuilder, options ...Option) (*Ingestion, error) { + i := getOptions(options) -// WithStaticBuffer configures the ingest client to upload data to Kusto using a set of one or more static memory buffers with a fixed size. -func WithStaticBuffer(bufferSize int, maxBuffers int) Option { - return func(s *Ingestion) { - s.bufferSize = bufferSize - s.maxBuffers = maxBuffers + if !i.withoutEndpointCorrection { + newKcsb := *kcsb + newKcsb.DataSource = addIngestPrefix(newKcsb.DataSource) + kcsb = &newKcsb } -} + clientDetails := azkustodata.NewClientDetails(kcsb.ApplicationForTracing, kcsb.UserForTracing) + i.applicationForTracing = clientDetails.ApplicationForTracing() + i.clientVersionForTracing = clientDetails.ClientVersionForTracing() -// New is a constructor for Ingestion. -func New(client QueryClient, db, table string, options ...Option) (*Ingestion, error) { - mgr, err := resources.New(client) + client, err := azkustodata.New(kcsb) if err != nil { return nil, err } - i := &Ingestion{ - client: client, - mgr: mgr, - db: db, - table: table, - } - i.applicationForTracing = client.ClientDetails().ApplicationForTracing() - i.clientVersionForTracing = client.ClientDetails().ClientVersionForTracing() + return newFromClient(client, i) +} - for _, option := range options { - option(i) +func newFromClient(client QueryClient, i *Ingestion) (*Ingestion, error) { + mgr, err := resources.New(client) + if err != nil { + client.Close() + return nil, err } - fs, err := queued.New(db, table, mgr, client.HttpClient(), i.applicationForTracing, i.clientVersionForTracing, queued.WithStaticBuffer(i.bufferSize, i.maxBuffers)) + i.client = client + i.mgr = mgr + + fs, err := queued.New(i.db, i.table, mgr, client.HttpClient(), i.applicationForTracing, i.clientVersionForTracing, queued.WithStaticBuffer(i.bufferSize, i.maxBuffers)) if err != nil { + mgr.Close() + client.Close() return nil, err } @@ -203,49 +200,6 @@ func (i *Ingestion) fromReader(ctx context.Context, reader io.Reader, options [] return result, nil } -// Deprecated: Stream use a streaming ingest client instead - `ingest.NewStreaming`. -// takes a payload that is encoded in format with a server stored mappingName, compresses it and uploads it to Kusto. -// More information can be found here: -// https://docs.microsoft.com/en-us/azure/kusto/management/create-ingestion-mapping-command -// The context object can be used with a timeout or cancel to limit the request time. -func (i *Ingestion) Stream(ctx context.Context, payload []byte, format DataFormat, mappingName string) error { - c, err := i.getStreamConn() - if err != nil { - return err - } - - props := properties.All{ - Ingestion: properties.Ingestion{ - DatabaseName: i.db, - TableName: i.table, - Additional: properties.Additional{ - Format: format, - IngestionMappingRef: mappingName, - }, - }, - } - - _, err = streamImpl(c, ctx, bytes.NewReader(payload), props, false) - - return err -} - -func (i *Ingestion) getStreamConn() (streamIngestor, error) { - i.connMu.Lock() - defer i.connMu.Unlock() - - if i.streamConn != nil { - return i.streamConn, nil - } - - sc, err := kusto.NewConn(removeIngestPrefix(i.client.Endpoint()), i.client.Auth(), i.client.HttpClient(), i.client.ClientDetails()) - if err != nil { - return nil, err - } - i.streamConn = sc - return i.streamConn, nil -} - func (i *Ingestion) newProp() properties.All { return properties.All{ Ingestion: properties.Ingestion{ @@ -257,15 +211,10 @@ func (i *Ingestion) newProp() properties.All { func (i *Ingestion) Close() error { i.mgr.Close() - var err error - err = i.fs.Close() - if i.streamConn != nil { - err2 := i.streamConn.Close() - if err == nil { - err = err2 - } else { - err = errors.GetCombinedError(err, err2) - } + err := i.client.Close() + if err != nil { + return err } + err = i.fs.Close() return err } diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingestion_options.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingestion_options.go new file mode 100644 index 0000000000..b6e4f81a79 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingestion_options.go @@ -0,0 +1,109 @@ +package azkustoingest + +import ( + "github.com/Azure/azure-kusto-go/azkustodata" + "net" + "strings" +) + +// Option is an optional argument to New(). +type Option func(s *Ingestion) + +// WithStaticBuffer configures the ingest client to upload data to Kusto using a set of one or more static memory buffers with a fixed size. +// Only relevant for Queued and Managed ingestion. +func WithStaticBuffer(bufferSize int, maxBuffers int) Option { + return func(s *Ingestion) { + s.bufferSize = bufferSize + s.maxBuffers = maxBuffers + } +} + +// WithDefaultDatabase configures the ingest client to use the given database name as the default database for all ingest operations. +func WithDefaultDatabase(db string) Option { + return func(s *Ingestion) { + s.db = db + } +} + +// WithDefaultTable configures the ingest client to use the given table name as the default table for all ingest operations. +func WithDefaultTable(table string) Option { + return func(s *Ingestion) { + s.table = table + } +} + +// WithoutEndpointCorrection disables the automatic correction of the Kusto cluster address. +// The address will be used as-is, without adding or removing the "ingest-" prefix. +func WithoutEndpointCorrection() Option { + return func(s *Ingestion) { + s.withoutEndpointCorrection = true + } +} + +// WithCustomIngestConnectionString is relevant to Managed ingestion client only. +// It configures the ingest client using a custom connection string, as opposed to one derived from the streaming client. +// This option implies WithoutEndpointCorrection(). +func WithCustomIngestConnectionString(kcsb *azkustodata.ConnectionStringBuilder) Option { + return func(s *Ingestion) { + s.withoutEndpointCorrection = true + s.customIngestConnectionString = kcsb + } +} + +func getOptions(options []Option) *Ingestion { + s := &Ingestion{} + for _, o := range options { + o(s) + } + return s +} + +const domainPrefix = "://" +const ingestPrefix = "ingest-" + +func removeIngestPrefix(s string) string { + if isReservedHostname(s) { + return s + } + + return strings.Replace(s, ingestPrefix, "", 1) +} + +func addIngestPrefix(s string) string { + if isReservedHostname(s) { + return s + } + if strings.Contains(s, ingestPrefix) { + return s + } + + if strings.Contains(s, domainPrefix) { + return strings.Replace(s, domainPrefix, domainPrefix+ingestPrefix, 1) + } else { + return ingestPrefix + s + } +} + +func isReservedHostname(host string) bool { + if strings.Contains(host, domainPrefix) { + host = strings.Split(host, domainPrefix)[1] + } + + // Check if host is an IP address + if ip := net.ParseIP(host); ip != nil { + return true + } + + // Check if host is "localhost" + if strings.ToLower(host) == "localhost" { + return true + } + + // Check if host is "onebox.dev.kusto.windows.net" + if host == "onebox.dev.kusto.windows.net" { + return true + } + + // If none of the conditions match, return false + return false +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions/ingestoptions.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions/ingestoptions.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions/ingestoptions.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions/ingestoptions.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/gzip/gzip.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/gzip/gzip.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/gzip/gzip.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/gzip/gzip.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties/properties.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/properties/properties.go similarity index 97% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties/properties.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/properties/properties.go index 5d82a0c5df..a0f1a157e2 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties/properties.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/properties/properties.go @@ -6,22 +6,21 @@ import ( "encoding/base64" "encoding/json" "fmt" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/cenkalti/backoff/v4" "net/url" "os" "path/filepath" "strings" "time" - "github.com/Azure/azure-kusto-go/kusto" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/cenkalti/backoff/v4" + "github.com/Azure/azure-kusto-go/azkustodata/errors" "github.com/google/uuid" ) // DataFormat indicates what type of encoding format was used for source data. -// Note: This is very similar to ingest.DataFormat, except this supports more formats. +// Note: This is very similar to azkustoingest.DataFormat, except this supports more formats. // We are not using a shared list, because this list is used only internally and is for the // data itself, not the mapping reference. Structure prevents packages such as filesystem // from importing ingest, because ingest imports filesystem. We would end up with recursive imports. @@ -144,7 +143,7 @@ func (d DataFormat) CamelCase() string { return "" } -func (d DataFormat) KnownOrDefault() kusto.DataFormatForStreaming { +func (d DataFormat) KnownOrDefault() azkustodata.DataFormatForStreaming { if d == DFUnknown { return CSV } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued/.gitignore b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/queued/.gitignore similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued/.gitignore rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/queued/.gitignore diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued/queued.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/queued/queued.go similarity index 90% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued/queued.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/queued/queued.go index 1689eecb22..f621b8b3c0 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued/queued.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/queued/queued.go @@ -5,6 +5,8 @@ package queued import ( "context" "fmt" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/utils" "io" "net/http" "net/url" @@ -12,17 +14,14 @@ import ( "path/filepath" "time" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/gzip" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/gzip" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/resources" - "github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" - "github.com/Azure/azure-storage-queue-go/azqueue" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue" "github.com/google/uuid" ) @@ -274,8 +273,13 @@ func (i *Ingestion) Blob(ctx context.Context, from string, fileSize int64, props if attempts >= StorageMaxRetryPolicy { return errors.ES(errors.OpFileIngest, errors.KBlobstore, "max retry policy reached").SetNoRetry() } - queueClient := i.upstreamQueue(queueUri) - if _, err := queueClient.Enqueue(ctx, j, 0, 0); err != nil { + queue, err := i.upstreamQueue(queueUri) + if err != nil { + i.mgr.ReportStorageResourceResult(queueUri.Account(), false) + continue + } + + if _, err := queue.EnqueueMessage(ctx, j, nil); err != nil { i.mgr.ReportStorageResourceResult(queueUri.Account(), false) continue } else { @@ -320,28 +324,20 @@ func (i *Ingestion) upstreamContainer(resourceUri *resources.URI) (*azblob.Clien return client, resourceUri.ObjectName(), nil } -func (i *Ingestion) upstreamQueue(resourceUri *resources.URI) azqueue.MessagesURL { +func (i *Ingestion) upstreamQueue(resourceUri *resources.URI) (*azqueue.QueueClient, error) { queueUrl := resourceUri.URL() - service, _ := url.Parse(fmt.Sprintf("%s://%s?%s", queueUrl.Scheme, queueUrl.Host, resourceUri.SAS().Encode())) - - p := createPipeline(i.http) - - return azqueue.NewServiceURL(*service, p).NewQueueURL(resourceUri.ObjectName()).NewMessagesURL() -} + serviceUrl := fmt.Sprintf("%s://%s?%s", queueUrl.Scheme, queueUrl.Host, resourceUri.SAS().Encode()) -func createPipeline(http *http.Client) pipeline.Pipeline { - // This is a lot of boilerplate, but all it does is setting the http client to be our own. - return pipeline.NewPipeline([]pipeline.Factory{pipeline.MethodFactoryMarker()}, pipeline.Options{ - HTTPSender: pipeline.FactoryFunc(func(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.PolicyFunc { - return func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { - r, err := http.Do(request.WithContext(ctx)) - if err != nil { - err = pipeline.NewError(err, "HTTP request failed") - } - return pipeline.NewHTTPResponse(r), err - } - }), + service, err := azqueue.NewServiceClientWithNoCredential(serviceUrl, &azqueue.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Transport: i.http, + }, }) + if err != nil { + return nil, errors.E(errors.OpFileIngest, errors.KBlobstore, err) + } + + return service.NewQueueClient(resourceUri.ObjectName()), nil } var nower = time.Now diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/ranked_storage_account.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/ranked_storage_account.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/ranked_storage_account.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/ranked_storage_account.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/ranked_storage_account_set.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/ranked_storage_account_set.go similarity index 100% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/ranked_storage_account_set.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/ranked_storage_account_set.go diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/resources.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/resources.go similarity index 87% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/resources.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/resources.go index 97224ad3dc..3d46477d81 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/resources.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/resources.go @@ -12,10 +12,12 @@ import ( "sync/atomic" "time" - "github.com/Azure/azure-kusto-go/kusto" - kustoErrors "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/data/table" - "github.com/Azure/azure-kusto-go/kusto/kql" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustodata/query" + v1 "github.com/Azure/azure-kusto-go/azkustodata/query/v1" + + kustoErrors "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/kql" "github.com/cenkalti/backoff/v4" ) @@ -26,9 +28,9 @@ const ( fetchInterval = 1 * time.Hour ) -// mgmter is a private interface that allows us to write hermetic tests against the kusto.Client.Mgmt() method. +// mgmter is a private interface that allows us to write hermetic tests against the azkustodata.Client.Mgmt() method. type mgmter interface { - Mgmt(ctx context.Context, db string, query kusto.Statement, options ...kusto.MgmtOption) (*kusto.RowIterator, error) + Mgmt(ctx context.Context, db string, statement azkustodata.Statement, options ...azkustodata.QueryOption) (v1.Dataset, error) } // URI represents a resource URI for an ingestion command. @@ -172,11 +174,11 @@ func (m *Manager) AuthContext(ctx context.Context) (string, error) { return m.kustoToken.AuthContext, nil } - var rows *kusto.RowIterator + var dataset v1.Dataset retryCtx := backoff.WithContext(initBackoff(), ctx) err := backoff.Retry(func() error { var err error - rows, err = m.client.Mgmt(ctx, "NetDefaultDB", kql.New(".get kusto identity token"), kusto.IngestionEndpoint()) + dataset, err = m.client.Mgmt(ctx, "NetDefaultDB", kql.New(".get kusto identity token")) if err == nil { return nil } @@ -193,27 +195,21 @@ func (m *Manager) AuthContext(ctx context.Context) (string, error) { return "", fmt.Errorf("problem getting authorization context from Kusto via Mgmt: %s", err) } - count := 0 - token := token{} - err = rows.DoOnRowOrError( - func(r *table.Row, e *kustoErrors.Error) error { - if e != nil { - return e - } - if count != 0 { - return fmt.Errorf("call for AuthContext returned more than 1 Row") - } - count++ - return r.ToStruct(&token) - }, - ) + tokens, err := query.ToStructs[token](dataset) if err != nil { return "", err } + if tokens == nil { + return "", fmt.Errorf("call for AuthContext returned no Rows") + } + + if len(tokens) != 1 { + return "", fmt.Errorf("call for AuthContext returned more than 1 Row") + } - m.kustoToken = token + m.kustoToken = tokens[0] m.authTokenCacheExpiration = time.Now().UTC().Add(time.Hour) - return token.AuthContext, nil + return tokens[0].AuthContext, nil } // ingestResc represents a kusto Mgmt() record about a resource @@ -291,16 +287,16 @@ func (i *Ingestion) getRankedStorageQueues(rankedStorageAccounts []RankedStorage return groupResourcesByStorageAccount(i.Queues, rankedStorageAccounts) } -// fetch makes a kusto.Client.Mgmt() call to retrieve the resources used for Ingestion. +// fetch makes a azkustodata.Client.Mgmt() call to retrieve the resources used for Ingestion. func (m *Manager) fetch(ctx context.Context) error { m.fetchLock.Lock() defer m.fetchLock.Unlock() - var rows *kusto.RowIterator + var dataset v1.Dataset retryCtx := backoff.WithContext(initBackoff(), ctx) err := backoff.Retry(func() error { var err error - rows, err = m.client.Mgmt(ctx, "NetDefaultDB", kql.New(".get ingestion resources"), kusto.IngestionEndpoint()) + dataset, err = m.client.Mgmt(ctx, "NetDefaultDB", kql.New(".get ingestion resources")) if err == nil { return nil } @@ -318,21 +314,18 @@ func (m *Manager) fetch(ctx context.Context) error { } ingest := Ingestion{} - err = rows.DoOnRowOrError( - func(r *table.Row, e *kustoErrors.Error) error { - if e != nil { - return e - } - rec := ingestResc{} - if err := r.ToStruct(&rec); err != nil { - return err - } - if err := ingest.importRec(rec, m.rankedStorageAccount); err != nil && err != errDoNotCare { - return err - } - return nil - }, - ) + + resc, err := query.ToStructs[ingestResc](dataset) + if err != nil { + return err + } + + for _, rec := range resc { + if err := ingest.importRec(rec, m.rankedStorageAccount); err != nil && !errors.Is(err, errDoNotCare) { + return err + } + } + if err != nil { return fmt.Errorf("problem reading ingestion resources from Kusto: %s", err) } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/test_helpers.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/test_helpers.go similarity index 51% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/test_helpers.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/test_helpers.go index d2d288836e..ae0166de7f 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources/test_helpers.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/resources/test_helpers.go @@ -4,54 +4,59 @@ import ( "context" "errors" "fmt" + "github.com/Azure/azure-kusto-go/azkustodata" + dataErrors "github.com/Azure/azure-kusto-go/azkustodata/errors" + v1 "github.com/Azure/azure-kusto-go/azkustodata/query/v1" "io" - "github.com/Azure/azure-kusto-go/kusto" - "github.com/Azure/azure-kusto-go/kusto/data/table" - "github.com/Azure/azure-kusto-go/kusto/data/types" - "github.com/Azure/azure-kusto-go/kusto/data/value" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "github.com/Azure/azure-kusto-go/azkustodata/value" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" ) type FakeMgmt struct { - mock *kusto.MockRows DBEqual string QueryEqual string - mgmtErr bool + err error + dataset v1.Dataset } func FakeResources(rows []value.Values, setErr bool) *FakeMgmt { - cols := table.Columns{ - { - Name: "ResourceTypeName", - Type: types.String, - }, - { - Name: "StorageRoot", - Type: types.String, - }, + cols := []v1.RawColumn{ + {ColumnName: "ResourceTypeName", ColumnType: string(types.String)}, + {ColumnName: "StorageRoot", ColumnType: string(types.String)}, } fm := NewFakeMgmt(cols, rows, setErr) return fm } -func NewFakeMgmt(columns table.Columns, rows []value.Values, setErr bool) *FakeMgmt { - mock, err := kusto.NewMockRows(columns) - if err != nil { - panic(err) - } - - for _, row := range rows { - _ = mock.Row(row) +func NewFakeMgmt(columns []v1.RawColumn, vals []value.Values, setErr bool) *FakeMgmt { + outRows := make([]v1.RawRow, 0, len(vals)) + for _, rowVal := range vals { + row := make([]interface{}, 0, len(rowVal)) + for _, val := range rowVal { + row = append(row, val.GetValue()) + } + outRows = append(outRows, v1.RawRow{Row: row}) } + var err error if setErr { - _ = mock.Error(errors.New("some error")) + err = dataErrors.ES(dataErrors.OpMgmt, dataErrors.KOther, "some error") } + dataset, _ := v1.NewDataset(context.Background(), dataErrors.OpMgmt, v1.V1{ + Tables: []v1.RawTable{ + { + TableName: "Table", + Columns: columns, + Rows: outRows, + }, + }}) return &FakeMgmt{ - mock: mock, + dataset: dataset, + err: err, } } @@ -66,11 +71,11 @@ func (f *FakeMgmt) SetQueryEquals(s string) *FakeMgmt { } func (f *FakeMgmt) SetMgmtErr() *FakeMgmt { - f.mgmtErr = true + f.err = errors.New("Set some error") return f } -func (f *FakeMgmt) Mgmt(_ context.Context, db string, query kusto.Statement, _ ...kusto.MgmtOption) (*kusto.RowIterator, error) { +func (f *FakeMgmt) Mgmt(_ context.Context, db string, query azkustodata.Statement, _ ...azkustodata.QueryOption) (v1.Dataset, error) { if f.DBEqual != "" { if db != f.DBEqual { panic(fmt.Sprintf("expected db to be %q, was %q", f.DBEqual, db)) @@ -81,38 +86,24 @@ func (f *FakeMgmt) Mgmt(_ context.Context, db string, query kusto.Statement, _ . panic(fmt.Sprintf("expected query to be %q, was %q", f.QueryEqual, db)) } } - if f.mgmtErr { - return nil, fmt.Errorf("some mgmt error") - } - iter := &kusto.RowIterator{} - if err := iter.Mock(f.mock); err != nil { - panic(err) + + if f.err != nil { + return nil, f.err } - return iter, nil + + return f.dataset, nil } func SuccessfulFakeResources() *FakeMgmt { return FakeResources( []value.Values{ { - value.String{ - Valid: true, - Value: "TempStorage", - }, - value.String{ - Valid: true, - Value: "https://account.blob.core.windows.net/storageroot0", - }, + value.NewString("TempStorage"), + value.NewString("https://account.blob.core.windows.net/storageroot0"), }, { - value.String{ - Valid: true, - Value: "SecuredReadyForAggregationQueue", - }, - value.String{ - Valid: true, - Value: "https://account.blob.core.windows.net/storageroot1", - }, + value.NewString("SecuredReadyForAggregationQueue"), + value.NewString("https://account.blob.core.windows.net/storageroot1"), }, }, false, diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/status/status_table_client.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/status/status_table_client.go similarity index 95% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/status/status_table_client.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/status/status_table_client.go index fbc9266f4e..bc9f5ec943 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/status/status_table_client.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/status/status_table_client.go @@ -1,7 +1,7 @@ package status import ( - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/resources" "github.com/Azure/azure-sdk-for-go/storage" "github.com/google/uuid" ) diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils/ingestion_utils.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/utils/ingestion_utils.go similarity index 90% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils/ingestion_utils.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/utils/ingestion_utils.go index 19a4919025..9ca42a6330 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils/ingestion_utils.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/internal/utils/ingestion_utils.go @@ -15,14 +15,14 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service" - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/resources" ) const EstimatedCompressionFactor = 11 func FetchBlobSize(fPath string, ctx context.Context, client *http.Client) (size int64, err error) { - if !strings.Contains(fPath, ".blob.") || strings.Contains(fPath, "Managed_Identity=") || strings.Contains(fPath, "Token=") { + if !strings.Contains(fPath, ".blob.") || strings.Contains(strings.ToLower(fPath), "managed_identity=") || strings.Contains(strings.ToLower(fPath), "token=") { return 0, nil } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/managed.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/managed.go similarity index 84% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/managed.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/managed.go index a57de91932..be773be0b8 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/managed.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/managed.go @@ -1,18 +1,19 @@ -package ingest +package azkustoingest import ( "bytes" "context" "fmt" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/queued" "io" "time" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/gzip" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/gzip" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/utils" "github.com/cenkalti/backoff/v4" "github.com/google/uuid" @@ -32,12 +33,19 @@ type Managed struct { } // NewManaged is a constructor for Managed. -func NewManaged(client QueryClient, db, table string, options ...Option) (*Managed, error) { - queued, err := New(client, db, table, options...) +func NewManaged(kcsb *azkustodata.ConnectionStringBuilder, options ...Option) (*Managed, error) { + o := getOptions(options) + + queuedKcsb := kcsb + if o.customIngestConnectionString != nil { + queuedKcsb = o.customIngestConnectionString + } + + queued, err := New(queuedKcsb, options...) if err != nil { return nil, err } - streaming, err := NewStreaming(client, db, table) + streaming, err := NewStreaming(kcsb, options...) if err != nil { return nil, err } @@ -48,6 +56,13 @@ func NewManaged(client QueryClient, db, table string, options ...Option) (*Manag }, nil } +func newManagedFromClients(queued *Ingestion, streaming *Streaming) *Managed { + return &Managed{ + queued: queued, + streaming: streaming, + } +} + // Attempts to stream with retries, on success - return res,nil. // If failed permanently - return err,nil. // If failed transiently - return nil,nil. @@ -201,10 +216,5 @@ func (m *Managed) newProp() properties.All { } func (m *Managed) Close() error { - var err error - err = m.queued.Close() - if err2 := m.streaming.Close(); err2 != nil { - err = errors.GetCombinedError(err, err2) - } - return err + return errors.CombineErrors(m.queued.Close(), m.streaming.Close()) } diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustoingest/mock.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/mock.go new file mode 100644 index 0000000000..def0b20494 --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/mock.go @@ -0,0 +1,102 @@ +package azkustoingest + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustodata/query" + "github.com/Azure/azure-kusto-go/azkustodata/query/v1" + "github.com/Azure/azure-kusto-go/azkustodata/types" + "net/http" +) + +type mockClient struct { + endpoint string + auth azkustodata.Authorization + onMgmt func(ctx context.Context, db string, query azkustodata.Statement, options ...azkustodata.QueryOption) (v1.Dataset, error) +} + +func (m mockClient) Query(_ context.Context, _ string, _ azkustodata.Statement, _ ...azkustodata.QueryOption) (query.Dataset, error) { + panic("not implemented") +} + +func (m mockClient) IterativeQuery(_ context.Context, _ string, _ azkustodata.Statement, _ ...azkustodata.QueryOption) (query.IterativeDataset, error) { + panic("not implemented") +} + +func (m mockClient) ClientDetails() *azkustodata.ClientDetails { + return azkustodata.NewClientDetails("test", "test") +} +func (m mockClient) HttpClient() *http.Client { + return &http.Client{} +} + +func (m mockClient) Close() error { + return nil +} + +func (m mockClient) Auth() azkustodata.Authorization { + return m.auth +} + +func (m mockClient) Endpoint() string { + return m.endpoint +} + +func (m mockClient) Mgmt(ctx context.Context, db string, query azkustodata.Statement, options ...azkustodata.QueryOption) (v1.Dataset, error) { + if m.onMgmt != nil { + rows, err := m.onMgmt(ctx, db, query, options...) + if err != nil || rows != nil { + return rows, err + } + } + + if query.String() == ".get kusto identity token" { + return v1.NewDataset(ctx, errors.OpMgmt, v1.V1{ + Tables: []v1.RawTable{ + { + TableName: "Table", + Columns: []v1.RawColumn{ + { + ColumnName: "AuthorizationContext", + ColumnType: string(types.String), + }, + }, + Rows: []v1.RawRow{ + { + Row: []interface{}{"mock"}, + Errors: nil, + }, + }, + }, + }}) + } + + return v1.NewDataset(ctx, errors.OpMgmt, v1.V1{ + Tables: []v1.RawTable{ + { + TableName: "Table", + Columns: []v1.RawColumn{ + { + ColumnName: "ResourceTypeName", + ColumnType: string(types.String), + }, + { + ColumnName: "StorageRoot", + ColumnType: string(types.String), + }, + }, + Rows: []v1.RawRow{}, + }, + }}) + +} + +func newMockClient() mockClient { + return mockClient{ + endpoint: "localhost", + auth: azkustodata.Authorization{ + TokenProvider: &azkustodata.TokenProvider{}, + }, + } +} diff --git a/vendor/github.com/Azure/azure-kusto-go/azkustoingest/query_client.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/query_client.go new file mode 100644 index 0000000000..8032944c9e --- /dev/null +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/query_client.go @@ -0,0 +1,21 @@ +package azkustoingest + +import ( + "context" + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustodata/query" + v1 "github.com/Azure/azure-kusto-go/azkustodata/query/v1" + "io" + "net/http" +) + +type QueryClient interface { + io.Closer + Auth() azkustodata.Authorization + Endpoint() string + Query(ctx context.Context, db string, query azkustodata.Statement, options ...azkustodata.QueryOption) (query.Dataset, error) + Mgmt(ctx context.Context, db string, query azkustodata.Statement, options ...azkustodata.QueryOption) (v1.Dataset, error) + IterativeQuery(ctx context.Context, db string, query azkustodata.Statement, options ...azkustodata.QueryOption) (query.IterativeDataset, error) + HttpClient() *http.Client + ClientDetails() *azkustodata.ClientDetails +} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/result.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/result.go similarity index 95% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/result.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/result.go index a97fea9c45..aa64844972 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/result.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/result.go @@ -1,4 +1,4 @@ -package ingest +package azkustoingest import ( "context" @@ -6,9 +6,9 @@ import ( "math/rand" "time" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/resources" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/status" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/resources" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/status" ) // Result provides a way for users track the state of ingestion jobs. diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/status.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/status.go similarity index 99% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/status.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/status.go index b4237b24ca..cf8d90c40f 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/status.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/status.go @@ -1,10 +1,10 @@ -package ingest +package azkustoingest import ( "fmt" "time" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" storageuid "github.com/gofrs/uuid" "github.com/google/uuid" "github.com/kylelemons/godebug/pretty" diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/streaming.go b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/streaming.go similarity index 77% rename from vendor/github.com/Azure/azure-kusto-go/kusto/ingest/streaming.go rename to vendor/github.com/Azure/azure-kusto-go/azkustoingest/streaming.go index 2adea0edc5..14924033df 100644 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/streaming.go +++ b/vendor/github.com/Azure/azure-kusto-go/azkustoingest/streaming.go @@ -1,26 +1,25 @@ -package ingest +package azkustoingest import ( "bytes" "context" "encoding/json" + "github.com/Azure/azure-kusto-go/azkustoingest/ingestoptions" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/utils" "io" "os" - "github.com/Azure/azure-kusto-go/kusto" - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/ingest/ingestoptions" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/gzip" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/properties" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/queued" - "github.com/Azure/azure-kusto-go/kusto/ingest/internal/utils" - + "github.com/Azure/azure-kusto-go/azkustodata" + "github.com/Azure/azure-kusto-go/azkustodata/errors" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/gzip" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/properties" + "github.com/Azure/azure-kusto-go/azkustoingest/internal/queued" "github.com/google/uuid" ) type streamIngestor interface { io.Closer - StreamIngest(ctx context.Context, db, table string, payload io.Reader, format kusto.DataFormatForStreaming, mappingName string, clientRequestId string, isBlobUri bool) error + StreamIngest(ctx context.Context, db, table string, payload io.Reader, format azkustodata.DataFormatForStreaming, mappingName string, clientRequestId string, isBlobUri bool) error } // Streaming provides data ingestion from external sources into Kusto. @@ -38,15 +37,33 @@ type blobUri struct { // NewStreaming is the constructor for Streaming. // More information can be found here: // https://docs.microsoft.com/en-us/azure/kusto/management/create-ingestion-mapping-command -func NewStreaming(client QueryClient, db, table string) (*Streaming, error) { - streamConn, err := kusto.NewConn(removeIngestPrefix(client.Endpoint()), client.Auth(), client.HttpClient(), client.ClientDetails()) +func NewStreaming(kcsb *azkustodata.ConnectionStringBuilder, options ...Option) (*Streaming, error) { + o := getOptions(options) + + if !o.withoutEndpointCorrection { + newKcsb := *kcsb + newKcsb.DataSource = removeIngestPrefix(newKcsb.DataSource) + kcsb = &newKcsb + } + + client, err := azkustodata.New(kcsb) + if err != nil { + return nil, err + } + + return newStreamingFromClient(client, o) +} + +func newStreamingFromClient(client QueryClient, o *Ingestion) (*Streaming, error) { + streamConn, err := azkustodata.NewConn(removeIngestPrefix(client.Endpoint()), client.Auth(), client.HttpClient(), client.ClientDetails()) if err != nil { + client.Close() return nil, err } i := &Streaming{ - db: db, - table: table, + db: o.db, + table: o.table, client: client, streamConn: streamConn, } diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/from_kusto.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/from_kusto.go deleted file mode 100644 index 428071dc93..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/from_kusto.go +++ /dev/null @@ -1,66 +0,0 @@ -package table - -// value.go provides methods for converting a row to a *struct and for converting KustoValue into Go types -// or in the reverse. - -import ( - "fmt" - "reflect" - "strings" - - "github.com/Azure/azure-kusto-go/kusto/data/value" -) - -// decodeToStruct takes a list of columns and a row to decode into "p" which will be a pointer -// to a struct (enforce in the decoder). -func decodeToStruct(cols Columns, row value.Values, p interface{}) error { - t := reflect.TypeOf(p) - v := reflect.ValueOf(p) - fields := newFields(cols, t) - - for i, col := range cols { - if err := fields.convert(col, row[i], t, v); err != nil { - return err - } - } - return nil -} - -// fields represents the fields inside a struct. -type fields struct { - colNameToFieldName map[string]string -} - -// newFields takes in the Columns from our row and the reflect.Type of our *struct. -func newFields(cols Columns, ptr reflect.Type) fields { - nFields := fields{colNameToFieldName: map[string]string{}} - for i := 0; i < ptr.Elem().NumField(); i++ { - field := ptr.Elem().Field(i) - if tag := field.Tag.Get("kusto"); strings.TrimSpace(tag) != "" { - nFields.colNameToFieldName[tag] = field.Name - } else { - nFields.colNameToFieldName[field.Name] = field.Name - } - } - - return nFields -} - -// convert converts a KustoValue that is for Column col into "v" reflect.Value with reflect.Type "t". -func (f fields) convert(col Column, k value.Kusto, t reflect.Type, v reflect.Value) error { - fieldName, ok := f.colNameToFieldName[col.Name] - if !ok { - return nil - } - - if fieldName == "-" { - return nil - } - - err := k.Convert(v.Elem().FieldByName(fieldName)) - if err != nil { - return fmt.Errorf("column %s could not store in struct.%s: %s", col.Name, fieldName, err.Error()) - } - - return nil -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/table.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/table.go deleted file mode 100644 index d7182b6c8e..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/table/table.go +++ /dev/null @@ -1,174 +0,0 @@ -// Package table contains types that represent the makeup of a Kusto table. -package table - -import ( - "encoding/csv" - "fmt" - "reflect" - "strings" - - "github.com/Azure/azure-kusto-go/kusto/data/errors" - "github.com/Azure/azure-kusto-go/kusto/data/types" - "github.com/Azure/azure-kusto-go/kusto/data/value" -) - -// Column describes a column descriptor. -type Column struct { - // Name is the name of the column. - Name string `json:"ColumnName"` - // Type is the type of value stored in this column. These are described - // via constants starting with CT. - Type types.Column `json:"ColumnType"` -} - -// Columns is a set of columns. -type Columns []Column - -func (c Columns) Validate() error { - if len(c) == 0 { - return fmt.Errorf("Columns is zero length") - } - - names := make(map[string]bool, len(c)) - - for i, col := range c { - if col.Name == "" { - return fmt.Errorf("column[%d].Name is empty string", i) - } - if names[col.Name] { - return fmt.Errorf("column[%d].Name(%s) is already defined", i, col.Name) - } - names[col.Name] = true - - if !col.Type.Valid() { - return fmt.Errorf("column[%d] if of type %q, which is not valid", i, col.Type) - } - } - return nil -} - -// Row represents a row of Kusto data. Methods are not thread-safe. -type Row struct { - // ColumnType contains all the column type information for the row. - ColumnTypes Columns - // Values is the list of values that make up the row. - Values value.Values - // Op is the operation that resulted in the row. This is for internal use. - Op errors.Op - // Replace indicates whether the existing result set should be cleared and replaced with this row. - Replace bool - - columnNames []string -} - -// ColumnNames returns a list of all column names. -func (r *Row) ColumnNames() []string { - if r.columnNames == nil { - for _, col := range r.ColumnTypes { - r.columnNames = append(r.columnNames, col.Name) - } - } - return r.columnNames -} - -// Size returns the number of columns contained in Row. -func (r *Row) Size() int { - return len(r.ColumnTypes) -} - -// Columns fetches all column names in the row at once. -// The name of the kth column will be decoded into the kth argument to Columns. -// The number of arguments must be equal to the number of columns. -// Pass nil to specify that a column should be ignored. -// ptrs may be either the *string or *types.Column type. An error in decoding may leave -// some ptrs set and others not. -func (r *Row) Columns(ptrs ...interface{}) error { - if len(ptrs) != len(r.ColumnTypes) { - return errors.ES(r.Op, errors.KClientArgs, ".Columns() requires %d arguments for this row, had %d", len(r.ColumnTypes), len(ptrs)) - } - - for i, col := range r.ColumnTypes { - if ptrs[i] == nil { - continue - } - switch v := ptrs[i].(type) { - case *string: - *v = col.Name - case *Column: - v.Name = col.Name - v.Type = col.Type - default: - return errors.ES(r.Op, errors.KClientArgs, ".Columns() received argument at position %d that was not a *string, *types.Columns: was %T", i, ptrs[i]) - } - } - - return nil -} - -// ExtractValues fetches all values in the row at once. -// The value of the kth column will be decoded into the kth argument to ExtractValues. -// The number of arguments must be equal to the number of columns. -// Pass nil to specify that a column should be ignored. -// ptrs should be compatible with column types. An error in decoding may leave -// some ptrs set and others not. -func (r *Row) ExtractValues(ptrs ...interface{}) error { - if len(ptrs) != len(r.ColumnTypes) { - return errors.ES(r.Op, errors.KClientArgs, ".Columns() requires %d arguments for this row, had %d", len(r.ColumnTypes), len(ptrs)) - } - - for i, val := range r.Values { - if ptrs[i] == nil { - continue - } - if err := val.Convert(reflect.ValueOf(ptrs[i]).Elem()); err != nil { - return err - } - } - - return nil -} - -// ToStruct fetches the columns in a row into the fields of a struct. p must be a pointer to struct. -// The rules for mapping a row's columns into a struct's exported fields are: -// -// 1. If a field has a `kusto: "column_name"` tag, then decode column -// 'column_name' into the field. A special case is the `column_name: "-"` -// tag, which instructs ToStruct to ignore the field during decoding. -// -// 2. Otherwise, if the name of a field matches the name of a column (ignoring case), -// decode the column into the field. -// -// Slice and pointer fields will be set to nil if the source column is a null value, and a -// non-nil value if the column is not NULL. To decode NULL values of other types, use -// one of the kusto types (Int, Long, Dynamic, ...) as the type of the destination field. -// You can check the .Valid field of those types to see if the value was set. -func (r *Row) ToStruct(p interface{}) error { - // Check if p is a pointer to a struct - if t := reflect.TypeOf(p); t == nil || t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { - return errors.ES(r.Op, errors.KClientArgs, "type %T is not a pointer to a struct", p) - } - if len(r.ColumnTypes) != len(r.Values) { - return errors.ES(r.Op, errors.KClientArgs, "row does not have the correct number of values(%d) for the number of columns(%d)", len(r.Values), len(r.ColumnTypes)) - } - - return decodeToStruct(r.ColumnTypes, r.Values, p) -} - -// String implements fmt.Stringer for a Row. This simply outputs a CSV version of the row. -func (r *Row) String() string { - line := []string{} - for _, v := range r.Values { - line = append(line, v.String()) - } - b := &strings.Builder{} - w := csv.NewWriter(b) - err := w.Write(line) - if err != nil { - return "" - } - w.Flush() - return b.String() -} - -// Rows is a set of rows. -type Rows []*Row diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/bool.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/bool.go deleted file mode 100644 index a8fda7a25c..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/bool.go +++ /dev/null @@ -1,71 +0,0 @@ -package value - -import ( - "fmt" - "reflect" -) - -// Bool represents a Kusto boolean type. Bool implements Kusto. -type Bool struct { - // Value holds the value of the type. - Value bool - // Valid indicates if this value was set. - Valid bool -} - -func (Bool) isKustoVal() {} - -// String implements fmt.Stringer. -func (bo Bool) String() string { - if !bo.Valid { - return "" - } - if bo.Value { - return "true" - } - return "false" -} - -// Unmarshal unmarshals i into Bool. i must be a bool or nil. -func (bo *Bool) Unmarshal(i interface{}) error { - if i == nil { - bo.Value = false - bo.Valid = false - return nil - } - v, ok := i.(bool) - if !ok { - return fmt.Errorf("Column with type 'bool' had value that was %T", i) - } - bo.Value = v - bo.Valid = true - return nil -} - -// Convert Bool into reflect value. -func (bo Bool) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.Kind() == reflect.Bool: - if bo.Valid { - v.SetBool(bo.Value) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(bool))): - if bo.Valid { - b := new(bool) - if bo.Value { - *b = true - } - v.Set(reflect.ValueOf(b)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(Bool{})): - v.Set(reflect.ValueOf(bo)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&Bool{})): - v.Set(reflect.ValueOf(&bo)) - return nil - } - return fmt.Errorf("Column was type Kusto.Bool, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/datetime.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/datetime.go deleted file mode 100644 index dbc96574bd..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/datetime.go +++ /dev/null @@ -1,81 +0,0 @@ -package value - -import ( - "fmt" - "reflect" - "time" -) - -// DateTime represents a Kusto datetime type. DateTime implements Kusto. -type DateTime struct { - // Value holds the value of the type. - Value time.Time - // Valid indicates if this value was set. - Valid bool -} - -// String implements fmt.Stringer. -func (d DateTime) String() string { - if !d.Valid { - return "" - } - return fmt.Sprint(d.Value.Format(time.RFC3339Nano)) -} - -func (DateTime) isKustoVal() {} - -// Marshal marshals the DateTime into a Kusto compatible string. -func (d DateTime) Marshal() string { - if !d.Valid { - return time.Time{}.Format(time.RFC3339Nano) - } - return d.Value.Format(time.RFC3339Nano) -} - -// Unmarshal unmarshals i into DateTime. i must be a string representing RFC3339Nano or nil. -func (d *DateTime) Unmarshal(i interface{}) error { - if i == nil { - d.Value = time.Time{} - d.Valid = false - return nil - } - - str, ok := i.(string) - if !ok { - return fmt.Errorf("Column with type 'datetime' had value that was %T", i) - } - - t, err := time.Parse(time.RFC3339Nano, str) - if err != nil { - return fmt.Errorf("Column with type 'datetime' had value %s which did not parse: %s", str, err) - } - d.Value = t - d.Valid = true - - return nil -} - -// Convert DateTime into reflect value. -func (d DateTime) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.AssignableTo(reflect.TypeOf(time.Time{})): - if d.Valid { - v.Set(reflect.ValueOf(d.Value)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(time.Time))): - if d.Valid { - t := &d.Value - v.Set(reflect.ValueOf(t)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(DateTime{})): - v.Set(reflect.ValueOf(d)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&DateTime{})): - v.Set(reflect.ValueOf(&d)) - return nil - } - return fmt.Errorf("Column was type Kusto.DateTime, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/decimal.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/decimal.go deleted file mode 100644 index 26d6f47975..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/decimal.go +++ /dev/null @@ -1,82 +0,0 @@ -package value - -import ( - "fmt" - "math/big" - "reflect" - "regexp" -) - -// Decimal represents a Kusto decimal type. Decimal implements Kusto. -// Because Go does not have a dynamic decimal type that meets all needs, Decimal -// provides the string representation for you to unmarshal into. -type Decimal struct { - // Value holds the value of the type. - Value string - // Valid indicates if this value was set. - Valid bool -} - -func (Decimal) isKustoVal() {} - -// String implements fmt.Stringer. -func (d Decimal) String() string { - if !d.Valid { - return "" - } - return d.Value -} - -// ParseFloat provides builtin support for Go's *big.Float conversion where that type meets your needs. -func (d *Decimal) ParseFloat(base int, prec uint, mode big.RoundingMode) (f *big.Float, b int, err error) { - return big.ParseFloat(d.Value, base, prec, mode) -} - -var DecRE = regexp.MustCompile(`^((\d+\.?\d*)|(\d*\.?\d+))$`) // Matches decimal numbers, with or without decimal dot, with optional parts missing. - -// Unmarshal unmarshals i into Decimal. i must be a string representing a decimal type or nil. -func (d *Decimal) Unmarshal(i interface{}) error { - if i == nil { - d.Value = "" - d.Valid = false - return nil - } - - v, ok := i.(string) - if !ok { - return fmt.Errorf("Column with type 'decimal' had type %T", i) - } - - if !DecRE.MatchString(v) { - return fmt.Errorf("column with type 'decimal' does not appear to be a decimal number, was %v", v) - } - - d.Value = v - d.Valid = true - return nil -} - -// Convert Decimal into reflect value. -func (d Decimal) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.Kind() == reflect.String: - if d.Valid { - v.Set(reflect.ValueOf(d.Value)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(string))): - if d.Valid { - i := &d.Value - v.Set(reflect.ValueOf(i)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(Decimal{})): - v.Set(reflect.ValueOf(d)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&Decimal{})): - v.Set(reflect.ValueOf(&d)) - return nil - } - return fmt.Errorf("Column was type Kusto.Decimal, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/guid.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/guid.go deleted file mode 100644 index 321bdacd4a..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/guid.go +++ /dev/null @@ -1,71 +0,0 @@ -package value - -import ( - "fmt" - "reflect" - - "github.com/google/uuid" -) - -// GUID represents a Kusto GUID type. GUID implements Kusto. -type GUID struct { - // Value holds the value of the type. - Value uuid.UUID - // Valid indicates if this value was set. - Valid bool -} - -func (GUID) isKustoVal() {} - -// String implements fmt.Stringer. -func (g GUID) String() string { - if !g.Valid { - return "" - } - return g.Value.String() -} - -// Unmarshal unmarshals i into GUID. i must be a string representing a GUID or nil. -func (g *GUID) Unmarshal(i interface{}) error { - if i == nil { - g.Value = uuid.UUID{} - g.Valid = false - return nil - } - str, ok := i.(string) - if !ok { - return fmt.Errorf("Column with type 'guid' was not stored as a string, was %T", i) - } - u, err := uuid.Parse(str) - if err != nil { - return fmt.Errorf("Column with type 'guid' did not store a valid uuid(%s): %s", str, err) - } - g.Value = u - g.Valid = true - return nil -} - -// Convert GUID into reflect value. -func (g GUID) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.AssignableTo(reflect.TypeOf(uuid.UUID{})): - if g.Valid { - v.Set(reflect.ValueOf(g.Value)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(uuid.UUID))): - if g.Valid { - t := &g.Value - v.Set(reflect.ValueOf(t)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(GUID{})): - v.Set(reflect.ValueOf(g)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&GUID{})): - v.Set(reflect.ValueOf(&g)) - return nil - } - return fmt.Errorf("Column was type Kusto.GUID, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/int.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/int.go deleted file mode 100644 index c7b4cf6bf7..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/int.go +++ /dev/null @@ -1,103 +0,0 @@ -package value - -import ( - "encoding/json" - "fmt" - "math" - "reflect" - "strconv" -) - -// Int represents a Kusto int type. Values int type's are int32 values. Int implements Kusto. -type Int struct { - // Value holds the value of the type. - Value int32 - // Valid indicates if this value was set. - Valid bool -} - -func (Int) isKustoVal() {} - -// String implements fmt.Stringer. -func (in Int) String() string { - if !in.Valid { - return "" - } - return strconv.Itoa(int(in.Value)) -} - -// Unmarshal unmarshals i into Int. i must be an int32 or nil. -func (in *Int) Unmarshal(i interface{}) error { - if i == nil { - in.Value = 0 - in.Valid = false - return nil - } - - var myInt int64 - - switch v := i.(type) { - case json.Number: - var err error - myInt, err = v.Int64() - if err != nil { - return fmt.Errorf("Column with type 'int' had value json.Number that had error on .Int64(): %s", err) - } - case float64: - if v != math.Trunc(v) { - return fmt.Errorf("Column with type 'int' had value float64(%v) that did not represent a whole number", v) - } - myInt = int64(v) - case int: - myInt = int64(v) - default: - return fmt.Errorf("Column with type 'int' had value that was not a json.Number or int, was %T", i) - } - - if myInt > math.MaxInt32 { - return fmt.Errorf("Column with type 'int' had value that was greater than an int32 can hold, was %d", myInt) - } - in.Value = int32(myInt) - in.Valid = true - return nil -} - -var ( - int32PtrType = reflect.TypeOf((*int32)(nil)) - int32Type = int32PtrType.Elem() - kustoIntPtrType = reflect.TypeOf((*Int)(nil)) - kustoIntType = kustoIntPtrType.Elem() -) - -// Convert Int into reflect value. -func (in Int) Convert(v reflect.Value) error { - t := v.Type() - switch t { - case int32Type: - if in.Valid { - v.SetInt(int64(in.Value)) - } - case kustoIntType: - v.Set(reflect.ValueOf(in)) - case kustoIntPtrType: - v.Set(reflect.ValueOf(&in)) - default: - switch { - case int32Type.ConvertibleTo(t): - if in.Valid { - v.Set(reflect.ValueOf(in.Value).Convert(t)) - } - case int32PtrType.ConvertibleTo(t): - if in.Valid { - v.Set(reflect.ValueOf(&in.Value).Convert(t)) - } - case kustoIntType.ConvertibleTo(t): - v.Set(reflect.ValueOf(in).Convert(t)) - case kustoIntPtrType.ConvertibleTo(t): - v.Set(reflect.ValueOf(&in).Convert(t)) - default: - return fmt.Errorf("Column was type Kusto.Int, receiver had base Kind %s ", t.Kind()) - } - } - return nil -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/long.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/long.go deleted file mode 100644 index 85ab72524c..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/long.go +++ /dev/null @@ -1,86 +0,0 @@ -package value - -import ( - "encoding/json" - "fmt" - "math" - "reflect" - "strconv" -) - -// Long represents a Kusto long type, which is an int64. Long implements Kusto. -type Long struct { - // Value holds the value of the type. - Value int64 - // Valid indicates if this value was set. - Valid bool -} - -func (Long) isKustoVal() {} - -// String implements fmt.Stringer. -func (l Long) String() string { - if !l.Valid { - return "" - } - return strconv.Itoa(int(l.Value)) -} - -// Unmarshal unmarshals i into Long. i must be an int64 or nil. -func (l *Long) Unmarshal(i interface{}) error { - if i == nil { - l.Value = 0 - l.Valid = false - return nil - } - - var myInt int64 - - switch v := i.(type) { - case json.Number: - var err error - myInt, err = v.Int64() - if err != nil { - return fmt.Errorf("Column with type 'long' had value json.Number that had error on .Int64(): %s", err) - } - case int: - myInt = int64(v) - case float64: - if v != math.Trunc(v) { - return fmt.Errorf("Column with type 'int' had value float64(%v) that did not represent a whole number", v) - } - myInt = int64(v) - default: - return fmt.Errorf("Column with type 'ong' had value that was not a json.Number or int, was %T", i) - } - - l.Value = myInt - l.Valid = true - return nil -} - -// Convert Long into reflect value. -func (l Long) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.Kind() == reflect.Int64: - if l.Valid { - v.Set(reflect.ValueOf(l.Value)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(int64))): - if l.Valid { - i := &l.Value - fmt.Println(i) - v.Set(reflect.ValueOf(i)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(Long{})): - v.Set(reflect.ValueOf(l)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&Long{})): - v.Set(reflect.ValueOf(&l)) - return nil - } - return fmt.Errorf("Column was type Kusto.Long, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/real.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/real.go deleted file mode 100644 index 9dc396df66..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/real.go +++ /dev/null @@ -1,79 +0,0 @@ -package value - -import ( - "encoding/json" - "fmt" - "reflect" - "strconv" -) - -// Real represents a Kusto real type. Real implements Kusto. -type Real struct { - // Value holds the value of the type. - Value float64 - // Valid indicates if this value was set. - Valid bool -} - -func (Real) isKustoVal() {} - -// String implements fmt.Stringer. -func (r Real) String() string { - if !r.Valid { - return "" - } - return strconv.FormatFloat(r.Value, 'e', -1, 64) -} - -// Unmarshal unmarshals i into Real. i must be a json.Number(that is a float64), float64 or nil. -func (r *Real) Unmarshal(i interface{}) error { - if i == nil { - r.Value = 0.0 - r.Valid = false - return nil - } - - var myFloat float64 - - switch v := i.(type) { - case json.Number: - var err error - myFloat, err = v.Float64() - if err != nil { - return fmt.Errorf("Column with type 'real' had value json.Number that had error on .Float64(): %s", err) - } - case float64: - myFloat = v - default: - return fmt.Errorf("Column with type 'real' had value that was not a json.Number or float64, was %T", i) - } - - r.Value = myFloat - r.Valid = true - return nil -} - -// Convert Real into reflect value. -func (r Real) Convert(v reflect.Value) error { - t := v.Type() - switch { - case t.Kind() == reflect.Float64: - if r.Valid { - v.Set(reflect.ValueOf(r.Value)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(new(float64))): - if r.Valid { - i := &r.Value - v.Set(reflect.ValueOf(i)) - } - return nil - case t.ConvertibleTo(reflect.TypeOf(Real{})): - v.Set(reflect.ValueOf(r)) - return nil - case t.ConvertibleTo(reflect.TypeOf(&Real{})): - v.Set(reflect.ValueOf(&r)) - return nil - } - return fmt.Errorf("Column was type Kusto.Real, receiver had base Kind %s ", t.Kind()) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/value.go b/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/value.go deleted file mode 100644 index 35c59e46dc..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/data/value/value.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Package value holds Kusto data value representations. All types provide a Kusto that -stores the native value and Valid which indicates if the value was set or was null. - -# Kusto Value - -A value.Kusto can hold types that represent Kusto Scalar types that define column data. -We represent that with an interface: - - type Kusto interface - -This interface can hold the following values: - - value.Bool - value.Int - value.Long - value.Real - value.Decimal - value.String - value.Dynamic - value.DateTime - value.Timespan - -Each type defined above has at minimum two fields: - - .Value - The type specific value - .Valid - True if the value was non-null in the Kusto table - -Each provides at minimum the following two methods: - - .String() - Returns the string representation of the value. - .Unmarshal() - Unmarshals the value into a standard Go type. - -The Unmarshal() is for internal use, it should not be needed by an end user. Use .Value or table.Row.ToStruct() instead. -*/ -package value - -import "reflect" - -// Kusto represents a Kusto value. -type Kusto interface { - isKustoVal() - // String implements fmt.Stringer(). - String() string - // Convert into reflect value. - Convert(v reflect.Value) error -} - -// Values is a list of Kusto values, usually an ordered row. -type Values []Kusto diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/doc.go b/vendor/github.com/Azure/azure-kusto-go/kusto/doc.go deleted file mode 100644 index 9934bec77f..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/doc.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2020 Microsoft Corporation. All rights reserved. -// Use of this source code is governed by an MIT -// license that can be found in the LICENSE file. -// -// Additional licenses for third-pary packages can be found in third_party_licenses/ - -/* -Package kusto provides a client for accessing Azure Data Explorer, also known as Kusto. - -For details on the Azure Kusto service, see: https://azure.microsoft.com/en-us/services/data-explorer/ - -For general documentation on APIs and the Kusto query language, see: https://docs.microsoft.com/en-us/azure/data-explorer/ - -## Examples - -Examples for various scenarios can be found on [pkg.go.dev](https://pkg.go.dev/github.com/Azure/azure-kusto-go#readme-examples) or in the example*_test.go files in our GitHub repo for [azure-kusto-go](https://github.com/Azure/azure-kusto-go/tree/master/kusto). - -### Create the connection string - -Azure Data Explorer (Kusto) connection strings are created using a connection string builder for an existing Azure Data Explorer (Kusto) cluster endpoint of the form `https://..kusto.windows.net`. - -```go -kustoConnectionStringBuilder := kusto.NewConnectionStringBuilder(endpoint) -``` - -### Create and authenticate the client - -Azure Data Explorer (Kusto) clients are created from a connection string and authenticated using a credential from the [Azure Identity package][azure_identity_pkg], like [DefaultAzureCredential][default_azure_credential]. -You can also authenticate a client using a system- or user-assigned managed identity with Azure Active Directory (AAD) credentials. - -#### Using the `DefaultAzureCredential` - -```go -// kusto package is: github.com/Azure/azure-kusto-go/kusto - -// Initialize a new kusto client using the default Azure credential -kustoConnectionString := kustoConnectionStringBuilder.WithDefaultAzureCredential() -client, err = kusto.New(kustoConnectionString) - - if err != nil { - panic("add error handling") - } - -// Be sure to close the client when you're done. (Error handling omitted for brevity.) -defer client.Close() -``` - -#### Using the `az cli` - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithAzCli() -client, err = kusto.New(kustoConnectionString) -``` - -#### Using a system-assigned managed identity - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithSystemManagedIdentity() -client, err = kusto.New(kustoConnectionString) -``` - -#### Using a user-assigned managed identity - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithUserManagedIdentity(clientID) -client, err = kusto.New(kustoConnectionString) -``` - -#### Using a bearer token - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithApplicationToken(appId, token) -client, err = kusto.New(kustoConnectionString) -``` - -#### Using an app id and secret - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithAadAppKey(clientID, clientSecret, tenantID) -client, err = kusto.New(kustoConnectionString) -``` - -#### Using an application certificate - -```go -kustoConnectionString := kustoConnectionStringBuilder.WithAppCertificate(appId, certificate, thumbprint, sendCertChain, authorityID) -client, err = kusto.New(kustoConnectionString) -``` - -### Querying - -#### Simple queries - -* Works for queries and management commands. -* Limited to queries that can be built using a string literal known at compile time. - -The simplest queries can be built using `kql.New`: - -```go -query := kql.New("systemNodes | project CollectionTime, NodeId") -``` - -Queries can only be built using a string literals known at compile time, and special methods for specific parts of the query. -The reason for this is to discourage the use of string concatenation to build queries, which can lead to security vulnerabilities. - -#### Queries with parameters - -* Can re-use the same query with different parameters. -* Only work for queries, management commands are not supported. - -It is recommended to use parameters for queries that contain user input. -Management commands can not use parameters, and therefore should be built using the builder (see next section). - -Parameters can be implicitly referenced in a query: - -```go -query := kql.New("systemNodes | project CollectionTime, NodeId | where CollectionTime > startTime and NodeId == nodeIdValue") -``` - -Here, `startTime` and `nodeIdValue` are parameters that can be passed to the query. - -To Pass the parameters values to the query, create `kql.Parameters`: - -``` -params := kql.NewParameters().AddDateTime("startTime", dt).AddInt("nodeIdValue", 1) -``` - -And then pass it to the `Query` method, as an option: -```go -results, err := client.Query(ctx, database, query, QueryParameters(params)) - - if err != nil { - panic("add error handling") - } - -// You can see the generated parameters using the ToDeclarationString() method: -fmt.Println(params.ToDeclarationString()) // declare query_parameters(startTime:datetime, nodeIdValue:int); -``` - -#### Queries with inline parameters -* Works for queries and management commands. -* More involved building of queries, but allows for more flexibility. - -Queries with runtime data can be built using `kql.New`. -The builder will only accept the correct types for each part of the query, and will escape any special characters in the data. - -For example, here is a query that dynamically accepts values for the table name, and the comparison parameters for the columns: - -```go -dt, _ := time.Parse(time.RFC3339Nano, "2020-03-04T14:05:01.3109965Z") -tableName := "system nodes" -value := 1 - -query := kql.New("") - - .AddTable(tableName) - .AddLiteral(" | where CollectionTime == ").AddDateTime(dt) - .AddLiteral(" and ") - .AddLiteral("NodeId == ").AddInt(value) - -// To view the query string, use the String() method: -fmt.Println(query.String()) -// Output: ['system nodes'] | where CollectionTime == datetime(2020-03-04T14:05:01.3109965Z) and NodeId == int(1) -``` - -Building queries like this is useful for queries that are built from user input, or for queries that are built from a template, and are valid for management commands too. - -#### Query For Rows - -The kusto `table` package queries data into a ***table.Row** which can be printed or have the column data extracted. - -```go -// table package is: github.com/Azure/azure-kusto-go/kusto/data/table - -// Query our database table "systemNodes" for the CollectionTimes and the NodeIds. -iter, err := client.Query(ctx, "database", query) - - if err != nil { - panic("add error handling") - } - -defer iter.Stop() - -// .Do() will call the function for every row in the table. -err = iter.DoOnRowOrError( - - func(row *table.Row, e *kustoErrors.Error) error { - if e != nil { - return e - } - if row.Replace { - fmt.Println("---") // Replace flag indicates that the query result should be cleared and replaced with this row - } - fmt.Println(row) // As a convenience, printing a *table.Row will output csv - return nil - }, - -) - - if err != nil { - panic("add error handling") - } - -``` - -#### Query Into Structs - -Users will often want to turn the returned data into Go structs that are easier to work with. The ***table.Row** object -that is returned supports this via the `.ToStruct()` method. - -```go -// NodeRec represents our Kusto data that will be returned. - - type NodeRec struct { - // ID is the table's NodeId. We use the field tag here to instruct our client to convert NodeId to ID. - ID int64 `kusto:"NodeId"` - // CollectionTime is Go representation of the Kusto datetime type. - CollectionTime time.Time - } - -iter, err := client.Query(ctx, "database", query) - - if err != nil { - panic("add error handling") - } - -defer iter.Stop() - -recs := []NodeRec{} -err = iter.DoOnRowOrError( - - func(row *table.Row, e *kustoErrors.Error) error { - if e != nil { - return e - } - rec := NodeRec{} - if err := row.ToStruct(&rec); err != nil { - return err - } - if row.Replace { - recs = recs[:0] // Replace flag indicates that the query result should be cleared and replaced with this row - } - recs = append(recs, rec) - return nil - }, - -) - - if err != nil { - panic("add error handling") - } - -``` - -### Ingestion - -The `ingest` package provides access to Kusto's ingestion service for importing data into Kusto. This requires -some prerequisite knowledge of acceptable data formats, mapping references, etc. - -That documentation can be found [here](https://docs.microsoft.com/en-us/azure/kusto/management/data-ingestion/) - -If ingesting data from memory, it is suggested that you stream the data in via `FromReader()` passing in the reader -from an `io.Pipe()`. The data will not begin ingestion until the writer closes. - -#### Creating a queued ingestion client - -Setup is quite simple, simply pass a `*kusto.Client`, the name of the database and table you wish to ingest into. - -```go -in, err := ingest.New(kustoClient, "database", "table") - - if err != nil { - panic("add error handling") - } - -// Be sure to close the ingestor when you're done. (Error handling omitted for brevity.) -defer in.Close() -``` - -#### Other Ingestion Clients - -There are other ingestion clients that can be used for different ingestion scenarios. The `ingest` package provides -the following clients: - - Queued Ingest - `ingest.New()` - the default client, uses queues and batching to ingest data. Most reliable. - - Streaming Ingest - `ingest.NewStreaming()` - Directly streams data into the engine. Fast, but is limited with size and can fail. - - Managed Streaming Ingest - `ingest.NewManaged()` - Combines a streaming ingest client with a queued ingest client to provide a reliable ingestion method that is fast and can ingest large amounts of data. - Managed Streaming will try to stream the data, and if it fails multiple times, it will fall back to a queued ingestion. - -#### Ingestion From a File - -Ingesting a local file requires simply passing the path to the file to be ingested: - -```go - - if _, err := in.FromFile(ctx, "/path/to/a/local/file"); err != nil { - panic("add error handling") - } - -``` - -`FromFile()` will accept Unix path names on Unix platforms and Windows path names on Windows platforms. -The file will not be deleted after upload (there is an option that will allow that though). - -#### From a Blob Storage File - -This package will also accept ingestion from an Azure Blob Storage file: - -```go - - if _, err := in.FromFile(ctx, "https://myaccount.blob.core.windows.net/$root/myblob"); err != nil { - panic("add error handling") - } - -``` - -This will ingest a file from Azure Blob Storage. We only support `https://` paths and your domain name may differ than what is here. - -#### Ingestion from an io.Reader - -Sometimes you want to ingest a stream of data that you have in memory without writing to disk. You can do this simply by chunking the -data via an `io.Reader`. - -```go -r, w := io.Pipe() - -enc := json.NewEncoder(w) - - go func() { - defer w.Close() - for _, data := range dataSet { - if err := enc.Encode(data); err != nil { - panic("add error handling") - } - } - }() - - if _, err := in.FromReader(ctx, r); err != nil { - panic("add error handling") - } - -``` - -It is important to remember that `FromReader()` will terminate when it receives an `io.EOF` from the `io.Reader`. Use `io.Readers` that won't -return `io.EOF` until the `io.Writer` is closed (such as `io.Pipe`). - -# Mocking - -To support mocking for this client in your code for hermetic testing purposes, this client supports mocking the data -returned by our RowIterator object. Please see the MockRows documentation for code examples. - -# Package Examples - -Below you will find a simple and complex example of doing Query() the represent compiled code: -*/ -package kusto diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/doc.go b/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/doc.go deleted file mode 100644 index b59d696e00..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/doc.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Package ingest provides data ingestion from various external sources into Kusto. - -For more information on Kusto Data Ingestion, please see: https://docs.microsoft.com/en-us/azure/kusto/management/data-ingestion/ - -# Create a client - -Creating a client simply requires a *kusto.Client, the name of the database and the name of the table to be ingested into. - - in, err := ingest.New(kustoClient, "database", "table") - if err != nil { - panic("add error handling") - } - -# Ingestion from a local file - -Ingesting a local file requires simply passing the path to the file to be ingested: - - if _, err := in.FromFile(ctx, "/path/to/a/local/file"); err != nil { - panic("add error handling") - } - -FromFile() will accept Unix path names on Unix platforms and Windows path names on Windows platforms. -The file will not be deleted after upload (there is an option that will allow that though). - -# Ingestion from an Azure Blob Storage file - -This package will also accept ingestion from an Azure Blob Storage file: - - if _, err := in.FromFile(ctx, "https://myaccount.blob.core.windows.net/$root/myblob"); err != nil { - panic("add error handling") - } - -This will ingest a file from Azure Blob Storage. We only support https:// paths and your domain name may differ than what is here. - -# Ingestion from an io.Reader - -Sometimes you want to ingest a stream of data that you have in memory without writing to disk. You can do this simply by chunking the -data via an io.Reader. - - r, w := io.Pipe() - - enc := json.NewEncoder(w) - go func() { - defer w.Close() - for _, data := range dataSet { - if err := enc.Encode(data); err != nil { - panic("add error handling") - } - } - }() - - if _, err := in.FromReader(ctx, r); err != nil { - panic("add error handling") - } - -It is important to remember that FromReader() will terminate when it receives an io.EOF from the io.Reader. Use io.Readers that won't -return io.EOF until the io.Writer is closed (such as io.Pipe). - -# Ingestion from a Stream - -Instestion from a stream commits blocks of fully formed data encodes (JSON, AVRO, ...) into Kusto: - - if err := in.Stream(ctx , jsonEncodedData, ingest.JSON, "mappingName"); err != nil { - panic("add error handling") - } - -# Ingestion with Status Reporting - -You can use Kusto Go SDK to get table-based status reporting of ingestion operations. -Ingestion commands run using FromFile() and FromReader() return an error and a channel that can be waited upon for a final status. -If the error is not nil, the operation has failed locally. -If the error is nil and Table Status Reporting option was used, the SDK user can wait on the channel for a success (nil) or failure (Error) status. - -Note! -This feature is not suitable for users running ingestion at high rates, and may slow down the ingestion operation. - - status, err := ingestor.FromFile(ctx, "/path/to/file", ingest.ReportResultToTable()) - if err != nil { - // The ingestion command failed to be sent, Do something - } - - err = <-status.Wait(ctx) - if err != nil { - // the operation complete with an error - if ingest.IsRetryable(err) { - // Handle retries - } else { - // inspect the failure - // statusCode, _ := ingest.GetIngestionStatus(err) - // failureStatus, _ := ingest.GetIngestionFailureStatus(err) - } - } -*/ -package ingest diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/endpoint.go b/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/endpoint.go deleted file mode 100644 index c36ed5c1b0..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/endpoint.go +++ /dev/null @@ -1,11 +0,0 @@ -package ingest - -import ( - "strings" -) - -const ingestPrefix = "ingest-" - -func removeIngestPrefix(s string) string { - return strings.Replace(s, ingestPrefix, "", 1) -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/query_client.go b/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/query_client.go deleted file mode 100644 index d687d99074..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/ingest/query_client.go +++ /dev/null @@ -1,19 +0,0 @@ -package ingest - -import ( - "context" - "io" - "net/http" - - "github.com/Azure/azure-kusto-go/kusto" -) - -type QueryClient interface { - io.Closer - Auth() kusto.Authorization - Endpoint() string - Query(ctx context.Context, db string, query kusto.Statement, options ...kusto.QueryOption) (*kusto.RowIterator, error) - Mgmt(ctx context.Context, db string, query kusto.Statement, options ...kusto.MgmtOption) (*kusto.RowIterator, error) - HttpClient() *http.Client - ClientDetails() *kusto.ClientDetails -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/frames.go b/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/frames.go deleted file mode 100644 index f4763819f5..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/frames.go +++ /dev/null @@ -1,98 +0,0 @@ -package frames - -import ( - "context" - "fmt" - "io" - - "github.com/Azure/azure-kusto-go/kusto/data/errors" -) - -const ( - // TypeDataTable is the .FrameType that indicates a Kusto DataTable. - TypeDataTable = "DataTable" - // TypeDataSetCompletion is the .FrameType that indicates a Kusto DataSetCompletion. - TypeDataSetCompletion = "DataSetCompletion" - // TypeDataSetHeader is the .FrameType that indicates a Kusto DataSetHeader. - TypeDataSetHeader = "DataSetHeader" - // TypeTableHeader is the .FrameType that indicates a Kusto TableHeader. - TypeTableHeader = "TableHeader" - // TypeTableFragment is the .FrameType that indicates a Kusto TableFragment. - TypeTableFragment = "TableFragment" - // TypeTableProgress is the .FrameType that indicates a Kusto TableProgress. - TypeTableProgress = "TableProgress" - // TypeTableCompletion is the .FrameType that indicates a Kusto TableCompletion. - TypeTableCompletion = "TableCompletion" -) - -// These constants represent keys for fields when unmarshalling various JSON dicts representing Kusto frames. -const ( - FieldFrameType = "FrameType" - FieldTableID = "TableId" - FieldTableKind = "TableKind" - FieldTableName = "TableName" - FieldColumns = "Columns" - FieldRows = "Rows" - FieldColumnName = "ColumnName" - FieldColumnType = "ColumnType" - FieldCount = "FieldCount" - FieldTableFragmentType = "TableFragmentType" - FieldTableProgress = "TableProgress" - FieldRowCount = "RowCount" -) - -// TableKind describes the kind of table. -type TableKind string - -const ( - // QueryProperties is a dataTable.TableKind that contains properties about the query itself. - // The dataTable.TableName is usually ExtendedProperties. - QueryProperties TableKind = "QueryProperties" - // PrimaryResult is a dataTable.TableKind that contains the query information the user wants. - // The dataTable.TableName is PrimaryResult. - PrimaryResult TableKind = "PrimaryResult" - // QueryCompletionInformation contains information on how long the query took. - // The dataTable.TableName is QueryCompletionInformation. - QueryCompletionInformation TableKind = "QueryCompletionInformation" - QueryTraceLog TableKind = "QueryTraceLog" - QueryPerfLog TableKind = "QueryPerfLog" - QueryResult TableKind = "QueryResult" - TableOfContents TableKind = "TableOfContents" - QueryPlan TableKind = "QueryPlan" - ExtendedProperties TableKind = "@ExtendedProperties" - UnknownTableKind TableKind = "Unknown" -) - -// Decoder provides a function that will decode an incoming data stream and return a channel of Frame objects. -type Decoder interface { - // Decode decodes an io.Reader representing a stream of Kusto frames into our Frame representation. - // The type and order of frames is dependent on the REST interface version and the progressive frame settings. - Decode(ctx context.Context, r io.ReadCloser, op errors.Op) chan Frame -} - -// Frame is a type of Kusto frame as defined in the reference document. -type Frame interface { - IsFrame() -} - -// Error is not actually a Kusto frame, but is used to signal the end of a stream -// where we encountered an error. Error implements error. -type Error struct { - Msg string -} - -// Error implements error.Error(). -func (e Error) Error() string { - return e.Msg -} - -// IsFrame implements Frame.IsFrame(). -func (Error) IsFrame() {} - -// Errorf write a frames.Error to ch with fmt.Sprint(s, a...). -func Errorf(ctx context.Context, ch chan Frame, s string, a ...interface{}) { - select { - case <-ctx.Done(): - case ch <- Error{Msg: fmt.Sprintf(s, a...)}: - } -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/README.md b/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/README.md deleted file mode 100644 index 910330d045..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Why the fork of encoding/json (from version 1.14) - -The json package is setup for the general use case. And it makes a lot of assumptions about how people are going to send you data. - -In our case, we want to read a stream of Kusto frames represented by a JSON array, but we want to read them as a stream and not all at once. - -That means we need to use a json.Decoder. Which is all well and dandy, except what we are going to read out varies by the type of frame. And we won't know what that frame is until we parse the frametype key. - -So we decode into a json.RawMessage, extract the frametype from the message, and then unmarshal into the concrete frame. All good right? - -Wrong, because json.RawMessage makes a copy of the bytes that were sent in. That costs us a huge amount in allocation per frame on 100's of thousands or millions of frames. - -Next, for some reason which I can't explain, Go translates numbers in a json.Unmarshal() call into float64 if the target is an interface{}. I'm sure there is a good reason for it, I just don't understand it. I would think it would just be an int64 or float64. Or, because they made it, a json.Number. The decoder itself can translate to json.Number, if you enable it. But not Unmarshal. - -Because we need to unmarshal to a [][]interface{} so we can translate to a []value.Values(also an interface) that represent rows in a frame, the unmarshal call couldn't hold all numbers we support in a float64. So Unmarshal was changed to always unmarshal into a json.Number. - -# Important changes - -- RawMessage now uses the passed slice. This also means you **MUST** decode the raw message into something before making any other decoder calls. -- Unmarshal always unmarshals into a json.Number. - -# Things you might try, but won't work - -## Doing a RawMessage for the rows instead of [][]interface{}. Then using another Decoder on that. - -You have to store decoders modified for resetting for this not to go crazy in allocs. Also, the decoder doesn't really like being inside content from another decoder, it creates errors about spacing that actually don't cause an error, but it will eat up a lot of allocations (bad design or unintentional consequence). - -## Using json-iterator package - -Yeah, it looks like it will work, but then it doesn't have the Decoder.Token() thing. - -Then you are going to say, "Just remove the first byte to get rid of "[". - -Yeah, been there. Then it just errors out for some reason that isn't clear. Also, not a big fan of libraries that say 100% compatibility and then don't. - -I tried a lot of experiments with this library, but never one that worked well. It just is designed for its use case and not this one. - -## Use JSON (insert third party package name) - -I looked at a bunch of them. Don't want to add generated code (its a pain) and others like gojay require weird boiler plate I don't want to bolt on at this time. - -## Use map[string]interface{} and manually convert - -Actually, this works fine. The first iteration did this and was just ever so slightly faster over 5 million records fairly consistently. Its allocations were signifcantly less that using plain RawMessage for frame discovery and then doing the decode manually into the structs. - -But it was also a lot more code and with a single change to RawMessage I could half the allocations. On large loads this will keep our GC happy. Also, just less code. diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/decode.go b/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/decode.go deleted file mode 100644 index 4d38dae4f1..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/decode.go +++ /dev/null @@ -1,1292 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package json - -import ( - "encoding" - "encoding/base64" - "encoding/json" - "fmt" - "reflect" - "strconv" - "strings" - "unicode" - "unicode/utf16" - "unicode/utf8" -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. If v is nil or not a pointer, -// Unmarshal returns an InvalidUnmarshalError. -// -// Unmarshal uses the inverse of the encodings that -// Marshal uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a value implementing the Unmarshaler interface, -// Unmarshal calls that value's UnmarshalJSON method, including -// when the input is a JSON null. -// Otherwise, if the value implements encoding.TextUnmarshaler -// and the input is a JSON quoted string, Unmarshal calls that value's -// UnmarshalText method with the unquoted form of the string. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by Marshal (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. By -// default, object keys which don't have a corresponding struct field are -// ignored (see Decoder.DisallowUnknownFields for an alternative). -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -// bool, for JSON booleans -// float64, for JSON numbers -// string, for JSON strings -// []interface{}, for JSON arrays -// map[string]interface{}, for JSON objects -// nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores -// key-value pairs from the JSON object into the map. The map's key type must -// either be any string type, an integer, implement json.Unmarshaler, or -// implement encoding.TextUnmarshaler. -// -// If a JSON value is not appropriate for a given target type, -// or if a JSON number overflows the target type, Unmarshal -// skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an UnmarshalTypeError describing the earliest such error. In any -// case, it's not guaranteed that all the remaining fields following -// the problematic one will be unmarshaled into the target object. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// “not present,” unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -func Unmarshal(data []byte, v interface{}) error { - // Check for well-formedness. - // Avoids filling out half a data structure - // before discovering a JSON syntax error. - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return err - } - - d.useNumber = true - d.init(data) - return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -// -// By convention, to approximate the behavior of Unmarshal itself, -// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. -type Unmarshaler interface { - UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to - Offset int64 // error occurred after reading Offset bytes - Struct string // name of the struct type containing the field - Field string // the full path from root node to the field -} - -func (e *UnmarshalTypeError) Error() string { - if e.Struct != "" || e.Field != "" { - return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() - } - return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// -// Deprecated: No longer used; kept for compatibility. -type UnmarshalFieldError struct { - Key string - Type reflect.Type - Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { - return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. -// (The argument to Unmarshal must be a non-nil pointer.) -type InvalidUnmarshalError struct { - Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { - if e.Type == nil { - return "json: Unmarshal(nil)" - } - - if e.Type.Kind() != reflect.Ptr { - return "json: Unmarshal(non-pointer " + e.Type.String() + ")" - } - return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v interface{}) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() { - return &InvalidUnmarshalError{reflect.TypeOf(v)} - } - - d.scan.reset() - d.scanWhile(scanSkipSpace) - // We decode rv not rv.Elem because the Unmarshaler interface - // test must be applied at the top level of the value. - err := d.value(rv) - if err != nil { - return d.addErrorContext(err) - } - return d.savedError -} - -// A Number represents a JSON number literal. -type Number = json.Number - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext struct { // provides context for type errors - Struct reflect.Type - FieldStack []string - } - savedError error - useNumber bool - disallowUnknownFields bool - // safeUnquote is the number of current string literal bytes that don't - // need to be unquoted. When negative, no bytes need unquoting. - safeUnquote int -} - -// readIndex returns the position of the last byte read. -func (d *decodeState) readIndex() int { - return d.off - 1 -} - -// phasePanicMsg is used as a panic message when we end up with something that -// shouldn't happen. It can indicate a bug in the JSON decoder, or that -// something is editing the data slice while the decoder executes. -const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - d.savedError = nil - d.errorContext.Struct = nil - - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] - return d -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { - if d.savedError == nil { - d.savedError = d.addErrorContext(err) - } -} - -// addErrorContext returns a new error enhanced with information from d.errorContext -func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 { - switch err := err.(type) { - case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct.Name() - err.Field = strings.Join(d.errorContext.FieldStack, ".") - return err - } - } - return err -} - -// skip scans to the end of what was started. -func (d *decodeState) skip() { - s, data, i := &d.scan, d.data, d.off - depth := len(s.parseState) - for { - op := s.step(s, data[i]) - i++ - if len(s.parseState) < depth { - d.off = i - d.opcode = op - return - } - } -} - -// scanNext processes the byte at d.data[d.off]. -func (d *decodeState) scanNext() { - if d.off < len(d.data) { - d.opcode = d.scan.step(&d.scan, d.data[d.off]) - d.off++ - } else { - d.opcode = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -func (d *decodeState) scanWhile(op int) { - s, data, i := &d.scan, d.data, d.off - for i < len(data) { - newOp := s.step(s, data[i]) - i++ - if newOp != op { - d.opcode = newOp - d.off = i - return - } - } - - d.off = len(data) + 1 // mark processed EOF with len+1 - d.opcode = d.scan.eof() -} - -// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the -// common case where we're decoding a literal. The decoder scans the input -// twice, once for syntax errors and to check the length of the value, and the -// second to perform the decoding. -// -// Only in the second step do we use decodeState to tokenize literals, so we -// know there aren't any syntax errors. We can take advantage of that knowledge, -// and scan a literal's bytes much more quickly. -func (d *decodeState) rescanLiteral() { - data, i := d.data, d.off -Switch: - switch data[i-1] { - case '"': // string - // safeUnquote is initialized at -1, which means that all bytes - // checked so far can be unquoted at a later time with no work - // at all. When reaching the closing '"', if safeUnquote is - // still -1, all bytes can be unquoted with no work. Otherwise, - // only those bytes up until the first '\\' or non-ascii rune - // can be safely unquoted. - safeUnquote := -1 - for ; i < len(data); i++ { - if c := data[i]; c == '\\' { - if safeUnquote < 0 { // first unsafe byte - safeUnquote = int(i - d.off) - } - i++ // escaped char - } else if c == '"' { - d.safeUnquote = safeUnquote - i++ // tokenize the closing quote too - break Switch - } else if c >= utf8.RuneSelf { - if safeUnquote < 0 { // first unsafe byte - safeUnquote = int(i - d.off) - } - } - } - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number - for ; i < len(data); i++ { - switch data[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '.', 'e', 'E', '+', '-': - default: - break Switch - } - } - case 't': // true - i += len("rue") - case 'f': // false - i += len("alse") - case 'n': // null - i += len("ull") - } - if i < len(data) { - d.opcode = stateEndValue(&d.scan, data[i]) - } else { - d.opcode = scanEnd - } - d.off = i + 1 -} - -// value consumes a JSON value from d.data[d.off-1:], decoding into v, and -// reads the following byte ahead. If v is invalid, the value is discarded. -// The first byte of the value has been read already. -func (d *decodeState) value(v reflect.Value) error { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray: - if v.IsValid() { - if err := d.array(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginObject: - if v.IsValid() { - if err := d.object(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginLiteral: - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - if v.IsValid() { - if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { - return err - } - } - } - return nil -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() interface{} { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray, scanBeginObject: - d.skip() - d.scanNext() - - case scanBeginLiteral: - v := d.literalInterface() - switch v.(type) { - case nil, string: - return v - } - } - return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// If it encounters an Unmarshaler, indirect stops and returns that. -// If decodingNull is true, indirect stops at the first settable pointer so it -// can be set to nil. -func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // Issue #24153 indicates that it is generally not a guaranteed property - // that you may round-trip a reflect.Value by calling Value.Addr().Elem() - // and expect the value to still be settable for values derived from - // unexported embedded struct fields. - // - // The logic below effectively does this when it first addresses the value - // (to satisfy possible pointer methods) and continues to dereference - // subsequent pointers as necessary. - // - // After the first round-trip, we set v back to the original value to - // preserve the original RW flags contained in reflect.Value. - v0 := v - haveAddr := false - - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { - haveAddr = true - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { - haveAddr = false - v = e - continue - } - } - - if v.Kind() != reflect.Ptr { - break - } - - if decodingNull && v.CanSet() { - break - } - - // Prevent infinite loop if v is an interface pointing to its own address: - // var v interface{} - // v = &v - if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { - v = v.Elem() - break - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Unmarshaler); ok { - return u, nil, reflect.Value{} - } - if !decodingNull { - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, reflect.Value{} - } - } - } - - if haveAddr { - v = v0 // restore original value after round-trip Value.Addr().Elem() - haveAddr = false - } else { - v = v.Elem() - } - } - return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into v. -// The first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - - // Check type of target. - switch v.Kind() { - case reflect.Interface: - if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. - ai := d.arrayInterface() - v.Set(reflect.ValueOf(ai)) - return nil - } - // Otherwise it's invalid. - fallthrough - default: - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - case reflect.Array, reflect.Slice: - break - } - - i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - // Get element of array, growing if necessary. - if v.Kind() == reflect.Slice { - // Grow slice if necessary - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 - } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - } - - if i < v.Len() { - // Decode into element. - if err := d.value(v.Index(i)); err != nil { - return err - } - } else { - // Ran out of fixed array: skip. - if err := d.value(reflect.Value{}); err != nil { - return err - } - } - i++ - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - - if i < v.Len() { - if v.Kind() == reflect.Array { - // Array. Zero the rest. - z := reflect.Zero(v.Type().Elem()) - for ; i < v.Len(); i++ { - v.Index(i).Set(z) - } - } else { - v.SetLen(i) - } - } - if i == 0 && v.Kind() == reflect.Slice { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } - return nil -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - -// object consumes an object from d.data[d.off-1:], decoding into v. -// The first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - t := v.Type() - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - oi := d.objectInterface() - v.Set(reflect.ValueOf(oi)) - return nil - } - - var fields structFields - - // Check type of target: - // struct or - // map[T1]T2 where T1 is string, an integer type, - // or an encoding.TextUnmarshaler - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind, have an integer kind, - // or be an encoding.TextUnmarshaler. - switch t.Key().Kind() { - case reflect.String, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - default: - if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - fields = cachedTypeFields(t) - // ok - default: - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - - var mapElem reflect.Value - origErrorContext := d.errorContext - - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := d.unquoteBytes(item) - if !ok { - panic(phasePanicMsg) - } - - // Figure out field corresponding to key. - var subv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := t.Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } - subv = mapElem - } else { - var f *field - if i, ok := fields.nameIndex[string(key)]; ok { - // Found an exact name match. - f = &fields.list[i] - } else { - // Fall back to the expensive case-insensitive - // linear search. - for i := range fields.list { - ff := &fields.list[i] - if ff.equalFold(ff.nameBytes, key) { - f = ff - break - } - } - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Ptr { - if subv.IsNil() { - // If a struct embeds a pointer to an unexported type, - // it is not possible to set a newly allocated value - // since the field is unexported. - // - // See https://golang.org/issue/21357 - if !subv.CanSet() { - d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) - // Invalidate subv to ensure d.value(subv) skips over - // the JSON value without assigning it to subv. - subv = reflect.Value{} - destring = false - break - } - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) - d.errorContext.Struct = t - } else if d.disallowUnknownFields { - d.saveError(fmt.Errorf("json: unknown field %q", key)) - } - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - if err := d.literalStore(nullLiteral, subv, false); err != nil { - return err - } - case string: - if err := d.literalStore([]byte(qv), subv, true); err != nil { - return err - } - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - if err := d.value(subv); err != nil { - return err - } - } - - // Write value back to map; - // if using struct, subv points into struct already. - if v.Kind() == reflect.Map { - kt := t.Key() - var kv reflect.Value - switch { - case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(kt) - if err := d.literalStore(item, kv, true); err != nil { - return err - } - kv = kv.Elem() - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(kt) - default: - switch kt.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := string(key) - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.ValueOf(n).Convert(kt) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - s := string(key) - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.ValueOf(n).Convert(kt) - default: - panic("json: Unexpected key type") // should never occur - } - } - if kv.IsValid() { - v.SetMapIndex(kv, subv) - } - } - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return nil -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (interface{}, error) { - if d.useNumber { - return Number(s), nil - } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} - } - return f, nil -} - -var numberType = reflect.TypeOf(Number("")) - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { - // Check for unmarshaler. - if len(item) == 0 { - //Empty string given - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - isNull := item[0] == 'n' // null - u, ut, pv := indirect(v, isNull) - if u != nil { - return u.UnmarshalJSON(item) - } - if ut != nil { - if item[0] != '"' { - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - val := "number" - switch item[0] { - case 'n': - val = "null" - case 't', 'f': - val = "bool" - } - d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) - return nil - } - s, ok := d.unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - return ut.UnmarshalText(s) - } - - v = pv - - switch c := item[0]; c { - case 'n': // null - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "null" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - v.Set(reflect.Zero(v.Type())) - // otherwise, ignore null for primitives/string - } - case 't', 'f': // true, false - value := item[0] == 't' - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "true" && string(item) != "false" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - default: - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - case reflect.Bool: - v.SetBool(value) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(value)) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - case '"': // string - s, ok := d.unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - switch v.Kind() { - default: - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Slice: - if v.Type().Elem().Kind() != reflect.Uint8 { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) - n, err := base64.StdEncoding.Decode(b, s) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b[:n]) - case reflect.String: - if v.Type() == numberType && !isValidNumber(string(s)) { - return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) - } - v.SetString(string(s)) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(string(s))) - } else { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - default: // number - if c != '-' && (c < '0' || c > '9') { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - s := string(item) - switch v.Kind() { - default: - if v.Kind() == reflect.String && v.Type() == numberType { - // s must be a valid number, because it's - // already been tokenized. - v.SetString(s) - break - } - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Interface: - n, err := d.convertNumber(s) - if err != nil { - d.saveError(err) - break - } - if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.Set(reflect.ValueOf(n)) - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetInt(n) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetUint(n) - - case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(s, v.Type().Bits()) - if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetFloat(n) - } - } - return nil -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() (val interface{}) { - switch d.opcode { - default: - panic(phasePanicMsg) - case scanBeginArray: - val = d.arrayInterface() - d.scanNext() - case scanBeginObject: - val = d.objectInterface() - d.scanNext() - case scanBeginLiteral: - val = d.literalInterface() - } - return -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []interface{} { - var v = make([]interface{}, 0) - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - v = append(v, d.valueInterface()) - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() map[string]interface{} { - m := make(map[string]interface{}) - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read string key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := d.unquote(item) - if !ok { - panic(phasePanicMsg) - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - // Read value. - m[key] = d.valueInterface() - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return m -} - -// literalInterface consumes and returns a literal from d.data[d.off-1:] and -// it reads the following byte ahead. The first byte of the literal has been -// read already (that's how the caller knows it's a literal). -func (d *decodeState) literalInterface() interface{} { - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - item := d.data[start:d.readIndex()] - - switch c := item[0]; c { - case 'n': // null - return nil - - case 't', 'f': // true, false - return c == 't' - - case '"': // string - s, ok := d.unquote(item) - if !ok { - panic(phasePanicMsg) - } - return s - - default: // number - if c != '-' && (c < '0' || c > '9') { - panic(phasePanicMsg) - } - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - } - return n - } -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - var r rune - for _, c := range s[2:6] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -// The first byte in s must be '"'. -func (d *decodeState) unquote(s []byte) (t string, ok bool) { - s, ok = d.unquoteBytes(s) - t = string(s) - return -} - -func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) { - // We already know that s[0] == '"'. However, we don't know that the - // closing quote exists in all cases, such as when the string is nested - // via the ",string" option. - if len(s) < 2 || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // If there are no unusual characters, no unquoting is needed, so return - // a slice of the original bytes. - r := d.safeUnquote - if r == -1 { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} diff --git a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/encode.go b/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/encode.go deleted file mode 100644 index a0b62e3cd7..0000000000 --- a/vendor/github.com/Azure/azure-kusto-go/kusto/internal/frames/unmarshal/json/encode.go +++ /dev/null @@ -1,1357 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 7159. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package json - -import ( - "bytes" - "encoding" - "encoding/base64" - "fmt" - "math" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements the Marshaler interface -// and is not a nil pointer, Marshal calls its MarshalJSON method -// to produce JSON. If no MarshalJSON method is present but the -// value implements encoding.TextMarshaler instead, Marshal calls -// its MarshalText method and encodes the result as a JSON string. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// UnmarshalJSON. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and Number values encode as JSON numbers. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// So that the JSON will be safe to embed inside HTML