pax_global_header00006660000000000000000000000064144572345050014523gustar00rootroot0000000000000052 comment=09b0d3011fffdd272b58c6a1a993090c0ba4346a mysqlrouter-go-1.2.0/000077500000000000000000000000001445723450500145345ustar00rootroot00000000000000mysqlrouter-go-1.2.0/.actrc000066400000000000000000000001261445723450500156300ustar00rootroot00000000000000--platform ubuntu-latest=lucasalt/act_base:latest --container-architecture linux/amd64mysqlrouter-go-1.2.0/.github/000077500000000000000000000000001445723450500160745ustar00rootroot00000000000000mysqlrouter-go-1.2.0/.github/FUNDING.yml000066400000000000000000000000211445723450500177020ustar00rootroot00000000000000github: [rluisr] mysqlrouter-go-1.2.0/.github/dependabot.yml000066400000000000000000000004271445723450500207270ustar00rootroot00000000000000version: 2 registries: github-octocat: type: git url: https://github.com username: rluisr password: ${{secrets.MY_GITHUB_PERSONAL_TOKEN}} updates: - package-ecosystem: gomod directory: "/" registries: - github-octocat target-branch: "master"mysqlrouter-go-1.2.0/.github/workflows/000077500000000000000000000000001445723450500201315ustar00rootroot00000000000000mysqlrouter-go-1.2.0/.github/workflows/lint.yml000066400000000000000000000005161445723450500216240ustar00rootroot00000000000000name: lint on: push: pull_request: jobs: lint: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version-file: 'go.mod' cache: true - uses: golangci/golangci-lint-action@v3 with: version: latestmysqlrouter-go-1.2.0/.github/workflows/test.yml000066400000000000000000000003731445723450500216360ustar00rootroot00000000000000name: Test on: push: jobs: test: name: Test runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Test run: | cd test docker compose rm -f make testmysqlrouter-go-1.2.0/.gitignore000066400000000000000000000000271445723450500165230ustar00rootroot00000000000000.env .envrc test/.envrcmysqlrouter-go-1.2.0/.idea/000077500000000000000000000000001445723450500155145ustar00rootroot00000000000000mysqlrouter-go-1.2.0/.idea/.gitignore000066400000000000000000000002601445723450500175020ustar00rootroot00000000000000# Default ignored files /shelf/ /workspace.xml # Editor-based HTTP Client requests /httpRequests/ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml mysqlrouter-go-1.2.0/.idea/aws.xml000066400000000000000000000007511445723450500170330ustar00rootroot00000000000000 mysqlrouter-go-1.2.0/.idea/modules.xml000066400000000000000000000004301445723450500177030ustar00rootroot00000000000000 mysqlrouter-go-1.2.0/.idea/mysqlrouter-go.iml000066400000000000000000000005021445723450500212250ustar00rootroot00000000000000 mysqlrouter-go-1.2.0/.idea/vcs.xml000066400000000000000000000002641445723450500170330ustar00rootroot00000000000000 mysqlrouter-go-1.2.0/Dockerfile_test000066400000000000000000000000711445723450500175630ustar00rootroot00000000000000FROM golang:1.20 WORKDIR /go/src/mysqlrouter-go COPY . .mysqlrouter-go-1.2.0/LICENSE000066400000000000000000000261351445723450500155500ustar00rootroot00000000000000 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 APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. mysqlrouter-go-1.2.0/README.md000066400000000000000000000020311445723450500160070ustar00rootroot00000000000000mysqlrouter-go ============== [![Build Status](https://cloud.drone.io/api/badges/rluisr/mysqlrouter-go/status.svg)](https://cloud.drone.io/rluisr/mysqlrouter-go) client for getting mysql-router information. Supported version ----------------- - 20190715 (8.0.17 - 8.0.34 / 8.1.0) Enable HTTP Server and REST API ------------------------------- See [MySQL Router 8.0.17 and the REST API by lefred](https://lefred.be/content/mysqlrouter-8-0-17-and-the-rest-api/). Usage ----- ```go mysqlrouter.New("http://localhost:8080", "luis", "luis", nil) ``` See [example](example/main.go) and [client_test.go](client_test.go) Supported endpoint ------------------- ### server - [x] HTTPS with verify ### cluster - [x] /metadata - [x] /metadata/metadata_name/config - [x] /metadata/metadata_name/status ### app - [x] /router/status ### route - [x] /routes - [x] /routes/route_name/status - [x] /routes/route_name/health - [x] /routes/route_name/destinations - [x] /routes/route_name/connections Developer --------- ```shell $ cd test && make local ``` mysqlrouter-go-1.2.0/app.go000066400000000000000000000012531445723450500156440ustar00rootroot00000000000000package mysqlrouter import ( "encoding/json" "time" ) var ( appURL = "/router" ) // Router general information of MySQL Router type Router struct { ProcessID int `json:"processId"` ProductEdition string `json:"productEdition"` TimeStarted time.Time `json:"timeStarted"` Version string `json:"version"` Hostname string `json:"hostname"` } // GetRouterStatus returns information of MySQL Router func (c *Client) GetRouterStatus() (*Router, error) { b, err := c.request(c.URL + appURL + "/status") if err != nil { return nil, err } var r *Router err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r, nil } mysqlrouter-go-1.2.0/app_test.go000066400000000000000000000004021445723450500166760ustar00rootroot00000000000000package mysqlrouter import ( "testing" "github.com/stretchr/testify/assert" ) func TestClient_GetRouterStatus(t *testing.T) { setupWithoutTLS() routerStatus, err := client.GetRouterStatus() assert.NoError(t, err) assert.NotEmpty(t, routerStatus) } mysqlrouter-go-1.2.0/client.go000066400000000000000000000016051445723450500163430ustar00rootroot00000000000000package mysqlrouter import ( "errors" "net/http" ) const apiVer = "20190715" // Client holds the configuration for 20190715 version API client. type Client struct { URL string Username string Password string Options *Options } type Options struct { Transport *http.Transport } func newClient(url, user, pass string, Options *Options) *Client { return &Client{ URL: url + "/api/" + apiVer, Username: user, Password: pass, Options: Options, } } // New creates a new API client. func New(url, user, pass string, Options *Options) (*Client, error) { if url == "" { return nil, errors.New(errEmptyClientInformation) } client := newClient(url, user, pass, Options) err := client.verifyConnection() if err != nil { return nil, err } return client, nil } func (c *Client) verifyConnection() error { _, err := c.request(c.URL + "/swagger.json") return err } mysqlrouter-go-1.2.0/client_test.go000066400000000000000000000032001445723450500173730ustar00rootroot00000000000000package mysqlrouter import ( "crypto/tls" "crypto/x509" "github.com/stretchr/testify/assert" "net/http" "os" "path/filepath" "testing" ) var ( client *Client ) func setupWithoutTLS() { var err error client, err = New("http://mysql-router-http:8080", "root", "mysql", nil) if err != nil { panic(err) } } // TestNewClientWithSkipTLSVerify check a connection with InsecureSkipVerify: true func TestNewClientWithSkipTLSVerify(t *testing.T) { opts := &Options{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, } _, err := New("https://mysql-router-https:8443", "root", "mysql", opts) assert.NoError(t, err) } // TestNewClientWithTLS check a connection with certificates func TestNewClientWithTLS(t *testing.T) { certPath, err := filepath.Abs("test/mysql-router/certs/localhost.crt") if err != nil { assert.NoError(t, err) } keyPath, err := filepath.Abs("test/mysql-router/certs/localhost.key") if err != nil { assert.NoError(t, err) } caPath, err := filepath.Abs("test/mysql-router/certs/localCA.crt") if err != nil { assert.NoError(t, err) } cert, err := tls.LoadX509KeyPair(certPath, keyPath) if err != nil { assert.NoError(t, err) } caCert, err := os.ReadFile(caPath) if err != nil { assert.NoError(t, err) } caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, RootCAs: caCertPool, } opts := &Options{ Transport: &http.Transport{ TLSClientConfig: tlsConfig, }, } _, err = New("https://mysql-router-https:8443", "root", "mysql", opts) assert.NoError(t, err) } mysqlrouter-go-1.2.0/entrypoint.sh000066400000000000000000000016751445723450500173140ustar00rootroot00000000000000#!/bin/bash set -e echo "==============================================================================================" echo "To check any other containers log," echo "run \"docker compose up --build --force-recreate --always-recreate-deps --renew-anon-volumes\"" echo "==============================================================================================" readonly MAX_TRIES=120 attempt_num=0 until curl -I -s http://mysql-router-http:8080 -k >/dev/null; do echo "Waiting for mysql router(http) ($attempt_num/$MAX_TRIES)" sleep $((attempt_num++)) if ((attempt_num == MAX_TRIES)); then exit 1 fi done attempt_num=0 until curl -I -s https://mysql-router-https:8443 -k >/dev/null; do echo "Waiting for mysql router(https) ($attempt_num/$MAX_TRIES)" sleep $((attempt_num++)) if ((attempt_num == MAX_TRIES)); then exit 1 fi done echo "mysql router is ready." # # start go test # cd /go/src/mysqlrouter-go go test -v . mysqlrouter-go-1.2.0/errors.go000066400000000000000000000002751445723450500164030ustar00rootroot00000000000000package mysqlrouter // Error messages const ( errEmptyClientInformation = "invalid information: url is must not be empty" errStatusCode = "response status code is not 200" ) mysqlrouter-go-1.2.0/example/000077500000000000000000000000001445723450500161675ustar00rootroot00000000000000mysqlrouter-go-1.2.0/example/main.go000066400000000000000000000026511445723450500174460ustar00rootroot00000000000000package main import ( "fmt" "github.com/rluisr/mysqlrouter-go" ) func main() { mr, err := mysqlrouter.New("http://localhost:8080", "root", "mysql", nil) if err != nil { panic(err) } routes, err := mr.GetAllRoutes() if err != nil { panic(err) } route := routes[1].Name fmt.Printf("route name: %s\n", route) routeStatus, err := mr.GetRouteStatus(route) if err != nil { panic(err) } fmt.Printf("route status: %+v\n", routeStatus) routeHealth, err := mr.GetRouteHealth(route) if err != nil { panic(err) } fmt.Printf("route health: %+v\n", routeHealth) routeDestinations, err := mr.GetRouteDestinations(route) if err != nil { panic(err) } fmt.Printf("route destinations: %+v\n", routeDestinations[0]) routeConnections, err := mr.GetRouteConnections(route) if err != nil { panic(err) } fmt.Printf("route connections: %+v\n", routeConnections) metadatas, err := mr.GetAllMetadata() if err != nil { panic(err) } metadata := metadatas[0].Name fmt.Printf("metadata name: %s\n", metadata) metadataConfig, err := mr.GetMetadataConfig(metadata) if err != nil { panic(err) } fmt.Printf("metadata config: %+v\n", metadataConfig) metadataStatus, err := mr.GetMetadataStatus(metadata) if err != nil { panic(err) } fmt.Printf("metadata status: %+v\n", metadataStatus) routerStatus, err := mr.GetRouterStatus() if err != nil { panic(err) } fmt.Printf("router status: %+v\n", routerStatus) } mysqlrouter-go-1.2.0/go.mod000066400000000000000000000004141445723450500156410ustar00rootroot00000000000000module github.com/rluisr/mysqlrouter-go go 1.20 require github.com/stretchr/testify v1.6.1 require ( github.com/davecgh/go-spew v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) mysqlrouter-go-1.2.0/go.sum000066400000000000000000000020001445723450500156570ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= mysqlrouter-go-1.2.0/metadata.go000066400000000000000000000043271445723450500166510ustar00rootroot00000000000000package mysqlrouter import ( "encoding/json" "fmt" "time" ) var ( metadataURL = "/metadata" ) // MetadataResponse is the response of getting all metadata endpoint. type MetadataResponse struct { Item []*Metadata `json:"items"` } // Metadata is the structure of getting all metadata endpoint. type Metadata struct { Name string `json:"name"` } // MetadataConfig is the structure of the configuration of metadata. type MetadataConfig struct { ClusterName string `json:"clusterName"` TimeRefreshInMs int `json:"timeRefreshInMs"` GroupReplicationID string `json:"groupReplicationId"` Nodes []MetadataNode `json:"nodes"` } // MetadataNode is the structure of metadata of a node. type MetadataNode struct { Hostname string `json:"hostname"` Port int `json:"port"` } // MetadataStatus is the structure of the information of metadata. type MetadataStatus struct { RefreshFailed int `json:"refreshFailed"` RefreshSucceeded int `json:"refreshSucceeded"` TimeLastRefreshSucceeded time.Time `json:"timeLastRefreshSucceeded"` LastRefreshHostname string `json:"lastRefreshHostname"` LastRefreshPort int `json:"lastRefreshPort"` } // GetAllMetadata returns all metadata. func (c *Client) GetAllMetadata() ([]*Metadata, error) { b, err := c.request(c.URL + metadataURL) if err != nil { return nil, err } var r *MetadataResponse err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r.Item, nil } // GetMetadataConfig returns the configuration of metadata. func (c *Client) GetMetadataConfig(cName string) (*MetadataConfig, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/config", c.URL, metadataURL, cName)) if err != nil { return nil, err } var r *MetadataConfig err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r, nil } // GetMetadataStatus returns the state of metadata. func (c *Client) GetMetadataStatus(cName string) (*MetadataStatus, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/status", c.URL, metadataURL, cName)) if err != nil { return nil, err } var r *MetadataStatus err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r, nil } mysqlrouter-go-1.2.0/metadata_test.go000066400000000000000000000012631445723450500177040ustar00rootroot00000000000000package mysqlrouter import ( "testing" "github.com/stretchr/testify/assert" ) var ( metadata string ) func TestClient_GetAllMetadata(t *testing.T) { setupWithoutTLS() metadatas, err := client.GetAllMetadata() assert.NoError(t, err) assert.NotEmpty(t, metadatas) metadata = metadatas[0].Name } func TestClient_GetMetadataConfig(t *testing.T) { setupWithoutTLS() metadataConfig, err := client.GetMetadataConfig(metadata) assert.NoError(t, err) assert.NotEmpty(t, metadataConfig) } func TestClient_GetMetadataStatus(t *testing.T) { setupWithoutTLS() metadataStatus, err := client.GetMetadataStatus(metadata) assert.NoError(t, err) assert.NotEmpty(t, metadataStatus) } mysqlrouter-go-1.2.0/request.go000066400000000000000000000016051445723450500165550ustar00rootroot00000000000000package mysqlrouter import ( "fmt" "io" "net/http" ) func (c *Client) request(url string) ([]byte, error) { client := &http.Client{} if c.Options != nil { if c.Options.Transport != nil { client.Transport = c.Options.Transport } } req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } if c.Username != "" && c.Password != "" { req.SetBasicAuth(c.Username, c.Password) } resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // We accept InternalServerError because MySQL Router REST API return 500 when route status does not alive. see: https://github.com/rluisr/mysqlrouter_exporter/issues/30#issue-1703518829 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusInternalServerError { return nil, fmt.Errorf("%s got %d", errStatusCode, resp.StatusCode) } return io.ReadAll(resp.Body) } mysqlrouter-go-1.2.0/routes.go000066400000000000000000000070531445723450500164110ustar00rootroot00000000000000package mysqlrouter import ( "encoding/json" "fmt" "time" ) var ( routeURL = "/routes" ) // RoutesResponse is the response of getting all routes endpoint. type RoutesResponse struct { Item []*Routes `json:"items"` } // Routes is the response of getting all routes endpoint. type Routes struct { Name string `json:"name"` } // RouteStatus is the state of the route. type RouteStatus struct { ActiveConnections int `json:"activeConnections"` TotalConnections int `json:"totalConnections"` BlockedHosts int `json:"blockedHosts"` } // RouteHealth is the structure of health check of the route. type RouteHealth struct { IsAlive bool `json:"isAlive"` } // RouteDestinationsResponse is the response of getting the information of the route destination endpoint. type RouteDestinationsResponse struct { Item []*RouteDestinations `json:"items"` } // RouteDestinations is the structure of destination of the route. type RouteDestinations struct { Address string `json:"address"` Port int `json:"port"` } // RouteConnectionsResponse is the response of getting the information of route connection endpoint. type RouteConnectionsResponse struct { Item []*RouteConnections `json:"items"` } // RouteConnections is the structure of the information of the connection of route. type RouteConnections struct { BytesFromServer int `json:"bytesFromServer"` BytesToServer int `json:"bytesToServer"` SourceAddress string `json:"sourceAddress"` DestinationAddress string `json:"destinationAddress"` TimeStarted time.Time `json:"timeStarted"` TimeConnectedToServer time.Time `json:"timeConnectedToServer"` TimeLastSentToServer time.Time `json:"timeLastSentToServer"` TimeLastReceivedFromServer time.Time `json:"timeLastReceivedFromServer"` } // GetAllRoutes returns all routes. func (c *Client) GetAllRoutes() ([]*Routes, error) { b, err := c.request(c.URL + routeURL) if err != nil { return nil, err } var r *RoutesResponse err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r.Item, nil } // GetRouteStatus return the status of the route. func (c *Client) GetRouteStatus(rName string) (*RouteStatus, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/status", c.URL, routeURL, rName)) if err != nil { return nil, err } var rStatus *RouteStatus err = json.Unmarshal(b, &rStatus) if err != nil { return nil, err } return rStatus, nil } // GetRouteHealth returns the health check of the route. func (c *Client) GetRouteHealth(rName string) (*RouteHealth, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/health", c.URL, routeURL, rName)) if err != nil { return nil, err } var rHealth *RouteHealth err = json.Unmarshal(b, &rHealth) if err != nil { return nil, err } return rHealth, nil } // GetRouteDestinations returns destinations of the route. func (c *Client) GetRouteDestinations(rName string) ([]*RouteDestinations, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/destinations", c.URL, routeURL, rName)) if err != nil { return nil, err } var r *RouteDestinationsResponse err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r.Item, nil } // GetRouteConnections return connections of the route. func (c *Client) GetRouteConnections(rName string) ([]*RouteConnections, error) { b, err := c.request(fmt.Sprintf("%s%s/%s/connections", c.URL, routeURL, rName)) if err != nil { return nil, err } var r *RouteConnectionsResponse err = json.Unmarshal(b, &r) if err != nil { return nil, err } return r.Item, nil } mysqlrouter-go-1.2.0/routes_test.go000066400000000000000000000017761445723450500174560ustar00rootroot00000000000000package mysqlrouter import ( "testing" "github.com/stretchr/testify/assert" ) var ( route string ) func TestClient_GetAllRoutes(t *testing.T) { setupWithoutTLS() routes, err := client.GetAllRoutes() assert.NoError(t, err) assert.NotEmpty(t, routes) route = routes[1].Name } func TestClient_GetRouteStatus(t *testing.T) { setupWithoutTLS() _, err := client.GetRouteStatus(route) assert.NoError(t, err) // A newborn cluster has no route status. //assert.NotEmpty(t, routeStatus) } func TestClient_GetRouteHealth(t *testing.T) { setupWithoutTLS() routeHealth, err := client.GetRouteHealth(route) assert.NoError(t, err) assert.NotEmpty(t, routeHealth) } func TestClient_GetRouteDestinations(t *testing.T) { setupWithoutTLS() routeDestinations, err := client.GetRouteDestinations(route) assert.NoError(t, err) assert.NotEmpty(t, routeDestinations) } func TestClient_GetRouteConnections(t *testing.T) { setupWithoutTLS() _, err := client.GetRouteConnections(route) assert.NoError(t, err) } mysqlrouter-go-1.2.0/test/000077500000000000000000000000001445723450500155135ustar00rootroot00000000000000mysqlrouter-go-1.2.0/test/.env000066400000000000000000000000151445723450500163000ustar00rootroot00000000000000VERSION=8.1.0mysqlrouter-go-1.2.0/test/Makefile000066400000000000000000000004001445723450500171450ustar00rootroot00000000000000test: docker compose up --build --force-recreate --always-recreate-deps --renew-anon-volumes -d docker exec test-mysqlrouter-go-test-1 sh -c "bash /go/src/mysqlrouter-go/entrypoint.sh" clean: docker compose down docker compose rm -f local: test cleanmysqlrouter-go-1.2.0/test/README.md000066400000000000000000000000301445723450500167630ustar00rootroot00000000000000See [Makefile](Makefile)mysqlrouter-go-1.2.0/test/docker-compose.yml000066400000000000000000000100461445723450500211510ustar00rootroot00000000000000# See .env version: '3' services: mysqlrouter-go-test: image: golang build: context: .. dockerfile: Dockerfile_test stdin_open: true volumes: - .:/go/src/github.com/rluisr/mysqlrouter-go depends_on: - mysql-router-http - mysql-router-https # why using `latest` tag? # Oracle does not pin the version of mysql-server of linux/amd64 ^^ mysql-server-1: environment: MYSQL_ROOT_PASSWORD: "mysql" MYSQL_ROOT_HOST: "%" image: container-registry.oracle.com/mysql/community-server:latest command: [ "mysqld","--server_id=1", "--binlog-transaction-dependency-tracking=WRITESET", "--binlog_checksum=NONE","--gtid_mode=ON","--enforce_gtid_consistency=ON","--log_bin","--log_slave_updates=ON","--master_info_repository=TABLE","--relay_log_info_repository=TABLE","--transaction_write_set_extraction=XXHASH64","--user=mysql","--skip-host-cache","--skip-name-resolve", "--default_authentication_plugin=mysql_native_password" ] ports: - "3301:3306" mysql-server-2: environment: MYSQL_ROOT_PASSWORD: "mysql" MYSQL_ROOT_HOST: "%" image: container-registry.oracle.com/mysql/community-server:latest command: [ "mysqld","--server_id=2","--binlog-transaction-dependency-tracking=WRITESET", "--binlog_checksum=NONE","--gtid_mode=ON","--enforce_gtid_consistency=ON","--log_bin","--log_slave_updates=ON","--master_info_repository=TABLE","--relay_log_info_repository=TABLE","--transaction_write_set_extraction=XXHASH64","--user=mysql","--skip-host-cache","--skip-name-resolve", "--default_authentication_plugin=mysql_native_password" ] ports: - "3302:3306" mysql-server-3: environment: MYSQL_ROOT_PASSWORD: "mysql" MYSQL_ROOT_HOST: "%" image: container-registry.oracle.com/mysql/community-server:latest command: [ "mysqld","--server_id=3","--binlog-transaction-dependency-tracking=WRITESET", "--binlog_checksum=NONE","--gtid_mode=ON","--enforce_gtid_consistency=ON","--log_bin","--log_slave_updates=ON","--master_info_repository=TABLE","--relay_log_info_repository=TABLE","--transaction_write_set_extraction=XXHASH64","--user=mysql","--skip-host-cache","--skip-name-resolve", "--default_authentication_plugin=mysql_native_password" ] ports: - "3303:3306" mysql-shell: platform: linux/amd64 build: context: ./mysql-shell args: MYSQL_SHELL_PACKAGER_URL: "https://dev.mysql.com/get/Downloads/MySQL-Shell/mysql-shell-8.1.0-1.el7.x86_64.rpm" dockerfile: Dockerfile environment: MYSQL_USER: "root" MYSQL_HOST: "mysql-server-1" MYSQL_PORT: "3306" MYSQL_PASSWORD: "mysql" MYSQLSH_SCRIPT: "/setupCluster.js" image: mysqlshell:${VERSION} depends_on: - mysql-server-1 - mysql-server-2 - mysql-server-3 # # DO NOT CHANGE APP NAME # WE WILL HAVE TO CHANGE CERTIFICATES. # mysql-router-http: platform: linux/amd64 build: context: ./mysql-router args: MYSQL_YUM_REPO_URL: https://dev.mysql.com/get/mysql80-community-release-el7-8.noarch.rpm dockerfile: Dockerfile_http environment: MYSQL_USER: "root" MYSQL_HOST: "mysql-server-1" MYSQL_PORT: "3306" MYSQL_PASSWORD: mysql MYSQL_INNODB_NUM_MEMBERS: 3 image: mysqlrouter-http:${VERSION} ports: - "8080:8080" depends_on: - mysql-server-1 - mysql-server-2 - mysql-server-3 restart: on-failure # # DO NOT CHANGE APP NAME # WE WILL HAVE TO CHANGE CERTIFICATES. # mysql-router-https: platform: linux/amd64 build: context: ./mysql-router args: MYSQL_YUM_REPO_URL: https://dev.mysql.com/get/mysql80-community-release-el7-8.noarch.rpm dockerfile: Dockerfile_https environment: MYSQL_USER: "root" MYSQL_HOST: "mysql-server-1" MYSQL_PORT: "3306" MYSQL_PASSWORD: mysql MYSQL_INNODB_NUM_MEMBERS: 3 image: mysqlrouter-https:${VERSION} ports: - "8443:8443" depends_on: - mysql-server-1 - mysql-server-2 - mysql-server-3 restart: on-failuremysqlrouter-go-1.2.0/test/mysql-router/000077500000000000000000000000001445723450500201765ustar00rootroot00000000000000mysqlrouter-go-1.2.0/test/mysql-router/Dockerfile_http000066400000000000000000000007661445723450500232400ustar00rootroot00000000000000FROM oraclelinux:7-slim ARG MYSQL_YUM_REPO_URL RUN yum install -y $MYSQL_YUM_REPO_URL \ && yum-config-manager --enable mysql-innovation-community \ && yum install -y mysql-community-client mysql-router-community libpwquality \ && yum clean all COPY mysqlrouter.pwd /mysqlrouter.pwd COPY run_http.sh /tmp/run.sh RUN chmod +x /tmp/run.sh HEALTHCHECK \ CMD mysqladmin --port 6446 --protocol TCP ping 2>&1 | grep Access || exit 1 EXPOSE 8080 ENTRYPOINT ["/tmp/run.sh"] CMD ["mysqlrouter"]mysqlrouter-go-1.2.0/test/mysql-router/Dockerfile_https000066400000000000000000000011021445723450500234040ustar00rootroot00000000000000FROM oraclelinux:7-slim ARG MYSQL_YUM_REPO_URL RUN yum install -y $MYSQL_YUM_REPO_URL \ && yum-config-manager --enable mysql-innovation-community \ && yum install -y mysql-community-client mysql-router-community libpwquality \ && yum clean all COPY mysqlrouter.pwd /mysqlrouter.pwd COPY run_https.sh /tmp/run.sh COPY certs/localhost.crt /server.crt COPY certs/localhost.key /server.key RUN chmod +x /tmp/run.sh HEALTHCHECK \ CMD mysqladmin --port 6446 --protocol TCP ping 2>&1 | grep Access || exit 1 EXPOSE 8443 ENTRYPOINT ["/tmp/run.sh"] CMD ["mysqlrouter"]mysqlrouter-go-1.2.0/test/mysql-router/certs/000077500000000000000000000000001445723450500213165ustar00rootroot00000000000000mysqlrouter-go-1.2.0/test/mysql-router/certs/localCA.crt000066400000000000000000000023001445723450500233210ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVjCCAj4CCQD/jrtRF0jB4jANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJK UDEPMA0GA1UECAwGcmx1aXNyMRMwEQYDVQQHDApnaXRodWIuY29tMREwDwYDVQQK DAhwZXJzb25hbDERMA8GA1UECwwIcGVyc29uYWwxEjAQBgNVBAMMCWxvY2FsaG9z dDAeFw0yMjA2MjkxMTMxNTRaFw0zMjA2MjYxMTMxNTRaMG0xCzAJBgNVBAYTAkpQ MQ8wDQYDVQQIDAZybHVpc3IxEzARBgNVBAcMCmdpdGh1Yi5jb20xETAPBgNVBAoM CHBlcnNvbmFsMREwDwYDVQQLDAhwZXJzb25hbDESMBAGA1UEAwwJbG9jYWxob3N0 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv0JYLqjANqaRYPmwLct9 Ij+CuXm3wjyqQ1Umi5tcXJy4lHJ9OA4n/3HVW5m0UY3kqSkeBK2g71hnFKRPLrPq m8MSmr5lMi6jQKcJnXIU98CXhOZ+dLmMJBd/k2tL9RMsmuOMq+9UklcON/q43PTW 7o2QM9YeoLxtdfrvNu+/hpHKKkfwYoiqxH7pfxRFYCM5/tjxzySi14F1iy4os5D+ vNKvrfPwp42VjMvxkMBbO34WoivYytfMOdbAMwoaeL9S2/xfPnsgAjs/yHqy2KKi DPod5qH2DuAhGEqCDLgDGBR8MKDqQemw5TKnQJ905wKZvdz0NfJ1TSh9isryDlc4 wwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBwKzDyF19zqNkNBaV9f1BU1YingTMc tiQcVKY0udC1NomK34/YGMZZ+/2yvk/F3ETdS1NTOa9O4kUEkFCOK/yQ4uXp80q9 w4Dkqu3NlrMooqniLBQ4Z31ilAT00zxhr+08ez1+APZyL9b4Fy4vonuB6pMWLDPS 6NNKIGgiww0oawxnE7Sq4TL4HR4ZRQubZQBUnFNHF6zE7bZ3qbAugUuWthS67SR9 SXgU4oLxDxkkfHa2eWGF+ARjPHaL2GQ0zSZAneiO6ZFfG2FvC1iVsIKLe0LzxOYa eXBhvn3fjRdLGmd9E6Xp3XYaKv/7BZZ7uxfKpfGDWHS2KdLLvXExm5f+ -----END CERTIFICATE----- mysqlrouter-go-1.2.0/test/mysql-router/certs/localCA.csr000066400000000000000000000017651445723450500233360ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIICsjCCAZoCAQAwbTELMAkGA1UEBhMCSlAxDzANBgNVBAgMBnJsdWlzcjETMBEG A1UEBwwKZ2l0aHViLmNvbTERMA8GA1UECgwIcGVyc29uYWwxETAPBgNVBAsMCHBl cnNvbmFsMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQC/QlguqMA2ppFg+bAty30iP4K5ebfCPKpDVSaLm1xcnLiUcn04 Dif/cdVbmbRRjeSpKR4EraDvWGcUpE8us+qbwxKavmUyLqNApwmdchT3wJeE5n50 uYwkF3+Ta0v1Eyya44yr71SSVw43+rjc9NbujZAz1h6gvG11+u8277+GkcoqR/Bi iKrEful/FEVgIzn+2PHPJKLXgXWLLiizkP680q+t8/CnjZWMy/GQwFs7fhaiK9jK 18w51sAzChp4v1Lb/F8+eyACOz/IerLYoqIM+h3mofYO4CEYSoIMuAMYFHwwoOpB 6bDlMqdAn3TnApm93PQ18nVNKH2KyvIOVzjDAgMBAAGgADANBgkqhkiG9w0BAQsF AAOCAQEAbPHTZg0HzJTkH0HWbgNHXThAErEAkmNaTOm2OiEMdZrrKuv90zd8QKzD fpA2ncw1a9IO08t5X5mnHt/7rv2AqRRLfoZH9UsGl4aAWsWSyYAqLHJwES/aM3Sb khaTLKc+fT9jl6RY1XLuC91wQavgzTgudAf2q5U0zDvGt0vtcGi2LzKX4vB8ybNQ TuvqwBS43XIfh3dm6bUKaP3U7D/7fMj28VHd02aBZiwCrN2Rgx16KqeudCqhyGDY jfmElTLOtcuDF2W6tbwdLedmF5GW/BaDttoF5NFO0Sa21+jxcB7wPn8aurn+E79b yyvJ/Rinq4k0UG75Pl3qELPsod2z7A== -----END CERTIFICATE REQUEST----- mysqlrouter-go-1.2.0/test/mysql-router/certs/localCA.key000066400000000000000000000032171445723450500233310ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAv0JYLqjANqaRYPmwLct9Ij+CuXm3wjyqQ1Umi5tcXJy4lHJ9 OA4n/3HVW5m0UY3kqSkeBK2g71hnFKRPLrPqm8MSmr5lMi6jQKcJnXIU98CXhOZ+ dLmMJBd/k2tL9RMsmuOMq+9UklcON/q43PTW7o2QM9YeoLxtdfrvNu+/hpHKKkfw YoiqxH7pfxRFYCM5/tjxzySi14F1iy4os5D+vNKvrfPwp42VjMvxkMBbO34WoivY ytfMOdbAMwoaeL9S2/xfPnsgAjs/yHqy2KKiDPod5qH2DuAhGEqCDLgDGBR8MKDq Qemw5TKnQJ905wKZvdz0NfJ1TSh9isryDlc4wwIDAQABAoIBAQCEorTWvs511/PP 5biJOaow+wxkJgYKnNmS0lVl0bsuurzCrdcq7Z5NZxsIaEKFoDpoGYyov+Rwt8Tc qsoC4GCd3p1jVRCGyZMLfguL9ZaW7ifl0Zb2ycpnKSifCnTlo4N2csGWZuYmilrg 9W4IRX9cdi3/1MjuvV3HyNrmJUOURQhp2XtzPMyfGypdLVsd1PYtSQGyxz8gZRqN ovW14jSEpMZoF4voW5Rdl3xeLfOQYV8uDB5AHib5QFW9yYTdY75Gt6qr3sdAuadc 6/xaTxY+L4i4/gEqQr5zB5safSO/+6XnWX6+3k7sHwzRFpmCKG/C7sm82oxlbX8k dShslElBAoGBAPHPDJjXlsoU+bFkMPVjbkXPPSkMmwJ0PL9XqXUbGe3ijE/UENOZ AIHWCsKwV1ux5pnbJcIx4S3WyPn2pw8f6Tq5khACpjDiDzEft1sQxccazq6KcLQU mTd8F1mc80pleNL1Hq3VbhvmvuOj6319QomRw3IU0dQsfslGKTxv+zfjAoGBAMp7 1ZpJOhQIouaZHjeqBMCIaCTSXxPmOLEdy7vAqRIQhBpOGdz8TdcjlajZRB9X5/si FfQxFUQAp5eBpRs/pLymv/xydH2S0JClqzMcOgRMtIHIHFCDnRsFeARNaF3Y7jyl QSqsUVOnAUB+X8+NSvXGgWHvWvz/Ma9vfTXWQRGhAoGBANX5WvNRKyztfLq9pxku AGGj7kIJ1o1IYI0NPHXVIo+/vlvRk4Y6yRkbV/BJ7TPF7AJPy0zZqKJQgw22dsRK f68okRi7z2ZIVBsrLqxV3j2++g+3j926sI5Jr7vrx9oYit9aauh2ifYErPxxjCxC kIN9yg6EX9059oOTI2BI02vzAoGALYNWSP7KsjQawbCLLUHnHYvLtPMgce2espka 8VHl7uyNdQg3IggISyJxgmmLuWvd9gH8Y04hFI79HL4EabKNieYFY24qpws4HDtQ 1wUyOUMwk7dyPdrHlopNJtJrciTPsAwJMNlY0m/IhUGisZl1zvbWoDfYAOQvu9pY j6BgMeECgYBnJc8ynbFWx5PUR5Y+dsDZV61YHV2yBYXjhSrnfYRpMRt7rdcmXpc6 wLMKQ4TrSczW0x6dC8OhjMxeaWQcdUsCohQVGclryqzzzhAWxD3r4ereqKVIpaC1 QP8lsNaqHzV2yVF+LvH3eltcaNF+VMHzBgBEO0J1eBjGrSnbK0VZhQ== -----END RSA PRIVATE KEY----- mysqlrouter-go-1.2.0/test/mysql-router/certs/localCA.srl000066400000000000000000000000211445723450500233270ustar00rootroot00000000000000A16239FA01DDE4A2 mysqlrouter-go-1.2.0/test/mysql-router/certs/localhost.crt000066400000000000000000000025121445723450500240200ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIJAKFiOfoB3eSiMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV BAYTAkpQMQ8wDQYDVQQIDAZybHVpc3IxEzARBgNVBAcMCmdpdGh1Yi5jb20xETAP BgNVBAoMCHBlcnNvbmFsMREwDwYDVQQLDAhwZXJzb25hbDESMBAGA1UEAwwJbG9j YWxob3N0MB4XDTIyMDYyOTE0MDMzM1oXDTI3MDYyODE0MDMzM1owbTELMAkGA1UE BhMCSlAxDzANBgNVBAgMBnJsdWlzcjETMBEGA1UEBwwKZ2l0aHViLmNvbTERMA8G A1UECgwIcGVyc29uYWwxETAPBgNVBAsMCHBlcnNvbmFsMRIwEAYDVQQDDAlsb2Nh bGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDq/9MX1A9GJUqS htAjphZDl9E0ifA/cHNU527BE3wVLMjgjHSdGVgRXX/9V7Qs+RivoAdqEwc9MhAM w/fBAtHAiyMXWbfQEWMbWlOBPqOFu9/7nvjsTp2oQ/ILGF0gLnsMaaTTsViMOGFt 65YFsvAjGyJUE8kQr+C67HSd3FEGyI+uQAZjLv10t4RGFtcB2BJ+l6F6oAk54p/4 YgYQvUlhl53kveW0b0cAKQEgSSrG5i6F0Z16k9ZzhJGu8zWXZni9ejiQMNWfEEXv f8nX8L7tPRxA5LOieFt8BajpmDdQf/tlNebqkZCpX1r2wKVuMNoukzsddNdRdsyj wb84aBRxAgMBAAGjXzBdMFsGA1UdEQRUMFKCCWxvY2FsaG9zdIIVbG9jYWxob3N0 LmxvY2FsZG9tYWluhwR/AAABggNhcHCCD2FwcC5sb2NhbGRvbWFpboISbXlzcWwt cm91dGVyLWh0dHBzMA0GCSqGSIb3DQEBCwUAA4IBAQAuJGmrvuBYNdl6tA+4/u5s PaSh8DpAix5dKtjaJ9Wsa0h+6wbScqh8RVH8lWsqGQCFblDhVrSo3umyNvEMiZWH zgsvgPNIG/bvNByJ9IRYyqo5AM7bDinyWJB85GIMJSM0TTpsNKnlQ1ARbgz2j1L6 schQz3M5dRT5IX8PAfoENb2mY9qulFzVePaYUccWid10CP5nsyeHO4rz2VhRBndz XmvtRNmA6b2KSSPCYRMGIXLlChWv5OdRGoJAFOk2VU/t1TBqoR3MtY+9GjIYrtsF oUCmcglmpd+EyhACDbvG19VJMMDltL0cV9zmj3WIn7lFefGcR5nW5DysA/cEYIEV -----END CERTIFICATE----- mysqlrouter-go-1.2.0/test/mysql-router/certs/localhost.csr000066400000000000000000000017651445723450500240300ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIICsjCCAZoCAQAwbTELMAkGA1UEBhMCSlAxDzANBgNVBAgMBnJsdWlzcjETMBEG A1UEBwwKZ2l0aHViLmNvbTERMA8GA1UECgwIcGVyc29uYWwxETAPBgNVBAsMCHBl cnNvbmFsMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDq/9MX1A9GJUqShtAjphZDl9E0ifA/cHNU527BE3wVLMjgjHSd GVgRXX/9V7Qs+RivoAdqEwc9MhAMw/fBAtHAiyMXWbfQEWMbWlOBPqOFu9/7nvjs Tp2oQ/ILGF0gLnsMaaTTsViMOGFt65YFsvAjGyJUE8kQr+C67HSd3FEGyI+uQAZj Lv10t4RGFtcB2BJ+l6F6oAk54p/4YgYQvUlhl53kveW0b0cAKQEgSSrG5i6F0Z16 k9ZzhJGu8zWXZni9ejiQMNWfEEXvf8nX8L7tPRxA5LOieFt8BajpmDdQf/tlNebq kZCpX1r2wKVuMNoukzsddNdRdsyjwb84aBRxAgMBAAGgADANBgkqhkiG9w0BAQsF AAOCAQEALX2IKs51mfPLhOSJyNh6oLQc2WftlWWQm44lTmc/cgVeP97XOW+b1Nfa frzPBWlP8mpLFUuFlHL/omhPzilH24CCNECKnEO62gMRZfss/6wSzKaf6K4IVREI v79J+9XKoLM4BqF7Q6Yem/gG87hRVAK/oZohadu6xcDo5A5w8V1reuj8SAIHuClQ PPX17kJKL6wZfjsJGzHBC2wUBMBzYrVnj9de0F9q1qdktjSFMKID97LKj6kSg6jd MW6zjw0SPS1W7HCqbLU7Y1jDp6TkGv6C6HjH9yWgOClIqm/6Od9UTcQlfg4BNwWr qxhDXfjBTzwd/puym+MF+RvXCmcf9Q== -----END CERTIFICATE REQUEST----- mysqlrouter-go-1.2.0/test/mysql-router/certs/localhost.csx000066400000000000000000000001761445723450500240310ustar00rootroot00000000000000subjectAltName = DNS:localhost, DNS:localhost.localdomain, IP:127.0.0.1, DNS:app, DNS:app.localdomain, DNS:mysql-router-https mysqlrouter-go-1.2.0/test/mysql-router/certs/localhost.key000066400000000000000000000032171445723450500240230ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA6v/TF9QPRiVKkobQI6YWQ5fRNInwP3BzVOduwRN8FSzI4Ix0 nRlYEV1//Ve0LPkYr6AHahMHPTIQDMP3wQLRwIsjF1m30BFjG1pTgT6jhbvf+574 7E6dqEPyCxhdIC57DGmk07FYjDhhbeuWBbLwIxsiVBPJEK/guux0ndxRBsiPrkAG Yy79dLeERhbXAdgSfpeheqAJOeKf+GIGEL1JYZed5L3ltG9HACkBIEkqxuYuhdGd epPWc4SRrvM1l2Z4vXo4kDDVnxBF73/J1/C+7T0cQOSzonhbfAWo6Zg3UH/7ZTXm 6pGQqV9a9sClbjDaLpM7HXTXUXbMo8G/OGgUcQIDAQABAoIBAQCWwIpwjM9HloCi Qu2fENrTfb7tT1fZuo+h9d1s6sz84H/03OWqKin+6dZDdVHWT+3wLF7VQ2OvdEAr kEONg/t+40MdpaZvSdgkIevTy5UnI4Dqb+8L2Nr2qK/LQlPrYyX4roTYcLp3KWwH Ecxp14KJYszA1vhzRgCKqUmeQ0mPaTteQsrQtU6EiFWHxML30+WpGnoYZnUGIUq8 c3SgsAhhVzk6crTtdXWcxtHOUWnTKY1XmDsc7M71vELdMTr3yKYpLYAqUGNnK4ss owJ3LHfv2GQjvx/TVAT554QRMmAGjenqpz8BlbWUvyffM53lJOC2W8/SuhESd72s EBkjwjxJAoGBAPeFkwxlu5Qaw9unp/QC9Q5JmWSrTgDJ5pRLviMJgcVKz1hkdC78 9RcIwEDrSuf9PEPymHTAJzdvGKdZz3pBO3UOaoVM6uYGYZ9Qz/dRdKpDQ8fByLbY G/IDO/hlVmV5KVoFjpi4GjKqlM4FFFF4X+OFjYfoOVbU0u8s0Qeftu/zAoGBAPMM cgbqDNBntUTUS8WtzGRr8NWIVGxksX85P+ia4+xTrRxEdNQmkLwsesVpklkehqH5 KIHOMK4mzj1CCAA1+618pS5ApseLcEu+i0r975jn+9z9c5OOF26pBelP1soT8z2L cIqugpOHPpshK/ALegxBy7rwGM6huvEutlO8O2cLAoGBAOAUOtVkW/ZubJU0KGZN LxBqLMXoF0u7fFUQZOdPOf4kBaXd+xh2xGK/91xOJpfyt1ZEDyTSuC4FE2qdcakZ 2PvVuzVGNvlbGZGjFUKuqVFiZ8A1fMGaz2G+79Gl3BstHvRyR2+Wa5EmwGPqUUSY Fybgxwocf5xOO09vYSTnwDNlAoGAXh6srZbHXZE7tirMKQITy7OtMNO5dbxMrCrc X9RTfTouKGsuHtXMaMKEzJwEa3SRyHm3QQU6/sXSShCfDo3ZJ6bERLQOoemSlBJ2 2JSby0fS1hJkRnjZBCZ6Po6Ha/vrzyKHc3z+3eiayvI+lJetLL/yCDNgN+yTe0CO pMCY9F8CgYEAia6ojUo4iFJxUraPYKunbTe/1HMD2ExlZZSlEepQeP5phHG5Xyem kietVqkZknF1zXi/XROrkhhnOM24iO7cNt9SkHtN/rYZdYWGr6X1iPdEp0QjGW9c jbRxHAosQfIdtBFgxzAumcSo936GsbVm2i4YxNNk+1ITCI6eungFnJw= -----END RSA PRIVATE KEY----- mysqlrouter-go-1.2.0/test/mysql-router/mysqlrouter.pwd000066400000000000000000000001051445723450500233140ustar00rootroot00000000000000root:$5$IrmGUIlDcII60HJ/$Oqo/dWG5Kkk/kTThwNooOsMdWfLww6siRpEwr7dsbg/ mysqlrouter-go-1.2.0/test/mysql-router/run_http.sh000066400000000000000000000061731445723450500224040ustar00rootroot00000000000000#!/bin/bash set -e if [ "$1" = 'mysqlrouter' ]; then mysqlrouter --version if [[ -z $MYSQL_HOST || -z $MYSQL_PORT || -z $MYSQL_USER || -z $MYSQL_PASSWORD ]]; then echo "We require all of" echo " MYSQL_HOST" echo " MYSQL_PORT" echo " MYSQL_USER" echo " MYSQL_PASSWORD" echo "to be set. Exiting." exit 1 fi PASSFILE=$(mktemp) echo "$MYSQL_PASSWORD" > "$PASSFILE" DEFAULTS_EXTRA_FILE=$(mktemp) cat >"$DEFAULTS_EXTRA_FILE" < "/dev/tcp/$MYSQL_HOST/$MYSQL_PORT") >/dev/null 2>&1; do echo "Waiting for mysql server $MYSQL_HOST ($attempt_num/$max_tries)" sleep $(( attempt_num++ )) if (( attempt_num == max_tries )); then exit 1 fi done echo "Successfully contacted mysql server at $MYSQL_HOST. Checking for cluster state." mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -e "show status;" if ! [[ "$(mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -e "show status;" 2> /dev/null)" ]]; then echo "Can not connect to database. Exiting." exit 1 fi if [[ -n $MYSQL_INNODB_CLUSTER_MEMBERS ]]; then attempt_num=0 echo $attempt_num echo $max_tries until [ "$(mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -N performance_schema -e "select count(MEMBER_STATE) = $MYSQL_INNODB_CLUSTER_MEMBERS from replication_group_members where MEMBER_STATE = 'ONLINE';" 2> /dev/null)" -eq 1 ]; do echo "Waiting for $MYSQL_INNODB_CLUSTER_MEMBERS cluster instances to become available via $MYSQL_HOST ($attempt_num/$max_tries)" sleep $(( attempt_num++ )) if (( attempt_num == max_tries )); then exit 1 fi done echo "Successfully contacted cluster with $MYSQL_INNODB_CLUSTER_MEMBERS members. Bootstrapping." fi echo "Successfully contacted mysql server at $MYSQL_HOST. Trying to bootstrap." echo "Hello! I'm tired for creating this fuck containers!" chown mysqlrouter /mysqlrouter.pwd mysqlrouter --bootstrap "$MYSQL_USER@$MYSQL_HOST:$MYSQL_PORT" --user=mysqlrouter --directory /tmp/mysqlrouter --force < "$PASSFILE" sed -i -e 's/logging_folder=.*$/logging_folder=/' /tmp/mysqlrouter/mysqlrouter.conf # Remove sections related to rest api sed -i -e '60,83d' /tmp/mysqlrouter/mysqlrouter.conf # then add cat << EOF >> /tmp/mysqlrouter/mysqlrouter.conf [http_server] port=8080 [rest_api] [rest_router] require_realm=somerealm [rest_routing] require_realm=somerealm [rest_metadata_cache] require_realm=somerealm [http_auth_realm:somerealm] backend=somebackend method=basic name=Some Realm [http_auth_backend:somebackend] backend=file filename=/mysqlrouter.pwd EOF echo "Starting mysql-router." exec "$@" --config /tmp/mysqlrouter/mysqlrouter.conf fi rm -f "$PASSFILE" rm -f "$DEFAULTS_EXTRA_FILE" unset DEFAULTS_EXTRA_FILE exec "$@"mysqlrouter-go-1.2.0/test/mysql-router/run_https.sh000066400000000000000000000062171445723450500225660ustar00rootroot00000000000000#!/bin/bash set -e if [ "$1" = 'mysqlrouter' ]; then if [[ -z $MYSQL_HOST || -z $MYSQL_PORT || -z $MYSQL_USER || -z $MYSQL_PASSWORD ]]; then echo "We require all of" echo " MYSQL_HOST" echo " MYSQL_PORT" echo " MYSQL_USER" echo " MYSQL_PASSWORD" echo "to be set. Exiting." exit 1 fi PASSFILE=$(mktemp) echo "$MYSQL_PASSWORD" > "$PASSFILE" DEFAULTS_EXTRA_FILE=$(mktemp) cat >"$DEFAULTS_EXTRA_FILE" < "/dev/tcp/$MYSQL_HOST/$MYSQL_PORT") >/dev/null 2>&1; do echo "Waiting for mysql server $MYSQL_HOST ($attempt_num/$max_tries)" sleep $(( attempt_num++ )) if (( attempt_num == max_tries )); then exit 1 fi done echo "Successfully contacted mysql server at $MYSQL_HOST. Checking for cluster state." mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -e "show status;" if ! [[ "$(mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -e "show status;" 2> /dev/null)" ]]; then echo "Can not connect to database. Exiting." exit 1 fi if [[ -n $MYSQL_INNODB_CLUSTER_MEMBERS ]]; then attempt_num=0 echo $attempt_num echo $max_tries until [ "$(mysql --defaults-extra-file="$DEFAULTS_EXTRA_FILE" -u "$MYSQL_USER" -h "$MYSQL_HOST" -P "$MYSQL_PORT" -N performance_schema -e "select count(MEMBER_STATE) = $MYSQL_INNODB_CLUSTER_MEMBERS from replication_group_members where MEMBER_STATE = 'ONLINE';" 2> /dev/null)" -eq 1 ]; do echo "Waiting for $MYSQL_INNODB_CLUSTER_MEMBERS cluster instances to become available via $MYSQL_HOST ($attempt_num/$max_tries)" sleep $(( attempt_num++ )) if (( attempt_num == max_tries )); then exit 1 fi done echo "Successfully contacted cluster with $MYSQL_INNODB_CLUSTER_MEMBERS members. Bootstrapping." fi echo "Successfully contacted mysql server at $MYSQL_HOST. Trying to bootstrap." echo "Hello! I'm tired for creating this fuck containers!" chown mysqlrouter /mysqlrouter.pwd mysqlrouter --bootstrap "$MYSQL_USER@$MYSQL_HOST:$MYSQL_PORT" --user=mysqlrouter --directory /tmp/mysqlrouter --force < "$PASSFILE" sed -i -e 's/logging_folder=.*$/logging_folder=/' /tmp/mysqlrouter/mysqlrouter.conf # Remove sections related to rest api sed -i -e '60,83d' /tmp/mysqlrouter/mysqlrouter.conf # then add cat << EOF >> /tmp/mysqlrouter/mysqlrouter.conf [http_server] port=8443 ssl=1 ssl_cert=/server.crt ssl_key=/server.key [rest_api] [rest_router] require_realm=somerealm [rest_routing] require_realm=somerealm [rest_metadata_cache] require_realm=somerealm [http_auth_realm:somerealm] backend=somebackend method=basic name=Some Realm [http_auth_backend:somebackend] backend=file filename=/mysqlrouter.pwd EOF echo "Starting mysql-router." exec "$@" --config /tmp/mysqlrouter/mysqlrouter.conf fi rm -f "$PASSFILE" rm -f "$DEFAULTS_EXTRA_FILE" unset DEFAULTS_EXTRA_FILE exec "$@"mysqlrouter-go-1.2.0/test/mysql-shell/000077500000000000000000000000001445723450500177655ustar00rootroot00000000000000mysqlrouter-go-1.2.0/test/mysql-shell/Dockerfile000066400000000000000000000003641445723450500217620ustar00rootroot00000000000000FROM oraclelinux:7-slim ARG MYSQL_SHELL_PACKAGER_URL COPY run.sh /run.sh RUN chmod +x /run.sh COPY setupCluster.js /setupCluster.js RUN yum install -y $MYSQL_SHELL_PACKAGER_URL \ && yum clean all ENTRYPOINT ["/run.sh"] CMD ["mysqlsh"] mysqlrouter-go-1.2.0/test/mysql-shell/run.sh000066400000000000000000000017151445723450500211310ustar00rootroot00000000000000#!/bin/bash set -e if [ "$1" = 'mysqlsh' ]; then mysqlsh --version if [[ -z $MYSQL_HOST || -z $MYSQL_PORT || -z $MYSQL_USER || -z $MYSQL_PASSWORD ]]; then echo "We require all of" echo " MYSQL_HOST" echo " MYSQL_PORT" echo " MYSQL_USER" echo " MYSQL_PASSWORD" echo "to be set. Exiting." exit 1 fi max_tries=12 attempt_num=0 until (echo > "/dev/tcp/$MYSQL_HOST/$MYSQL_PORT") >/dev/null 2>&1; do echo "Waiting for mysql server $MYSQL_HOST ($attempt_num/$max_tries)" sleep $(( attempt_num++ )) if (( attempt_num == max_tries )); then exit 1 fi done if [ "$MYSQLSH_SCRIPT" ]; then mysqlsh "$MYSQL_USER@$MYSQL_HOST:$MYSQL_PORT" --dbpassword="$MYSQL_PASSWORD" -f "$MYSQLSH_SCRIPT" || true fi if [ "$MYSQL_SCRIPT" ]; then mysqlsh "$MYSQL_USER@$MYSQL_HOST:$MYSQL_PORT" --dbpassword="$MYSQL_PASSWORD" --sql -f "$MYSQL_SCRIPT" || true fi exit 0 fi exec "$@"mysqlrouter-go-1.2.0/test/mysql-shell/setupCluster.js000066400000000000000000000013211445723450500230220ustar00rootroot00000000000000var dbPass = "mysql" var clusterName = "devCluster" try { print('Setting up InnoDB cluster...\n'); shell.connect('root@mysql-server-1:3306', dbPass) var cluster = dba.createCluster(clusterName); print('Adding instances to the cluster.'); cluster.addInstance({user: "root", host: "mysql-server-2", password: dbPass}, {recoveryMethod: 'incremental'}) print('.'); cluster.addInstance({user: "root", host: "mysql-server-3", password: dbPass}, {recoveryMethod: 'incremental'}) print('.\nInstances successfully added to the cluster.'); print('\nInnoDB cluster deployed successfully.\n'); } catch (e) { print('\nThe InnoDB cluster could not be created.\n\nError: ' + e.message + '\n'); }