mirror of
https://github.com/openziti/ziti.git
synced 2026-10-12 23:32:02 +00:00
Initial migration from internal repositories.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
@@ -1,7 +1,297 @@
|
||||
# Ziti Fabric
|
||||
**This documentation requires revision after the migration to GitHub is complete.**
|
||||
|
||||
Ziti is a modern, programmable network overlay with associated edge components, for application-embedded, zero trust network connectivity, written by developers for developers. Ziti allows developers to take control of networking while with secure connectivity and advanced security concepts such as Zero Trust.
|
||||
# Ziti Fabric Layer
|
||||
|
||||
The Ziti Fabric represents the geo-scale network overlay, and core network programming model for the Ziti ecosystem.
|
||||
The Ziti Fabric is a long-haul transport fabric for the Ziti ecosystem.
|
||||
|
||||
Currently working through migrating our internal repositories over to GitHub. Stay tuned.
|
||||
## Creating a Development Workspace
|
||||
|
||||
If you're going to be working on the Ziti fabric, or just want to track the latest development changes, you'll need a development workspace.
|
||||
|
||||
First, install the golang environment for your platform. Visit http://golang.org to download your installer.
|
||||
|
||||
As of this update, we're currently using version `1.13` of golang.
|
||||
|
||||
Make sure that `go` is in your path:
|
||||
|
||||
$ go version
|
||||
go version go1.13.1 linux/amd64
|
||||
|
||||
You'll need to create a `GOPATH` for Ziti. I like to put mine in `~/Repos/nf/ziti`, but you can root it wherever you'd like. I'd suggest you call it `ziti`.
|
||||
|
||||
Essentially:
|
||||
|
||||
* `mkdir ziti`
|
||||
* `cd ziti`
|
||||
* `export GOPATH=$(pwd)`
|
||||
|
||||
When you've got your `GOPATH` ready, clone the repository.
|
||||
|
||||
* Clone this repository into `$GOPATH/src/bitbucket.org/netfoundry/ziti`
|
||||
* `mkdir -p $GOPATH/src/bitbucket.org/netfoundry`
|
||||
* `cd $GOPATH/src/bitbucket.org/netfoundry`
|
||||
* `git clone git@bitbucket.org:netfoundry/ziti`
|
||||
|
||||
Build the tree:
|
||||
|
||||
$ go install ./...
|
||||
|
||||
The binaries will be placed in `$GOPATH/bin`.
|
||||
|
||||
The development configuration files live in `$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc`, and contain relative paths, which expect the executables to be started from `$GOPATH`.
|
||||
|
||||
$ cd $GOPATH
|
||||
$ mkdir -p db
|
||||
$ bin/ziti-controller run src/github.com/netfoundry/ziti-fabric/fabric/etc/ctrl.yml
|
||||
|
||||
## Launching A Simple Environment
|
||||
|
||||
You'll want to open a number of terminal windows. All commands are executed relative to `$GOPATH` (shell PWD is `$GOPATH`).
|
||||
|
||||
### Launch The Controller
|
||||
|
||||
`$ bin/ziti-controller run src/github.com/netfoundry/ziti-fabric/fabric/etc/ctrl.yml`
|
||||
|
||||
### Configure Dotzeet
|
||||
|
||||
In order to use the `ziti-fabric` tool, you'll need a working identity configuration in your home directory. Create the file `~/.ziti/identities.yml` containing the following. Substitute your concrete `$GOPATH` for the actual value of your `$GOPATH` in this file:
|
||||
|
||||
```
|
||||
default:
|
||||
caCert: "$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/ca-chain.cert.pem"
|
||||
cert: "$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/dotzeet-client.cert.pem"
|
||||
serverCert: "$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/dotzeet-server.cert.pem"
|
||||
key: "$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/private/dotzeet.key.pem"
|
||||
endpoint: tls:127.0.0.1:10000
|
||||
```
|
||||
|
||||
Where, `"caCert": "$GOPATH/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/ca-chain.cert.pem"` becomes `"caCert": "/home/michael/Repos/nf/ziti/src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/ca-chain.cert.pem"`.
|
||||
|
||||
The `endpoint:` specification should point at the `mgmt` listener address for your `ziti-controller`.
|
||||
|
||||
### Enroll Routers
|
||||
|
||||
With your controller running, use the `ziti-fabric` tool to enroll routers:
|
||||
|
||||
$ bin/ziti-fabric create router src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/001-client.cert.pem
|
||||
$ bin/ziti-fabric create router src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/002-client.cert.pem
|
||||
$ bin/ziti-fabric create router src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/003-client.cert.pem
|
||||
$ bin/ziti-fabric create router src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/004-client.cert.pem
|
||||
|
||||
### Start Routers
|
||||
|
||||
With your controller running, you can now start routers to begin building your mesh:
|
||||
|
||||
`$ bin/ziti-router run src/github.com/netfoundry/ziti-fabric/fabric/etc/001.yml`
|
||||
|
||||
There are 4 router configurations provided (001, 002, 003, 004).
|
||||
|
||||
Start routers 001, 002, and 003.
|
||||
|
||||
The configuration provided in the tree assembles a "diamond" shaped mesh, where router `001` is intended to initiate
|
||||
(ingress) sessions, and router `003` is intended to terminate (egress) sessions. With smart routing and dynamic healing
|
||||
in play, traffic can flow between router `001` and router `003` over either router `002` or `004`.
|
||||
|
||||
### Create a Google Service
|
||||
|
||||
Create a service to access `google.com`:
|
||||
|
||||
`$ bin/ziti-fabric create service google tcp:google.com:80 003`
|
||||
|
||||
### Access the Google Service
|
||||
|
||||
Access the google service using `ziti-fabric`:
|
||||
|
||||
`$ bin/ziti-fabric-test http http://google --host www.google.com`
|
||||
|
||||
You should see HTTP output from the google website.
|
||||
|
||||
## Using The Fabric InfluxDB Metrics Reporter
|
||||
|
||||
First you'll want to launch an InfluxDB docker container like this:
|
||||
|
||||
$ docker run --name influxdb -d -p 8086:8086 -v /opt/influxdb:/var/lib/influxdb influxdb
|
||||
|
||||
The directory `/opt/influxdb` should be changed to wherever you would like InfluxDB to persist its data.
|
||||
|
||||
Next, open an `influx` cli connection:
|
||||
|
||||
$ docker exec -it influxdb influx
|
||||
Connected to http://localhost:8086 version 1.7.7
|
||||
InfluxDB shell version: 1.7.7
|
||||
>
|
||||
|
||||
Then create the `ziti` database:
|
||||
|
||||
> create database ziti
|
||||
>
|
||||
|
||||
Exit the `influx` cli. InfluxDB is ready to go.
|
||||
|
||||
Make sure you uncomment the `metrics` section in the `fabric/etc/ctrl.yml`:
|
||||
|
||||
metrics:
|
||||
influxdb:
|
||||
enabled: true
|
||||
url: http://localhost:8086
|
||||
database: ziti
|
||||
|
||||
Restart your controller and metrics should begin flowing into InfluxDB. You can verify like this:
|
||||
|
||||
$ docker exec -it influxdb influx
|
||||
Connected to http://localhost:8086 version 1.7.7
|
||||
InfluxDB shell version: 1.7.7
|
||||
> use ziti
|
||||
Using database ziti
|
||||
> show series
|
||||
key
|
||||
---
|
||||
egress.rx.bytesrate,source=001
|
||||
egress.rx.bytesrate,source=002
|
||||
egress.rx.bytesrate,source=003
|
||||
----8<----
|
||||
link.OY8P.tx.msgsize,source=002
|
||||
link.OY8P.tx.msgsize,source=003
|
||||
link.yMey.latency,source=001
|
||||
link.yMey.latency,source=002
|
||||
link.yMey.rx.bytesrate,source=001
|
||||
link.yMey.rx.bytesrate,source=002
|
||||
link.yMey.rx.msgrate,source=001
|
||||
link.yMey.rx.msgrate,source=002
|
||||
link.yMey.rx.msgsize,source=001
|
||||
link.yMey.rx.msgsize,source=002
|
||||
link.yMey.tx.bytesrate,source=001
|
||||
link.yMey.tx.bytesrate,source=002
|
||||
link.yMey.tx.msgrate,source=001
|
||||
link.yMey.tx.msgrate,source=002
|
||||
link.yMey.tx.msgsize,source=001
|
||||
link.yMey.tx.msgsize,source=002
|
||||
> select * from "link.yMey.latency"
|
||||
name: link.yMey.latency
|
||||
time count max mean min p50 p75 p95 p99 p999 p9999 source stddev variance
|
||||
---- ----- --- ---- --- --- --- --- --- ---- ----- ------ ------ --------
|
||||
1563471804584021939 1 615541 615541 615541 615541 615541 615541 615541 615541 615541 001 0 0
|
||||
1563471807396555092 1 549054 549054 549054 549054 549054 549054 549054 549054 549054 002 0 0
|
||||
1563471819583707653 2 630068 622804.5 615541 622804.5 630068 630068 630068 630068 630068 001 7263.5 52758432.25
|
||||
1563471822396356386 2 549054 506257 463460 506257 549054 549054 549054 549054 549054 002 42797 1831583209
|
||||
> select * from "link.yMey.latency"
|
||||
name: link.yMey.latency
|
||||
time count max mean min p50 p75 p95 p99 p999 p9999 source stddev variance
|
||||
---- ----- --- ---- --- --- --- --- --- ---- ----- ------ ------ --------
|
||||
1563471804584021939 1 615541 615541 615541 615541 615541 615541 615541 615541 615541 001 0 0
|
||||
1563471807396555092 1 549054 549054 549054 549054 549054 549054 549054 549054 549054 002 0 0
|
||||
1563471819583707653 2 630068 622804.5 615541 622804.5 630068 630068 630068 630068 630068 001 7263.5 52758432.25
|
||||
1563471822396356386 2 549054 506257 463460 506257 549054 549054 549054 549054 549054 002 42797 1831583209
|
||||
1563471834584197383 3 630068 555820 421851 615541 630068 630068 630068 630068 630068 001 94915.85098742289 9009018768.666666
|
||||
>
|
||||
|
||||
## Using The Fabric (JSON) Gateway
|
||||
|
||||
Launch the `ziti-fabric-gw` like this:
|
||||
|
||||
$ bin/ziti-fabric-gw run src/github.com/netfoundry/ziti-fabric/fabric/etc/gw.yml
|
||||
|
||||
Client access like this:
|
||||
|
||||
$ cd ${GOPATH}/src/bitbucket.org/netfoundry/ziti
|
||||
$ curl --cacert fabric/etc/ca/intermediate/certs/ca-chain.cert.pem --cert fabric/etc/ca/intermediate/certs/ctrl-client.cert.pem --key fabric/etc/ca/intermediate/private/ctrl.key.pem https://127.0.0.1:10080/ctrl/services | jq
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 443 100 443 0 0 88600 0 --:--:-- --:--:-- --:--:-- 88600
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "google",
|
||||
"endpointAddress": "tls:www.google.com:443",
|
||||
"egress": "003",
|
||||
"binding": ""
|
||||
},
|
||||
{
|
||||
"id": "googles",
|
||||
"endpointAddress": "tcp:www.google.com:443",
|
||||
"egress": "003",
|
||||
"binding": ""
|
||||
},
|
||||
{
|
||||
"id": "loop",
|
||||
"endpointAddress": "tcp:127.0.0.1:8171",
|
||||
"egress": "003",
|
||||
"binding": ""
|
||||
},
|
||||
{
|
||||
"id": "loop-broken",
|
||||
"endpointAddress": "tcp:127.0.0.1:8171",
|
||||
"egress": "003",
|
||||
"binding": ""
|
||||
},
|
||||
{
|
||||
"id": "quigley",
|
||||
"endpointAddress": "tcp:one.quigley.com:80",
|
||||
"egress": "003",
|
||||
"binding": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
To use `ziti-fabric-gw` with a plain HTTP listener (without TLS), comment out the `certPath` and `keyPath` lines in `gw.yml`:
|
||||
|
||||
# Comment out the following lines to disable the TLS listener
|
||||
#certPath: src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/certs/mgmt-gw.cert.pem
|
||||
#keyPath: src/github.com/netfoundry/ziti-fabric/fabric/etc/ca/intermediate/private/mgmt-gw.key.pem
|
||||
|
||||
And then the listener can be accessed with plain HTTP:
|
||||
|
||||
$ curl http://127.0.0.1:10080/ctrl/services | jq
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 443 100 443 0 0 432k 0 --:--:-- --:--:-- --:--:-- 432k
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "google",
|
||||
"binding": "",
|
||||
"endpointAddress": "tls:www.google.com:443",
|
||||
"egress": "003"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
## Generating Network Load Using loop2
|
||||
|
||||
In order to create interesting metrics, you'll need to create some network load. A simple tool for that is the `ziti-fabric-test loop2` tool.
|
||||
|
||||
Create the `loop` service in the fabric (if it's not already there):
|
||||
|
||||
$ bin/ziti-fabric create service loop tcp:127.0.0.1:8171 003
|
||||
|
||||
Launch a `loop2` listener (in $GOPATH):
|
||||
|
||||
$ bin/ziti-fabric-test loop2 listener
|
||||
|
||||
Launch a `loop2` dialer (begin generating load):
|
||||
|
||||
$ bin/ziti-fabric-test loop2 dialer src/github.com/netfoundry/ziti-fabric/fabric/etc/loop2/10-ambient.loop2.yml
|
||||
|
||||
Take a look at the various `loop2` scenario configurations in `fabric/etc/loop2` for examples of how to create a specific kind of workload.
|
||||
|
||||
## Creating Keys and Certificates for Development
|
||||
|
||||
This is not necessary if you are using the PKI infrastructure that is already configured in the development config files (above).
|
||||
|
||||
This is only necessary if you want to generate your own PKI infrastructure for your own configuration.
|
||||
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002 ca --ca-name=root-ca --ca-file=root-ca
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=root-ca intermediate
|
||||
|
||||
ziti pki create key --pki-root /home/plorenz/tmp/002/ --ca-name=intermediate --key-file ctrl
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate server --server-file=ctrl-server --ip 127.0.0.1 --key-file ctrl
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate client --client-file=ctrl-client --key-file ctrl
|
||||
|
||||
ziti pki create key --pki-root /home/plorenz/tmp/002/ --ca-name=intermediate --key-file dotzeet
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate server --server-file=dotzeet-server --ip 127.0.0.1 --key-file dotzeet
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate client --client-file=dotzeet-client --key-file dotzeet
|
||||
|
||||
ziti pki create key --pki-root /home/plorenz/tmp/002/ --ca-name=intermediate --key-file 002
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate server --server-file=002-server --ip 127.0.0.1 --key-file 002 --server-name 002
|
||||
ziti pki create --pki-root=/home/plorenz/tmp/002/ --ca-name=intermediate client --client-file=002-client --key-file 002 --client-name 002
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/config"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/db"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/metrics"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xgress"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/netfoundry/ziti-foundation/transport"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Id *identity.TokenId
|
||||
Network *network.Options
|
||||
Db *db.Db
|
||||
Trace struct {
|
||||
Handler *channel2.TraceHandler
|
||||
}
|
||||
Profile struct {
|
||||
Memory struct {
|
||||
Path string
|
||||
Interval time.Duration
|
||||
}
|
||||
CPU struct {
|
||||
Path string
|
||||
}
|
||||
}
|
||||
Ctrl struct {
|
||||
Listener transport.Address
|
||||
Options *channel2.Options
|
||||
}
|
||||
Mgmt struct {
|
||||
Listener transport.Address
|
||||
Options *channel2.Options
|
||||
}
|
||||
Metrics *metrics.Config
|
||||
src map[interface{}]interface{}
|
||||
}
|
||||
|
||||
func (config *Config) Configure(sub config.Subconfig) error {
|
||||
return sub.LoadConfig(config.src)
|
||||
}
|
||||
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
cfgBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfgmap := make(map[interface{}]interface{})
|
||||
if err = yaml.NewDecoder(bytes.NewReader(cfgBytes)).Decode(&cfgmap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.InjectEnv(cfgmap)
|
||||
if value, found := cfgmap["v"]; found {
|
||||
if value.(int) != 3 {
|
||||
panic("config version mismatch: see docs for information on config updates")
|
||||
}
|
||||
} else {
|
||||
panic("no config version: see docs for information on config")
|
||||
}
|
||||
|
||||
identityConfig := identity.IdentityConfig{}
|
||||
if value, found := cfgmap["identity"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["key"]; found {
|
||||
identityConfig.Key = value.(string)
|
||||
}
|
||||
if value, found := submap["cert"]; found {
|
||||
identityConfig.Cert = value.(string)
|
||||
}
|
||||
if value, found := submap["server_cert"]; found {
|
||||
identityConfig.ServerCert = value.(string)
|
||||
}
|
||||
if value, found := submap["server_key"]; found {
|
||||
identityConfig.ServerKey = value.(string)
|
||||
}
|
||||
if value, found := submap["ca"]; found {
|
||||
identityConfig.CA = value.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Network: network.DefaultOptions(),
|
||||
src: cfgmap,
|
||||
}
|
||||
|
||||
if id, err := identity.LoadIdentity(identityConfig); err != nil {
|
||||
return nil, fmt.Errorf("unable to load identity (%s)", err)
|
||||
} else {
|
||||
config.Id = identity.NewIdentity(id)
|
||||
}
|
||||
|
||||
if value, found := cfgmap["network"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if options, err := network.LoadOptions(submap); err == nil {
|
||||
config.Network = options
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid 'network' stanza (%s)", err)
|
||||
}
|
||||
} else {
|
||||
pfxlog.Logger().Warn("invalid or empty 'network' stanza")
|
||||
}
|
||||
}
|
||||
|
||||
if value, found := cfgmap["db"]; found {
|
||||
str, err := db.Open(value.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Db = str
|
||||
} else {
|
||||
panic("config must provide [db]")
|
||||
}
|
||||
|
||||
if value, found := cfgmap["trace"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["path"]; found {
|
||||
handler, err := channel2.NewTraceHandler(value.(string), config.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
handler.AddDecoder(&channel2.Decoder{})
|
||||
handler.AddDecoder(&ctrl_pb.Decoder{})
|
||||
handler.AddDecoder(&xgress.Decoder{})
|
||||
handler.AddDecoder(&mgmt_pb.Decoder{})
|
||||
config.Trace.Handler = handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if value, found := cfgmap["profile"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["memory"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["path"]; found {
|
||||
config.Profile.Memory.Path = value.(string)
|
||||
}
|
||||
if value, found := submap["intervalMs"]; found {
|
||||
config.Profile.Memory.Interval = time.Duration(value.(int)) * time.Millisecond
|
||||
} else {
|
||||
config.Profile.Memory.Interval = 15 * time.Second
|
||||
}
|
||||
}
|
||||
}
|
||||
if value, found := submap["cpu"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["path"]; found {
|
||||
config.Profile.CPU.Path = value.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if value, found := cfgmap["ctrl"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["listener"]; found {
|
||||
listener, err := transport.ParseAddress(value.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Ctrl.Listener = listener
|
||||
} else {
|
||||
panic("config must provide [ctrl/listener]")
|
||||
}
|
||||
|
||||
config.Ctrl.Options = channel2.DefaultOptions()
|
||||
if value, found := submap["options"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
config.Ctrl.Options = channel2.LoadOptions(submap)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Trace.Handler != nil {
|
||||
config.Ctrl.Options.PeekHandlers = append(config.Ctrl.Options.PeekHandlers, config.Trace.Handler)
|
||||
}
|
||||
} else {
|
||||
panic("config [ctrl] section in unexpected format")
|
||||
}
|
||||
} else {
|
||||
panic("config must provide [ctrl]")
|
||||
}
|
||||
|
||||
if value, found := cfgmap["mgmt"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["listener"]; found {
|
||||
listener, err := transport.ParseAddress(value.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Mgmt.Listener = listener
|
||||
} else {
|
||||
panic("config must provide [mgmt/listener]")
|
||||
}
|
||||
|
||||
config.Mgmt.Options = channel2.DefaultOptions()
|
||||
if value, found := submap["options"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
config.Mgmt.Options = channel2.LoadOptions(submap)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic("config [mgmt] section in unexpected format")
|
||||
}
|
||||
} else {
|
||||
panic("config must provide [mgmt]")
|
||||
}
|
||||
|
||||
if value, found := cfgmap["metrics"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if metricsCfg, err := metrics.LoadConfig(submap); err == nil {
|
||||
config.Metrics = metricsCfg
|
||||
} else {
|
||||
return nil, fmt.Errorf("error loading metrics config (%s)", err)
|
||||
}
|
||||
} else {
|
||||
pfxlog.Logger().Warn("invalid or empty [metrics] stanza")
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/handler_ctrl"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/handler_mgmt"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xctrl"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xctrl_example"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xmgmt"
|
||||
"github.com/netfoundry/ziti-foundation/profiler"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
config *Config
|
||||
network *network.Network
|
||||
ctrlConnectHandler *handler_ctrl.ConnectHandler
|
||||
mgmtConnectHandler *handler_mgmt.ConnectHandler
|
||||
xctrls []xctrl.Xctrl
|
||||
xmgmts []xmgmt.Xmgmt
|
||||
|
||||
ctrlListener channel2.UnderlayListener
|
||||
mgmtListener channel2.UnderlayListener
|
||||
}
|
||||
|
||||
func NewController(cfg *Config) (*Controller, error) {
|
||||
c := &Controller{
|
||||
config: cfg,
|
||||
}
|
||||
|
||||
if n, err := network.NewNetwork(cfg.Id, cfg.Network, cfg.Db, cfg.Metrics); err == nil {
|
||||
c.network = n
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.showOptions(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Controller) Run() error {
|
||||
c.startProfiling()
|
||||
|
||||
if err := c.registerComponents(); err != nil {
|
||||
return fmt.Errorf("error registering component: %s", err)
|
||||
}
|
||||
|
||||
/**
|
||||
* ctrl listener/accepter.
|
||||
*/
|
||||
c.ctrlListener = channel2.NewClassicListener(c.config.Id, c.config.Ctrl.Listener)
|
||||
if err := c.ctrlListener.Listen(c.ctrlConnectHandler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctrlAccepter := handler_ctrl.NewCtrlAccepter(c.network, c.xctrls, c.ctrlListener, c.config.Ctrl.Options)
|
||||
go ctrlAccepter.Run()
|
||||
/* */
|
||||
|
||||
/**
|
||||
* mgmt listener/accepter.
|
||||
*/
|
||||
c.mgmtListener = channel2.NewClassicListener(c.config.Id, c.config.Mgmt.Listener)
|
||||
if err := c.mgmtListener.Listen(c.mgmtConnectHandler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mgmtAccepter := handler_mgmt.NewMgmtAccepter(c.mgmtListener, c.config.Mgmt.Options)
|
||||
go mgmtAccepter.Run()
|
||||
/* */
|
||||
|
||||
c.network.Run()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) Shutdown() {
|
||||
if c.ctrlListener != nil {
|
||||
if err := c.ctrlListener.Close(); err != nil {
|
||||
pfxlog.Logger().WithError(err).Error("failed to close ctrl channel listener")
|
||||
}
|
||||
}
|
||||
|
||||
if c.mgmtListener != nil {
|
||||
if err := c.mgmtListener.Close(); err != nil {
|
||||
pfxlog.Logger().WithError(err).Error("failed to close mgmt channel listener")
|
||||
}
|
||||
}
|
||||
|
||||
c.network.Shutdown()
|
||||
}
|
||||
|
||||
func (c *Controller) showOptions() error {
|
||||
if ctrl, err := json.MarshalIndent(c.config.Ctrl.Options, "", " "); err == nil {
|
||||
pfxlog.Logger().Infof("ctrl = %s", string(ctrl))
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
if mgmt, err := json.MarshalIndent(c.config.Mgmt.Options, "", " "); err == nil {
|
||||
pfxlog.Logger().Infof("mgmt = %s", string(mgmt))
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) startProfiling() {
|
||||
if c.config.Profile.Memory.Path != "" {
|
||||
go profiler.NewMemory(c.config.Profile.Memory.Path, c.config.Profile.Memory.Interval).Run()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Controller) registerComponents() error {
|
||||
c.ctrlConnectHandler = handler_ctrl.NewConnectHandler(c.network, c.xctrls)
|
||||
c.mgmtConnectHandler = handler_mgmt.NewConnectHandler(c.network)
|
||||
|
||||
c.config.Mgmt.Options.BindHandlers = []channel2.BindHandler{handler_mgmt.NewBindHandler(c.network, c.xmgmts)}
|
||||
|
||||
if err := c.RegisterXctrl(xctrl_example.NewExample()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) RegisterXctrl(x xctrl.Xctrl) error {
|
||||
if err := c.config.Configure(x); err != nil {
|
||||
return err
|
||||
}
|
||||
if x.Enabled() {
|
||||
c.xctrls = append(c.xctrls, x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) RegisterXmgmt(x xmgmt.Xmgmt) error {
|
||||
if err := c.config.Configure(x); err != nil {
|
||||
return err
|
||||
}
|
||||
if x.Enabled() {
|
||||
c.xmgmts = append(c.xmgmts, x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) GetNetwork() *network.Network {
|
||||
return c.network
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
type Db struct {
|
||||
db *bbolt.DB
|
||||
}
|
||||
|
||||
func Open(path string) (*Db, error) {
|
||||
db, err := bbolt.Open(path, 0600, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to open controller database [%s] (%s)", path, err)
|
||||
}
|
||||
if err := db.Update(createRoots); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Db{db: db}, nil
|
||||
}
|
||||
|
||||
func (db *Db) Close() error {
|
||||
return db.db.Close()
|
||||
}
|
||||
|
||||
func (db *Db) Update(fn func(tx *bbolt.Tx) error) error {
|
||||
return db.db.Update(fn)
|
||||
}
|
||||
|
||||
func (db *Db) View(fn func(tx *bbolt.Tx) error) error {
|
||||
return db.db.View(fn)
|
||||
}
|
||||
|
||||
func (db *Db) RootBucket(tx *bbolt.Tx) (*bbolt.Bucket, error) {
|
||||
ziti := tx.Bucket([]byte("ziti"))
|
||||
if ziti == nil {
|
||||
return nil, errors.New("db missing 'ziti' root")
|
||||
}
|
||||
return ziti, nil
|
||||
}
|
||||
|
||||
func createRoots(tx *bbolt.Tx) error {
|
||||
if ziti, err := tx.CreateBucketIfNotExists([]byte("ziti")); err == nil {
|
||||
if _, err := ziti.CreateBucketIfNotExists([]byte("services")); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := ziti.CreateBucketIfNotExists([]byte("routers")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xctrl"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-foundation/transport"
|
||||
)
|
||||
|
||||
type CtrlAccepter struct {
|
||||
network *network.Network
|
||||
xctrls []xctrl.Xctrl
|
||||
listener channel2.UnderlayListener
|
||||
options *channel2.Options
|
||||
}
|
||||
|
||||
func NewCtrlAccepter(network *network.Network,
|
||||
xctrls []xctrl.Xctrl,
|
||||
listener channel2.UnderlayListener,
|
||||
options *channel2.Options) *CtrlAccepter {
|
||||
return &CtrlAccepter{
|
||||
network: network,
|
||||
xctrls: xctrls,
|
||||
listener: listener,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrlAccepter *CtrlAccepter) Run() {
|
||||
log := pfxlog.Logger()
|
||||
log.Info("started")
|
||||
defer log.Warn("exited")
|
||||
|
||||
for {
|
||||
ch, err := channel2.NewChannel("ctrl", ctrlAccepter.listener, ctrlAccepter.options)
|
||||
if err == nil {
|
||||
if r, err := ctrlAccepter.network.KnownRouter(ch.Id().Token); err == nil {
|
||||
if ch.Underlay().Headers() != nil {
|
||||
if listenerValue, found := ch.Underlay().Headers()[channel2.HelloListenerHeader]; found {
|
||||
listenerString := string(listenerValue)
|
||||
if listener, err := transport.ParseAddress(listenerString); err == nil {
|
||||
r.AdvertisedListener = listener
|
||||
} else {
|
||||
log.Errorf("error parsing listener address (%s)", err)
|
||||
_ = ch.Close()
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
log.Warn("missing listener attribute")
|
||||
}
|
||||
} else {
|
||||
log.Warn("no attributes provided")
|
||||
}
|
||||
|
||||
r.Control = ch
|
||||
if err := r.Control.Bind(newBindHandler(r, ctrlAccepter.network, ctrlAccepter.xctrls)); err != nil {
|
||||
log.Errorf("error binding router (%s)", err)
|
||||
_ = ch.Close()
|
||||
continue
|
||||
}
|
||||
ctrlAccepter.network.ConnectRouter(r)
|
||||
|
||||
log.Infof("accepted new router connection [r/%s]", r.Id)
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Errorf("error accepting (%s)", err)
|
||||
if err.Error() == "closed" {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/trace"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xctrl"
|
||||
)
|
||||
|
||||
type bindHandler struct {
|
||||
router *network.Router
|
||||
network *network.Network
|
||||
xctrls []xctrl.Xctrl
|
||||
}
|
||||
|
||||
func newBindHandler(router *network.Router, network *network.Network, xctrls []xctrl.Xctrl) *bindHandler {
|
||||
return &bindHandler{router: router, network: network, xctrls: xctrls}
|
||||
}
|
||||
|
||||
func (bindHandler *bindHandler) BindChannel(ch channel2.Channel) error {
|
||||
ch.SetLogicalName(bindHandler.router.Id)
|
||||
ch.AddReceiveHandler(newSessionRequestHandler(bindHandler.router, bindHandler.network))
|
||||
ch.AddReceiveHandler(newHostRequestHandler(bindHandler.router, bindHandler.network))
|
||||
ch.AddReceiveHandler(newLinkHandler(bindHandler.router, bindHandler.network))
|
||||
ch.AddReceiveHandler(newFaultHandler(bindHandler.router, bindHandler.network))
|
||||
ch.AddReceiveHandler(newMetricsHandler(bindHandler.network))
|
||||
ch.AddReceiveHandler(bindHandler.network.GetTraceEventController())
|
||||
ch.AddReceiveHandler(newInspectHandler(bindHandler.network))
|
||||
ch.AddPeekHandler(trace.NewChannelPeekHandler(bindHandler.network.GetAppId(), ch, bindHandler.network.GetTraceController(), bindHandler.network.GetTraceEventController()))
|
||||
|
||||
xctrlDone := make(chan struct{})
|
||||
for _, x := range bindHandler.xctrls {
|
||||
if err := ch.Bind(x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := x.Run(ch, bindHandler.network.GetDb(), xctrlDone); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(bindHandler.xctrls) > 0 {
|
||||
ch.AddCloseHandler(newXctrlCloseHandler(xctrlDone))
|
||||
}
|
||||
|
||||
ch.AddCloseHandler(newCloseHandler(bindHandler.router, bindHandler.network))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type hostRequestHandler struct {
|
||||
r *network.Router
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
var successResponse = &ctrl_pb.BindResponse{Success: true}
|
||||
|
||||
func newHostRequestHandler(r *network.Router, network *network.Network) *hostRequestHandler {
|
||||
return &hostRequestHandler{r: r, network: network}
|
||||
}
|
||||
|
||||
func (h *hostRequestHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_BindRequestType)
|
||||
}
|
||||
|
||||
func (h *hostRequestHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
request := &ctrl_pb.BindRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err != nil {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
return
|
||||
}
|
||||
|
||||
response := successResponse
|
||||
|
||||
var err error
|
||||
if request.BindType == ctrl_pb.BindType_Bind {
|
||||
err = h.network.BindService(h.r, request.Token, request.ServiceId)
|
||||
} else if request.BindType == ctrl_pb.BindType_Unbind {
|
||||
err = h.network.UnbindService(h.r, request.Token, request.ServiceId)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
response = &ctrl_pb.BindResponse{Success: false, Message: err.Error()}
|
||||
}
|
||||
|
||||
if body, err := proto.Marshal(response); err == nil {
|
||||
responseMsg := channel2.NewMessage(int32(ctrl_pb.ContentType_BindResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := h.r.Control.Send(responseMsg); err != nil {
|
||||
log.Errorf("unable to respond (%s)", err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type closeHandler struct {
|
||||
r *network.Router
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newCloseHandler(r *network.Router, network *network.Network) *closeHandler {
|
||||
return &closeHandler{r: r, network: network}
|
||||
}
|
||||
|
||||
func (h *closeHandler) HandleClose(ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger("r/" + h.r.Id)
|
||||
log.Warn("disconnected")
|
||||
h.network.DisconnectRouter(h.r)
|
||||
}
|
||||
|
||||
type xctrlCloseHandler struct {
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func newXctrlCloseHandler(done chan struct{}) channel2.CloseHandler {
|
||||
return &xctrlCloseHandler{done: done}
|
||||
}
|
||||
|
||||
func (h *xctrlCloseHandler) HandleClose(ch channel2.Channel) {
|
||||
pfxlog.ContextLogger(ch.Label()).Info("closing Xctrl instances")
|
||||
close(h.done)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xctrl"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type ConnectHandler struct {
|
||||
network *network.Network
|
||||
xctrls []xctrl.Xctrl
|
||||
}
|
||||
|
||||
func NewConnectHandler(network *network.Network, xctrls []xctrl.Xctrl) *ConnectHandler {
|
||||
return &ConnectHandler{network: network, xctrls: xctrls}
|
||||
}
|
||||
|
||||
func (h *ConnectHandler) HandleConnection(hello *channel2.Hello, certificates []*x509.Certificate) error {
|
||||
log := pfxlog.ContextLogger(hello.IdToken)
|
||||
|
||||
id := hello.IdToken
|
||||
|
||||
/*
|
||||
* Control channel connections dump the client-supplied certificate details. We'll
|
||||
* soon be using these certificates for router enrollment.
|
||||
*/
|
||||
fingerprint := ""
|
||||
if certificates != nil {
|
||||
log.Debugf("peer has [%d] certificates", len(certificates))
|
||||
for i, c := range certificates {
|
||||
fingerprint = fmt.Sprintf("%x", sha1.Sum(c.Raw))
|
||||
log.Debugf("%d): peer certificate fingerprint [%s]", i, fingerprint)
|
||||
log.Debugf("%d): peer common name [%s]", i, c.Subject.CommonName)
|
||||
}
|
||||
} else {
|
||||
log.Warnf("peer has no certificates")
|
||||
}
|
||||
/* */
|
||||
|
||||
if h.network.ConnectedRouter(id) {
|
||||
return errors.New("router already connected")
|
||||
}
|
||||
|
||||
if r, err := h.network.KnownRouter(id); err == nil {
|
||||
if r.Fingerprint != fingerprint {
|
||||
return errors.New("unenrolled router")
|
||||
}
|
||||
} else {
|
||||
return errors.New("unenrolled router")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type faultHandler struct {
|
||||
r *network.Router
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newFaultHandler(r *network.Router, network *network.Network) *faultHandler {
|
||||
return &faultHandler{r: r, network: network}
|
||||
}
|
||||
|
||||
func (h *faultHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_FaultType)
|
||||
}
|
||||
|
||||
func (h *faultHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
fault := &ctrl_pb.Fault{}
|
||||
if err := proto.Unmarshal(msg.Body, fault); err == nil {
|
||||
switch fault.Subject {
|
||||
case ctrl_pb.FaultSubject_LinkFault:
|
||||
linkId := &identity.TokenId{Token: fault.Id}
|
||||
if err := h.network.LinkConnected(linkId, false); err == nil {
|
||||
if link, found := h.network.GetLink(linkId); found {
|
||||
h.network.LinkChanged(link)
|
||||
}
|
||||
log.Infof("link fault [l/%s]", linkId.Token)
|
||||
}
|
||||
|
||||
case ctrl_pb.FaultSubject_IngressFault:
|
||||
if err := h.network.RemoveSession(&identity.TokenId{Token: fault.Id}, false); err != nil {
|
||||
log.Errorf("error handling ingress fault (%s)", err)
|
||||
} else {
|
||||
log.Debugf("handled ingress fault for (%s)", fault.Id)
|
||||
}
|
||||
|
||||
case ctrl_pb.FaultSubject_EgressFault:
|
||||
if err := h.network.RemoveSession(&identity.TokenId{Token: fault.Id}, false); err != nil {
|
||||
log.Errorf("error handling egress fault (%s)", err)
|
||||
} else {
|
||||
log.Debugf("handled egress fault for (%s)", fault.Id)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Errorf("unexpected subject (%s)", fault.Subject.String())
|
||||
}
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type inspectHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newInspectHandler(network *network.Network) *inspectHandler {
|
||||
return &inspectHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *inspectHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_InspectRequestType)
|
||||
}
|
||||
|
||||
func (h *inspectHandler) HandleReceive(request *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
inspectRequest := &ctrl_pb.InspectRequest{}
|
||||
if err := proto.Unmarshal(request.Body, inspectRequest); err != nil {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
h.respondWithError(ch, request, fmt.Errorf("failed to decode request: (%v)", err).Error())
|
||||
}
|
||||
|
||||
response := &ctrl_pb.InspectResponse{Success: true}
|
||||
for _, value := range inspectRequest.RequestedValues {
|
||||
if value == "capability" {
|
||||
for _, capability := range h.network.GetCapabilities() {
|
||||
response.AddValue("capability", capability)
|
||||
}
|
||||
}
|
||||
}
|
||||
h.respond(ch, request, response)
|
||||
}
|
||||
|
||||
func (h *inspectHandler) respondWithError(ch channel2.Channel, request *channel2.Message, errs...string) {
|
||||
response := &ctrl_pb.InspectResponse{Success: false, Errors: errs }
|
||||
h.respond(ch, request, response)
|
||||
}
|
||||
|
||||
func (h *inspectHandler) respond(ch channel2.Channel, request *channel2.Message, response *ctrl_pb.InspectResponse) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
if body, err := proto.Marshal(response); err == nil {
|
||||
responseMsg := channel2.NewMessage(int32(ctrl_pb.ContentType_InspectResponseType), body)
|
||||
responseMsg.ReplyTo(request)
|
||||
if err := ch.Send(responseMsg); err != nil {
|
||||
log.Errorf("unable to respond to inspect request(%s)", err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("unexpected error marshalling response (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type linkHandler struct {
|
||||
r *network.Router
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newLinkHandler(r *network.Router, network *network.Network) *linkHandler {
|
||||
return &linkHandler{r: r, network: network}
|
||||
}
|
||||
|
||||
func (h *linkHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_LinkType)
|
||||
}
|
||||
|
||||
func (h *linkHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
link := &ctrl_pb.Link{}
|
||||
if err := proto.Unmarshal(msg.Body, link); err == nil {
|
||||
if err := h.network.LinkConnected(&identity.TokenId{Token: link.Id}, true); err == nil {
|
||||
log.Infof("link connected [l/%s]", link.Id)
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/metrics"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type metricsHandler struct {
|
||||
metrics.EventController
|
||||
}
|
||||
|
||||
func newMetricsHandler(network *network.Network) *metricsHandler {
|
||||
return &metricsHandler{network.GetMetricsEventController()}
|
||||
}
|
||||
|
||||
func (h *metricsHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_MetricsType)
|
||||
}
|
||||
|
||||
func (h *metricsHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
metricsMsg := &ctrl_pb.MetricsMessage{}
|
||||
if err := proto.Unmarshal(msg.Body, metricsMsg); err == nil {
|
||||
h.AcceptMetrics(metricsMsg)
|
||||
} else {
|
||||
pfxlog.ContextLogger(ch.Label()).Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_ctrl
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/ctrl_msg"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"time"
|
||||
)
|
||||
|
||||
type sessionRequestHandler struct {
|
||||
r *network.Router
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newSessionRequestHandler(r *network.Router, network *network.Network) *sessionRequestHandler {
|
||||
return &sessionRequestHandler{r: r, network: network}
|
||||
}
|
||||
|
||||
func (h *sessionRequestHandler) ContentType() int32 {
|
||||
return int32(ctrl_pb.ContentType_SessionRequestType)
|
||||
}
|
||||
|
||||
func (h *sessionRequestHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
request := &ctrl_pb.SessionRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err == nil {
|
||||
/*
|
||||
* This is running in a goroutine because CreateSession does a 'SendAndWait', which cannot be invoked from
|
||||
* inside a ReceiveHandler (without parallel support).
|
||||
*/
|
||||
go func() {
|
||||
if session, err := h.network.CreateSession(h.r, &identity.TokenId{Token: request.IngressId}, request.ServiceId); err == nil {
|
||||
responseMsg := ctrl_msg.NewSessionSuccessMsg(session.Id.Token, session.Circuit.IngressId)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if startXgressSession, err := h.r.Control.SendAndWaitWithTimeout(responseMsg, time.Second*10); err != nil {
|
||||
log.Errorf("unable to respond (%s)", err)
|
||||
h.network.RemoveSession(session.Id, true)
|
||||
} else {
|
||||
if startXgressSession.ContentType == int32(ctrl_pb.ContentType_StartXgressType) {
|
||||
if err = h.network.StartSessionEgress(session.Id); err != nil {
|
||||
log.WithError(err).Error("failure starting xgress")
|
||||
h.network.RemoveSession(session.Id, true)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("unexpected reply to dial response: %v", startXgressSession.ContentType)
|
||||
h.network.RemoveSession(session.Id, true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
responseMsg := ctrl_msg.NewSessionFailedMsg(err.Error())
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := h.r.Control.Send(responseMsg); err != nil {
|
||||
log.Errorf("unable to respond (%s)", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
/* */
|
||||
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
)
|
||||
|
||||
type MgmtAccepter struct {
|
||||
listener channel2.UnderlayListener
|
||||
options *channel2.Options
|
||||
}
|
||||
|
||||
func NewMgmtAccepter(listener channel2.UnderlayListener,
|
||||
options *channel2.Options) *MgmtAccepter {
|
||||
return &MgmtAccepter{
|
||||
listener: listener,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (mgmtAccepter *MgmtAccepter) Run() {
|
||||
log := pfxlog.Logger()
|
||||
log.Info("started")
|
||||
defer log.Warn("exited")
|
||||
|
||||
for {
|
||||
ch, err := channel2.NewChannel("mgmt", mgmtAccepter.listener, mgmtAccepter.options)
|
||||
if err == nil {
|
||||
log.Debugf("accepted mgmt connection [%s]", ch.Id().Token)
|
||||
|
||||
} else {
|
||||
log.Errorf("error accepting (%s)", err)
|
||||
if err.Error() == "closed" {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/trace"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/xmgmt"
|
||||
)
|
||||
|
||||
type BindHandler struct {
|
||||
network *network.Network
|
||||
xmgmts []xmgmt.Xmgmt
|
||||
}
|
||||
|
||||
func NewBindHandler(network *network.Network, xmgmts []xmgmt.Xmgmt) *BindHandler {
|
||||
return &BindHandler{network: network, xmgmts: xmgmts}
|
||||
}
|
||||
|
||||
func (bindHandler *BindHandler) BindChannel(ch channel2.Channel) error {
|
||||
network := bindHandler.network
|
||||
ch.AddReceiveHandler(newCreateRouterHandler(network))
|
||||
ch.AddReceiveHandler(newCreateServiceHandler(network))
|
||||
ch.AddReceiveHandler(newGetServiceHandler(network))
|
||||
ch.AddReceiveHandler(newInspectHandler(network))
|
||||
ch.AddReceiveHandler(newListLinksHandler(network))
|
||||
ch.AddReceiveHandler(newListRoutersHandler(network))
|
||||
ch.AddReceiveHandler(newListServicesHandler(network))
|
||||
ch.AddReceiveHandler(newListSessionsHandler(network))
|
||||
ch.AddReceiveHandler(newRemoveRouterHandler(network))
|
||||
ch.AddReceiveHandler(newRemoveServiceHandler(network))
|
||||
ch.AddReceiveHandler(newRemoveSessionHandler(network))
|
||||
ch.AddReceiveHandler(newSetLinkCostHandler(network))
|
||||
ch.AddReceiveHandler(newSetLinkDownHandler(network))
|
||||
|
||||
streamMetricHandler := newStreamMetricsHandler(network)
|
||||
ch.AddReceiveHandler(streamMetricHandler)
|
||||
ch.AddCloseHandler(streamMetricHandler)
|
||||
|
||||
streamSessionsHandler := newStreamSessionsHandler(network)
|
||||
ch.AddReceiveHandler(streamSessionsHandler)
|
||||
ch.AddCloseHandler(streamSessionsHandler)
|
||||
|
||||
streamTracesHandler := newStreamTracesHandler(network)
|
||||
ch.AddReceiveHandler(streamTracesHandler)
|
||||
ch.AddCloseHandler(streamTracesHandler)
|
||||
|
||||
ch.AddReceiveHandler(newTogglePipeTracesHandler(network))
|
||||
ch.AddPeekHandler(trace.NewChannelPeekHandler(network.GetAppId(), ch, network.GetTraceController(), network.GetTraceEventController()))
|
||||
|
||||
xmgmtDone := make(chan struct{})
|
||||
for _, x := range bindHandler.xmgmts {
|
||||
if err := ch.Bind(x); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := x.Run(ch, xmgmtDone); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(bindHandler.xmgmts) > 0 {
|
||||
ch.AddCloseHandler(newXmgmtCloseHandler(xmgmtDone))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type xmgmtCloseHandler struct {
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func newXmgmtCloseHandler(done chan struct{}) channel2.CloseHandler {
|
||||
return &xmgmtCloseHandler{done: done}
|
||||
}
|
||||
|
||||
func (h *xmgmtCloseHandler) HandleClose(ch channel2.Channel) {
|
||||
pfxlog.Logger().Infof("closing Xmgmt instances for [%s]", ch.Label())
|
||||
close(h.done)
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"crypto/x509"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type ConnectHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func NewConnectHandler(network *network.Network) *ConnectHandler {
|
||||
return &ConnectHandler{
|
||||
network: network,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ConnectHandler) HandleConnection(hello *channel2.Hello, certificates []*x509.Certificate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendSuccess(request *channel2.Message, ch channel2.Channel, message string) {
|
||||
sendResult(request, ch, message, true)
|
||||
}
|
||||
|
||||
func sendFailure(request *channel2.Message, ch channel2.Channel, message string) {
|
||||
sendResult(request, ch, message, false)
|
||||
}
|
||||
|
||||
func sendResult(request *channel2.Message, ch channel2.Channel, message string, success bool) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
if !success {
|
||||
log.Errorf("mgmt error (%s)", message)
|
||||
}
|
||||
|
||||
response := channel2.NewResult(success, message)
|
||||
response.ReplyTo(request)
|
||||
_ = ch.Send(response)
|
||||
log.Debug("success")
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type createRouterHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newCreateRouterHandler(network *network.Network) *createRouterHandler {
|
||||
return &createRouterHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *createRouterHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_CreateRouterRequestType)
|
||||
}
|
||||
|
||||
func (h *createRouterHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
create := &mgmt_pb.CreateRouterRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, create); err == nil {
|
||||
r := network.NewRouter(create.Router.Id, create.Router.Fingerprint)
|
||||
if err := h.network.CreateRouter(r); err == nil {
|
||||
log.Infof("created router [r/%s] with fingerprint [%s]", r.Id, r.Fingerprint)
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type createServiceHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newCreateServiceHandler(network *network.Network) *createServiceHandler {
|
||||
return &createServiceHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *createServiceHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_CreateServiceRequestType)
|
||||
}
|
||||
|
||||
func (h *createServiceHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
cs := &mgmt_pb.CreateServiceRequest{}
|
||||
err := proto.Unmarshal(msg.Body, cs)
|
||||
if err == nil {
|
||||
binding := "transport"
|
||||
if cs.Service.Binding != "" {
|
||||
binding = cs.Service.Binding
|
||||
}
|
||||
if err = h.network.CreateService(&network.Service{
|
||||
Id: cs.Service.Id,
|
||||
Binding: binding,
|
||||
EndpointAddress: cs.Service.EndpointAddress,
|
||||
Egress: cs.Service.Egress,
|
||||
}); err == nil {
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type getServiceHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newGetServiceHandler(network *network.Network) *getServiceHandler {
|
||||
return &getServiceHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *getServiceHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_GetServiceRequestType)
|
||||
}
|
||||
|
||||
func (h *getServiceHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
rs := &mgmt_pb.GetServiceRequest{}
|
||||
err := proto.Unmarshal(msg.Body, rs)
|
||||
if err == nil {
|
||||
response := &mgmt_pb.GetServiceResponse{}
|
||||
if svc, found := h.network.GetService(rs.ServiceId); found {
|
||||
response.Service = &mgmt_pb.Service{
|
||||
Id: svc.Id,
|
||||
Binding: svc.Binding,
|
||||
EndpointAddress: svc.EndpointAddress,
|
||||
Egress: svc.Egress,
|
||||
}
|
||||
|
||||
body, err := proto.Marshal(response)
|
||||
if err == nil {
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_GetServiceResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
ch.Send(responseMsg)
|
||||
|
||||
} else {
|
||||
pfxlog.ContextLogger(ch.Label()).Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
sendFailure(msg, ch, "no such service")
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-foundation/util/debugz"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type inspectHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newInspectHandler(network *network.Network) *inspectHandler {
|
||||
return &inspectHandler{network: network}
|
||||
}
|
||||
|
||||
func (*inspectHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_InspectRequestType)
|
||||
}
|
||||
|
||||
func (handler *inspectHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
context := &inspectRequestContext{
|
||||
handler: handler,
|
||||
msg: msg,
|
||||
ch: ch,
|
||||
request: &mgmt_pb.InspectRequest{},
|
||||
response: &mgmt_pb.InspectResponse{Success: true},
|
||||
}
|
||||
|
||||
var err error
|
||||
if err = proto.Unmarshal(msg.Body, context.request); err != nil {
|
||||
context.appendError(handler.network.GetAppId().Token, err.Error())
|
||||
}
|
||||
|
||||
context.regex, err = regexp.Compile(context.request.AppRegex)
|
||||
if err != nil {
|
||||
context.appendError(handler.network.GetAppId().Token, err.Error())
|
||||
}
|
||||
|
||||
if !context.response.Success {
|
||||
context.sendResponse()
|
||||
return
|
||||
}
|
||||
|
||||
context.processLocal()
|
||||
context.processRemote()
|
||||
context.sendResponse()
|
||||
}
|
||||
|
||||
type inspectRequestContext struct {
|
||||
handler *inspectHandler
|
||||
msg *channel2.Message
|
||||
ch channel2.Channel
|
||||
request *mgmt_pb.InspectRequest
|
||||
response *mgmt_pb.InspectResponse
|
||||
regex *regexp.Regexp
|
||||
}
|
||||
|
||||
func (context *inspectRequestContext) processLocal() {
|
||||
if context.regex.MatchString(context.handler.network.GetAppId().Token) {
|
||||
for _, requested := range context.request.RequestedValues {
|
||||
if strings.ToLower(requested) == "stackdump" {
|
||||
context.appendValue(context.handler.network.GetAppId().Token, requested, debugz.GenerateStack())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (context *inspectRequestContext) processRemote() {
|
||||
routerRequest := &ctrl_pb.InspectRequest{RequestedValues: context.request.RequestedValues}
|
||||
body, err := proto.Marshal(routerRequest)
|
||||
if err != nil {
|
||||
context.appendError(context.handler.network.GetAppId().Token, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
remoteResultChan := make(chan *remoteInspectResult)
|
||||
waitGroup := &sync.WaitGroup{}
|
||||
|
||||
for _, router := range context.handler.network.AllConnectedRouters() {
|
||||
if context.regex.MatchString(router.Id) {
|
||||
msg := channel2.NewMessage(int32(ctrl_pb.ContentType_InspectRequestType), body)
|
||||
respCh, err := router.Control.SendAndWait(msg)
|
||||
if err != nil {
|
||||
context.appendError(router.Id, err.Error())
|
||||
} else {
|
||||
waitGroup.Add(1)
|
||||
go handleInspectResponse(router.Id, respCh, remoteResultChan, waitGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close chan once all results have been queued
|
||||
go func() {
|
||||
waitGroup.Wait()
|
||||
close(remoteResultChan)
|
||||
}()
|
||||
|
||||
for remoteResult := range remoteResultChan {
|
||||
for _, err := range remoteResult.result.Errors {
|
||||
context.appendError(remoteResult.appId, err)
|
||||
}
|
||||
for _, val := range remoteResult.result.Values {
|
||||
context.appendValue(remoteResult.appId, val.Name, val.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleInspectResponse(appId string, respCh <-chan *channel2.Message, msgsCh chan<- *remoteInspectResult, waitGroup *sync.WaitGroup) {
|
||||
defer waitGroup.Done()
|
||||
|
||||
timeout := time.After(time.Second * 5)
|
||||
|
||||
select {
|
||||
case response, ok := <-respCh:
|
||||
if !ok {
|
||||
routerInspectFailed(appId, msgsCh, "no response from router")
|
||||
} else if response.ContentType == int32(ctrl_pb.ContentType_InspectResponseType) {
|
||||
result := &ctrl_pb.InspectResponse{}
|
||||
if err := proto.Unmarshal(response.Body, result); err != nil {
|
||||
routerInspectFailed(appId, msgsCh, fmt.Sprintf("Failed to decode response from router: %v", err))
|
||||
} else {
|
||||
msgsCh <- &remoteInspectResult{appId: appId, result: result}
|
||||
}
|
||||
} else {
|
||||
msg := fmt.Sprintf("Unexpected response type from router %v: %v\n", appId, response.ContentType)
|
||||
routerInspectFailed(appId, msgsCh, msg)
|
||||
}
|
||||
case <-timeout:
|
||||
routerInspectFailed(appId, msgsCh, "timed out waiting for response from router")
|
||||
}
|
||||
}
|
||||
|
||||
func routerInspectFailed(appId string, msgsCh chan<- *remoteInspectResult, msg string) {
|
||||
msgsCh <- &remoteInspectResult{
|
||||
appId: appId,
|
||||
result: &ctrl_pb.InspectResponse{Errors: []string{msg}},
|
||||
}
|
||||
}
|
||||
|
||||
func (context *inspectRequestContext) sendResponse() {
|
||||
body, err := proto.Marshal(context.response)
|
||||
if err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error serializing InspectResponse (%s)", err)
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_InspectResponseType), body)
|
||||
responseMsg.ReplyTo(context.msg)
|
||||
if err := context.ch.Send(responseMsg); err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error sending InspectResponse (%s)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (context *inspectRequestContext) appendValue(appId string, name string, value string) {
|
||||
context.response.Values = append(context.response.Values, &mgmt_pb.InspectResponse_InspectValue{
|
||||
AppId: appId,
|
||||
Name: name,
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
|
||||
func (context *inspectRequestContext) appendError(appId string, err string) {
|
||||
context.response.Success = false
|
||||
context.response.Errors = append(context.response.Errors, fmt.Sprintf("%v: %v", appId, err))
|
||||
}
|
||||
|
||||
type remoteInspectResult struct {
|
||||
appId string
|
||||
result *ctrl_pb.InspectResponse
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type listLinksHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newListLinksHandler(network *network.Network) *listLinksHandler {
|
||||
return &listLinksHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *listLinksHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_ListLinksRequestType)
|
||||
}
|
||||
|
||||
func (h *listLinksHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
list := &mgmt_pb.ListLinksRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, list); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
links := h.network.GetAllLinks()
|
||||
response := &mgmt_pb.ListLinksResponse{
|
||||
Links: make([]*mgmt_pb.Link, 0),
|
||||
}
|
||||
for _, l := range links {
|
||||
responseLink := &mgmt_pb.Link{
|
||||
Id: l.Id.Token,
|
||||
Src: l.Src.Id,
|
||||
Dst: l.Dst.Id,
|
||||
State: l.CurrentState().Mode.String(),
|
||||
Down: l.Down,
|
||||
Cost: int32(l.Cost),
|
||||
SrcLatency: l.SrcLatency,
|
||||
DstLatency: l.DstLatency,
|
||||
}
|
||||
response.Links = append(response.Links, responseLink)
|
||||
}
|
||||
|
||||
body, err := proto.Marshal(response)
|
||||
if err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListLinksResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := ch.Send(responseMsg); err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error sending response (%s)", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type listRoutersHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newListRoutersHandler(network *network.Network) *listRoutersHandler {
|
||||
return &listRoutersHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *listRoutersHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_ListRoutersRequestType)
|
||||
}
|
||||
|
||||
func (h *listRoutersHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
list := &mgmt_pb.ListRoutersRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, list); err == nil {
|
||||
response := &mgmt_pb.ListRoutersResponse{Routers: make([]*mgmt_pb.Router, 0)}
|
||||
if routers, err := h.network.AllRouters(); err == nil {
|
||||
log.Infof("got [%d] routers", len(routers))
|
||||
for _, r := range routers {
|
||||
connected := false
|
||||
if connR, found := h.network.GetConnectedRouter(r.Id); found {
|
||||
connected = true
|
||||
r.AdvertisedListener = connR.AdvertisedListener
|
||||
}
|
||||
responseR := &mgmt_pb.Router{
|
||||
Id: r.Id,
|
||||
Fingerprint: r.Fingerprint,
|
||||
Connected: connected,
|
||||
}
|
||||
if r.AdvertisedListener != nil {
|
||||
responseR.ListenerAddress = r.AdvertisedListener.String()
|
||||
}
|
||||
response.Routers = append(response.Routers, responseR)
|
||||
}
|
||||
|
||||
if body, err := proto.Marshal(response); err == nil {
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListRoutersResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := ch.Send(responseMsg); err != nil {
|
||||
pfxlog.ContextLogger(ch.Label()).Errorf("unexpected error sending response (%s)", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type listServicesHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newListServicesHandler(network *network.Network) *listServicesHandler {
|
||||
return &listServicesHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *listServicesHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_ListServicesRequestType)
|
||||
}
|
||||
|
||||
func (h *listServicesHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
ls := &mgmt_pb.ListServicesRequest{}
|
||||
err := proto.Unmarshal(msg.Body, ls)
|
||||
if err == nil {
|
||||
response := &mgmt_pb.ListServicesResponse{Services: make([]*mgmt_pb.Service, 0)}
|
||||
svcs, err := h.network.AllServices()
|
||||
if err == nil {
|
||||
for _, s := range svcs {
|
||||
response.Services = append(response.Services, &mgmt_pb.Service{
|
||||
Id: s.Id,
|
||||
Binding: s.Binding,
|
||||
EndpointAddress: s.EndpointAddress,
|
||||
Egress: s.Egress,
|
||||
})
|
||||
}
|
||||
|
||||
body, err := proto.Marshal(response)
|
||||
if err == nil {
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListServicesResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := ch.Send(responseMsg); err != nil {
|
||||
pfxlog.ContextLogger(ch.Label()).Errorf("unexpected error sending response (%s)", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type listSessionsHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newListSessionsHandler(network *network.Network) *listSessionsHandler {
|
||||
return &listSessionsHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *listSessionsHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_ListSessionsRequestType)
|
||||
}
|
||||
|
||||
func (h *listSessionsHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
list := &mgmt_pb.ListSessionsRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, list); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sessions := h.network.GetAllSessions()
|
||||
response := &mgmt_pb.ListSessionsResponse{
|
||||
Sessions: make([]*mgmt_pb.Session, 0),
|
||||
}
|
||||
for _, s := range sessions {
|
||||
responseSession := &mgmt_pb.Session{
|
||||
Id: s.Id.Token,
|
||||
ClientId: s.ClientId.Token,
|
||||
ServiceId: s.Service.Id,
|
||||
Circuit: NewCircuit(s.Circuit),
|
||||
}
|
||||
response.Sessions = append(response.Sessions, responseSession)
|
||||
}
|
||||
body, err := proto.Marshal(response)
|
||||
if err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_ListSessionsResponseType), body)
|
||||
responseMsg.ReplyTo(msg)
|
||||
if err := ch.Send(responseMsg); err != nil {
|
||||
pfxlog.ContextLogger(ch.Label()).Errorf("unexpected error sending response (%s)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func NewCircuit(circuit *network.Circuit) *mgmt_pb.Circuit {
|
||||
mgmtCircuit := &mgmt_pb.Circuit{}
|
||||
for _, r := range circuit.Path {
|
||||
mgmtCircuit.Path = append(mgmtCircuit.Path, r.Id)
|
||||
}
|
||||
for _, l := range circuit.Links {
|
||||
mgmtCircuit.Links = append(mgmtCircuit.Links, l.Id.Token)
|
||||
}
|
||||
return mgmtCircuit
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type removeRouterHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newRemoveRouterHandler(network *network.Network) *removeRouterHandler {
|
||||
return &removeRouterHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *removeRouterHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_RemoveRouterRequestType)
|
||||
}
|
||||
|
||||
func (h *removeRouterHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
remove := &mgmt_pb.RemoveRouterRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, remove); err == nil {
|
||||
router, err := h.network.GetRouter(remove.RouterId)
|
||||
if err == nil {
|
||||
if err := h.network.RemoveRouter(router); err == nil {
|
||||
log.Infof("removed router [r/%s]", remove.RouterId)
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type removeServiceHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newRemoveServiceHandler(network *network.Network) *removeServiceHandler {
|
||||
return &removeServiceHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *removeServiceHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_RemoveServiceRequestType)
|
||||
}
|
||||
|
||||
func (h *removeServiceHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
rs := &mgmt_pb.RemoveServiceRequest{}
|
||||
err := proto.Unmarshal(msg.Body, rs)
|
||||
if err == nil {
|
||||
if svc, found := h.network.GetService(rs.ServiceId); found {
|
||||
if err := h.network.RemoveService(svc.Id); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
} else {
|
||||
sendSuccess(msg, ch, "")
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, "no such service")
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type removeSessionHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newRemoveSessionHandler(network *network.Network) *removeSessionHandler {
|
||||
return &removeSessionHandler{network: network}
|
||||
}
|
||||
|
||||
func (handler *removeSessionHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_RemoveSessionRequestType)
|
||||
}
|
||||
|
||||
func (handler *removeSessionHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
request := &mgmt_pb.RemoveSessionRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err == nil {
|
||||
sessionId := &identity.TokenId{Token: request.SessionId}
|
||||
if err := handler.network.RemoveSession(sessionId, request.Now); err == nil {
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
pfxlog.Logger().Errorf("unexpected error removing session s/[%s] (%s)", sessionId.Token, err)
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type setLinkCostHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newSetLinkCostHandler(network *network.Network) *setLinkCostHandler {
|
||||
return &setLinkCostHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *setLinkCostHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_SetLinkCostRequestType)
|
||||
}
|
||||
|
||||
func (h *setLinkCostHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
set := &mgmt_pb.SetLinkCostRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, set); err == nil {
|
||||
if l, found := h.network.GetLink(&identity.TokenId{Token: set.LinkId}); found {
|
||||
l.Cost = int(set.Cost)
|
||||
h.network.LinkChanged(l)
|
||||
log.Infof("set cost of link [l/%s] to [%d]", set.LinkId, set.Cost)
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
sendFailure(msg, ch, fmt.Sprintf("unknown link [l/%s]", set.LinkId))
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type setLinkDownHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newSetLinkDownHandler(network *network.Network) *setLinkDownHandler {
|
||||
return &setLinkDownHandler{network: network}
|
||||
}
|
||||
|
||||
func (h *setLinkDownHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_SetLinkDownRequestType)
|
||||
}
|
||||
|
||||
func (h *setLinkDownHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
log := pfxlog.ContextLogger(ch.Label())
|
||||
|
||||
set := &mgmt_pb.SetLinkDownRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, set); err == nil {
|
||||
if l, found := h.network.GetLink(&identity.TokenId{Token: set.LinkId}); found {
|
||||
l.Down = set.Down
|
||||
h.network.LinkChanged(l)
|
||||
log.Infof("set down state of link [l/%s] to [%t]", set.LinkId, set.Down)
|
||||
sendSuccess(msg, ch, "")
|
||||
} else {
|
||||
sendFailure(msg, ch, fmt.Sprintf("unknown link [l/%s]", set.LinkId))
|
||||
}
|
||||
} else {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/metrics"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type streamMetricsHandler struct {
|
||||
network *network.Network
|
||||
streamHandlers []metrics.Handler
|
||||
}
|
||||
|
||||
func newStreamMetricsHandler(network *network.Network) *streamMetricsHandler {
|
||||
return &streamMetricsHandler{network: network}
|
||||
}
|
||||
|
||||
func (*streamMetricsHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_StreamMetricsRequestType)
|
||||
}
|
||||
|
||||
func (handler *streamMetricsHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
request := &mgmt_pb.StreamMetricsRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
filters, err := parseFilters(request)
|
||||
if err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
metricsStreamHandler := &MetricsStreamHandler{
|
||||
ch: ch,
|
||||
filters: filters,
|
||||
eventController: handler.network.GetMetricsEventController(),
|
||||
}
|
||||
|
||||
handler.streamHandlers = append(handler.streamHandlers, metricsStreamHandler)
|
||||
handler.network.GetMetricsEventController().AddHandler(metricsStreamHandler)
|
||||
}
|
||||
|
||||
func (handler *streamMetricsHandler) HandleClose(ch channel2.Channel) {
|
||||
for _, streamHandler := range handler.streamHandlers {
|
||||
handler.network.GetMetricsEventController().RemoveHandler(streamHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func parseFilters(msg *mgmt_pb.StreamMetricsRequest) ([]*metricsFilter, error) {
|
||||
var filters []*metricsFilter
|
||||
for _, filterDef := range msg.Matchers {
|
||||
filter := &metricsFilter{}
|
||||
|
||||
if filterDef.NameRegex != "" {
|
||||
regex, err := regexp.Compile(filterDef.NameRegex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.metricFilter = regex
|
||||
}
|
||||
|
||||
if filterDef.NameRegex != "" {
|
||||
regex, err := regexp.Compile(filterDef.SourceIDRegex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.sourceFilter = regex
|
||||
}
|
||||
|
||||
filters = append(filters, filter)
|
||||
}
|
||||
return filters, nil
|
||||
}
|
||||
|
||||
type metricsFilter struct {
|
||||
sourceFilter *regexp.Regexp
|
||||
metricFilter *regexp.Regexp
|
||||
}
|
||||
|
||||
type MetricsStreamHandler struct {
|
||||
ch channel2.Channel
|
||||
filters []*metricsFilter
|
||||
eventController metrics.EventController
|
||||
}
|
||||
|
||||
func (handler *MetricsStreamHandler) AcceptMetrics(msg *ctrl_pb.MetricsMessage) {
|
||||
if handler.filters == nil {
|
||||
handler.filter(nil, msg)
|
||||
return
|
||||
}
|
||||
|
||||
var filters []*metricsFilter
|
||||
for _, filter := range handler.filters {
|
||||
if filter.sourceFilter == nil || filter.sourceFilter.Match([]byte(msg.SourceId)) {
|
||||
filters = append(filters, filter)
|
||||
}
|
||||
}
|
||||
if len(filters) > 0 {
|
||||
handler.filter(filters, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *MetricsStreamHandler) filter(filters []*metricsFilter, msg *ctrl_pb.MetricsMessage) {
|
||||
event := &mgmt_pb.StreamMetricsEvent{
|
||||
SourceId: msg.SourceId,
|
||||
Timestamp: msg.Timestamp,
|
||||
Tags: msg.Tags,
|
||||
}
|
||||
|
||||
for name, value := range msg.IntValues {
|
||||
filterIntMetric(name, value, event, filters)
|
||||
}
|
||||
|
||||
for name, value := range msg.FloatValues {
|
||||
filterFloatMetric(name, value, event, filters)
|
||||
}
|
||||
|
||||
for name, value := range msg.Meters {
|
||||
filterIntMetric(name+".count", value.Count, event, filters)
|
||||
filterFloatMetric(name+".mean_rate", value.MeanRate, event, filters)
|
||||
filterFloatMetric(name+".m1_rate", value.M1Rate, event, filters)
|
||||
filterFloatMetric(name+".m5_rate", value.M5Rate, event, filters)
|
||||
filterFloatMetric(name+".m15_rate", value.M15Rate, event, filters)
|
||||
}
|
||||
|
||||
for name, value := range msg.Histograms {
|
||||
filterIntMetric(name+".count", value.Count, event, filters)
|
||||
filterIntMetric(name+".min", value.Min, event, filters)
|
||||
filterIntMetric(name+".max", value.Max, event, filters)
|
||||
filterFloatMetric(name+".mean", value.Mean, event, filters)
|
||||
filterFloatMetric(name+".std_dev", value.StdDev, event, filters)
|
||||
filterFloatMetric(name+".variance", value.Variance, event, filters)
|
||||
filterFloatMetric(name+".p50", value.P50, event, filters)
|
||||
filterFloatMetric(name+".p75", value.P75, event, filters)
|
||||
filterFloatMetric(name+".p95", value.P95, event, filters)
|
||||
filterFloatMetric(name+".p99", value.P99, event, filters)
|
||||
filterFloatMetric(name+".p999", value.P999, event, filters)
|
||||
filterFloatMetric(name+".p9999", value.P9999, event, filters)
|
||||
}
|
||||
|
||||
for name, interval := range msg.IntervalCounters {
|
||||
if nameMatches(name, filters) {
|
||||
for _, bucket := range interval.Buckets {
|
||||
intervalMetric := &mgmt_pb.StreamMetricsEvent_IntervalMetric{
|
||||
Name: name,
|
||||
}
|
||||
intervalMetric.Values = bucket.Values
|
||||
intervalMetric.IntervalStartUTC = ×tamp.Timestamp{Seconds: bucket.IntervalStartUTC}
|
||||
intervalEndSeconds := bucket.IntervalStartUTC + int64(interval.IntervalLength)
|
||||
intervalMetric.IntervalEndUTC = ×tamp.Timestamp{Seconds: intervalEndSeconds}
|
||||
|
||||
event.IntervalMetrics = append(event.IntervalMetrics, intervalMetric)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(event.IntMetrics) > 0 || len(event.FloatMetrics) > 0 || len(event.IntervalMetrics) > 0 {
|
||||
handler.send(event)
|
||||
}
|
||||
}
|
||||
|
||||
func filterIntMetric(name string, value int64, event *mgmt_pb.StreamMetricsEvent, filters []*metricsFilter) {
|
||||
if nameMatches(name, filters) {
|
||||
if event.IntMetrics == nil {
|
||||
event.IntMetrics = make(map[string]int64)
|
||||
}
|
||||
event.IntMetrics[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func filterFloatMetric(name string, value float64, event *mgmt_pb.StreamMetricsEvent, filters []*metricsFilter) {
|
||||
if nameMatches(name, filters) {
|
||||
if event.FloatMetrics == nil {
|
||||
event.FloatMetrics = make(map[string]float64)
|
||||
}
|
||||
event.FloatMetrics[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
func nameMatches(name string, filters []*metricsFilter) bool {
|
||||
if len(filters) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, filter := range filters {
|
||||
if filter.metricFilter == nil || filter.metricFilter.Match([]byte(name)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (handler *MetricsStreamHandler) send(msg *mgmt_pb.StreamMetricsEvent) {
|
||||
body, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error serializing StreamMetricsEvent (%s)", err)
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_StreamMetricsEventType), body)
|
||||
if err := handler.ch.Send(responseMsg); err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error sending StreamMetricsEvent (%s)", err)
|
||||
handler.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *MetricsStreamHandler) close() {
|
||||
if err := handler.ch.Close(); err != nil {
|
||||
pfxlog.Logger().WithError(err).Errorf("failure while closing handler")
|
||||
}
|
||||
handler.eventController.RemoveHandler(handler)
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type streamSessionsHandler struct {
|
||||
network *network.Network
|
||||
streamHandlers []network.SessionLifeCycleListener
|
||||
}
|
||||
|
||||
func newStreamSessionsHandler(network *network.Network) *streamSessionsHandler {
|
||||
return &streamSessionsHandler{network: network}
|
||||
}
|
||||
|
||||
func (*streamSessionsHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_StreamSessionsRequestType)
|
||||
}
|
||||
|
||||
func (handler *streamSessionsHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
request := &mgmt_pb.StreamSessionsRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sessionEventRouter := handler.network.GetSessionLifeCycleController()
|
||||
sessionsStreamHandler := &SessionsStreamHandler{
|
||||
ch: ch,
|
||||
router: sessionEventRouter,
|
||||
}
|
||||
handler.streamHandlers = append(handler.streamHandlers, sessionsStreamHandler)
|
||||
sessionEventRouter.AddListener(sessionsStreamHandler)
|
||||
}
|
||||
|
||||
func (handler *streamSessionsHandler) HandleClose(ch channel2.Channel) {
|
||||
for _, listener := range handler.streamHandlers {
|
||||
handler.network.GetSessionLifeCycleController().RemoveListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
type SessionsStreamHandler struct {
|
||||
ch channel2.Channel
|
||||
router network.SessionLifeCycleController
|
||||
}
|
||||
|
||||
func (handler *SessionsStreamHandler) SessionCreated(sessionId *identity.TokenId, clientId *identity.TokenId, serviceId string, circuit *network.Circuit) {
|
||||
event := &mgmt_pb.StreamSessionsEvent{
|
||||
EventType: mgmt_pb.StreamSessionEventType_SessionCreated,
|
||||
SessionId: sessionId.Token,
|
||||
ClientId: clientId.Token,
|
||||
ServiceId: serviceId,
|
||||
Circuit: NewCircuit(circuit),
|
||||
}
|
||||
handler.sendEvent(event)
|
||||
}
|
||||
|
||||
func (handler *SessionsStreamHandler) SessionDeleted(sessionId *identity.TokenId) {
|
||||
event := &mgmt_pb.StreamSessionsEvent{
|
||||
EventType: mgmt_pb.StreamSessionEventType_SessionDeleted,
|
||||
SessionId: sessionId.Token,
|
||||
}
|
||||
handler.sendEvent(event)
|
||||
}
|
||||
|
||||
func (handler *SessionsStreamHandler) CircuitUpdated(sessionId *identity.TokenId, circuit *network.Circuit) {
|
||||
event := &mgmt_pb.StreamSessionsEvent{
|
||||
EventType: mgmt_pb.StreamSessionEventType_CircuitUpdated,
|
||||
SessionId: sessionId.Token,
|
||||
Circuit: NewCircuit(circuit),
|
||||
}
|
||||
handler.sendEvent(event)
|
||||
}
|
||||
|
||||
func (handler *SessionsStreamHandler) sendEvent(event *mgmt_pb.StreamSessionsEvent) {
|
||||
body, err := proto.Marshal(event)
|
||||
if err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error serializing StreamSessionsEvent (%s)", err)
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_StreamSessionsEventType), body)
|
||||
if err := handler.ch.Send(responseMsg); err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error sending StreamMetricsEvent (%s)", err)
|
||||
handler.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *SessionsStreamHandler) close() {
|
||||
if err := handler.ch.Close(); err != nil {
|
||||
pfxlog.Logger().WithError(err).Error("unexpected error closing mgmt channel")
|
||||
}
|
||||
handler.router.RemoveListener(handler)
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/trace"
|
||||
trace_pb "github.com/netfoundry/ziti-foundation/trace/pb"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type traceTogglePipeHandler struct {
|
||||
network *network.Network
|
||||
}
|
||||
|
||||
func newTogglePipeTracesHandler(network *network.Network) *traceTogglePipeHandler {
|
||||
return &traceTogglePipeHandler{network: network}
|
||||
}
|
||||
|
||||
func (*traceTogglePipeHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_TogglePipeTracesRequestType)
|
||||
}
|
||||
|
||||
func (handler *traceTogglePipeHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
request := &trace_pb.TogglePipeTracesRequest{}
|
||||
|
||||
if err := proto.Unmarshal(msg.Body, request); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
matchers, result := trace.NewPipeToggleMatchers(request)
|
||||
|
||||
if !result.Success {
|
||||
handler.complete(msg, ch, result)
|
||||
return
|
||||
}
|
||||
|
||||
resultChan := make(chan trace.ToggleApplyResult)
|
||||
|
||||
verbosity := trace.GetVerbosity(request.Verbosity)
|
||||
|
||||
if checkMatch(handler.network.GetAppId().Token, matchers, verbosity, result) {
|
||||
if request.Enable {
|
||||
handler.network.GetTraceController().EnableTracing(trace.SourceTypePipe, matchers.PipeMatcher, resultChan)
|
||||
} else {
|
||||
handler.network.GetTraceController().DisableTracing(trace.SourceTypePipe, matchers.PipeMatcher, resultChan)
|
||||
}
|
||||
getApplyResults(resultChan, verbosity, result)
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
handler.complete(msg, ch, result)
|
||||
return
|
||||
}
|
||||
|
||||
remoteResultChan := make(chan *remoteToggleResult)
|
||||
waitGroup := &sync.WaitGroup{}
|
||||
|
||||
for _, router := range handler.network.AllConnectedRouters() {
|
||||
if checkMatch(router.Id, matchers, verbosity, result) {
|
||||
msg := channel2.NewMessage(int32(ctrl_pb.ContentType_TogglePipeTracesRequestType), msg.Body)
|
||||
respCh, err := router.Control.SendAndWait(msg)
|
||||
if err != nil {
|
||||
result.Success = false
|
||||
result.Append(fmt.Sprintf("Trace enable of Router %v failed with: %v", router.Id, err))
|
||||
} else {
|
||||
waitGroup.Add(1)
|
||||
go handleResponse(router.Id, respCh, remoteResultChan, waitGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close chan once all results have been queued
|
||||
go func() {
|
||||
waitGroup.Wait()
|
||||
close(remoteResultChan)
|
||||
}()
|
||||
|
||||
for remoteToggleResult := range remoteResultChan {
|
||||
if !remoteToggleResult.success {
|
||||
result.Success = false
|
||||
}
|
||||
result.Message.WriteString(remoteToggleResult.message)
|
||||
}
|
||||
|
||||
handler.complete(msg, ch, result)
|
||||
}
|
||||
|
||||
func (handler *traceTogglePipeHandler) complete(msg *channel2.Message, ch channel2.Channel, result *trace.ToggleResult) {
|
||||
if result.Success {
|
||||
sendSuccess(msg, ch, result.Message.String())
|
||||
} else {
|
||||
sendFailure(msg, ch, result.Message.String())
|
||||
}
|
||||
}
|
||||
|
||||
func checkMatch(appId string, matchers *trace.PipeToggleMatchers, verbosity trace.ToggleVerbosity, result *trace.ToggleResult) bool {
|
||||
appMatches := matchers.AppMatcher.Matches(appId)
|
||||
applyResult := &trace.ToggleApplyResultImpl{
|
||||
Matched: appMatches,
|
||||
Message: fmt.Sprintf("App %v matched? %v", appId, appMatches),
|
||||
}
|
||||
applyResult.Append(result, verbosity)
|
||||
return appMatches
|
||||
}
|
||||
|
||||
func getApplyResults(resultChan chan trace.ToggleApplyResult, verbosity trace.ToggleVerbosity, result *trace.ToggleResult) {
|
||||
timout := time.After(time.Second * 5)
|
||||
for {
|
||||
select {
|
||||
case applyResult, chanOpen := <-resultChan:
|
||||
if !chanOpen {
|
||||
return
|
||||
}
|
||||
applyResult.Append(result, verbosity)
|
||||
case <-timout:
|
||||
result.Success = false
|
||||
result.Append("Timed out waiting for toggle to be applied to controller")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleResponse(targetId string, respCh <-chan *channel2.Message, msgsCh chan<- *remoteToggleResult, waitGroup *sync.WaitGroup) {
|
||||
defer waitGroup.Done()
|
||||
|
||||
timeout := time.After(time.Second * 5)
|
||||
|
||||
select {
|
||||
case response, ok := <-respCh:
|
||||
if !ok {
|
||||
msg := fmt.Sprintf("No response from router %v\n", targetId)
|
||||
msgsCh <- &remoteToggleResult{false, msg}
|
||||
} else if response.ContentType == channel2.ContentTypeResultType {
|
||||
result := channel2.UnmarshalResult(response)
|
||||
msgsCh <- &remoteToggleResult{result.Success, result.Message}
|
||||
} else {
|
||||
msg := fmt.Sprintf("Unexpected response type from router %v: %v\n", targetId, response.ContentType)
|
||||
msgsCh <- &remoteToggleResult{false, msg}
|
||||
}
|
||||
case <-timeout:
|
||||
msg := fmt.Sprintf("Timed out waiting for response from router %v\n", targetId)
|
||||
msgsCh <- &remoteToggleResult{false, msg}
|
||||
}
|
||||
}
|
||||
|
||||
type remoteToggleResult struct {
|
||||
success bool
|
||||
message string
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package handler_mgmt
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/network"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/mgmt_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/trace"
|
||||
"github.com/netfoundry/ziti-foundation/trace/pb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type streamTracesHandler struct {
|
||||
network *network.Network
|
||||
streamHandlers []trace.EventHandler
|
||||
}
|
||||
|
||||
func newStreamTracesHandler(network *network.Network) *streamTracesHandler {
|
||||
return &streamTracesHandler{network: network}
|
||||
}
|
||||
|
||||
func (*streamTracesHandler) ContentType() int32 {
|
||||
return int32(mgmt_pb.ContentType_StreamTracesRequestType)
|
||||
}
|
||||
|
||||
func (handler *streamTracesHandler) HandleReceive(msg *channel2.Message, ch channel2.Channel) {
|
||||
request := &mgmt_pb.StreamTracesRequest{}
|
||||
if err := proto.Unmarshal(msg.Body, request); err != nil {
|
||||
sendFailure(msg, ch, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
eventRouter := handler.network.GetTraceEventController()
|
||||
|
||||
filter := createFilter(request)
|
||||
eventHandler := &traceEventsHandler{ch, eventRouter, filter}
|
||||
|
||||
handler.streamHandlers = append(handler.streamHandlers, eventHandler)
|
||||
eventRouter.AddHandler(eventHandler)
|
||||
}
|
||||
|
||||
func (handler *streamTracesHandler) HandleClose(ch channel2.Channel) {
|
||||
for _, streamHandler := range handler.streamHandlers {
|
||||
handler.network.GetTraceEventController().RemoveHandler(streamHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func createFilter(request *mgmt_pb.StreamTracesRequest) trace.Filter {
|
||||
if !request.EnabledFilter {
|
||||
return trace.NewAllowAllFilter()
|
||||
}
|
||||
if request.FilterType == mgmt_pb.TraceFilterType_INCLUDE {
|
||||
return trace.NewIncludeFilter(request.ContentTypes)
|
||||
}
|
||||
return trace.NewExcludeFilter(request.ContentTypes)
|
||||
}
|
||||
|
||||
type traceEventsHandler struct {
|
||||
ch channel2.Channel
|
||||
router trace.EventController
|
||||
filter trace.Filter
|
||||
}
|
||||
|
||||
func (handler *traceEventsHandler) Accept(event *trace_pb.ChannelMessage) {
|
||||
if !handler.filter.Accept(event) {
|
||||
return
|
||||
}
|
||||
body, err := proto.Marshal(event)
|
||||
if err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error unmarshalling ChannelMessage (%s)", err)
|
||||
return
|
||||
}
|
||||
|
||||
responseMsg := channel2.NewMessage(int32(mgmt_pb.ContentType_StreamTracesEventType), body)
|
||||
if err := handler.ch.Send(responseMsg); err != nil {
|
||||
pfxlog.Logger().Errorf("unexpected error sending ChannelMessage (%s)", err)
|
||||
handler.close()
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *traceEventsHandler) close() {
|
||||
if err := handler.ch.Close(); err != nil {
|
||||
pfxlog.Logger().WithError(err).Error("unexpected error while closing mgmt channel")
|
||||
}
|
||||
handler.router.RemoveHandler(handler)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-foundation/util/info"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
func (network *Network) assemble() {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
if network.routerController.count() > 1 {
|
||||
log.Debugf("assembling with [%d] routers", network.routerController.count())
|
||||
|
||||
missingLinks, err := network.linkController.missingLinks(network.routerController.all())
|
||||
if err == nil {
|
||||
for _, missingLink := range missingLinks {
|
||||
network.linkController.add(missingLink)
|
||||
|
||||
dial := &ctrl_pb.Dial{
|
||||
Id: missingLink.Id.Token,
|
||||
Address: missingLink.Dst.AdvertisedListener.String(),
|
||||
}
|
||||
bytes, err := proto.Marshal(dial)
|
||||
if err == nil {
|
||||
msg := channel2.NewMessage(int32(ctrl_pb.ContentType_DialType), bytes)
|
||||
missingLink.Src.Control.Send(msg)
|
||||
|
||||
} else {
|
||||
log.Errorf("unexpected error (%s)", err)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
log.WithField("err", err).Error("missing link enumeration failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) clean() {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
failedLinks := network.linkController.linksInMode(Failed)
|
||||
|
||||
now := info.NowInMilliseconds()
|
||||
lRemove := make(map[string]*Link)
|
||||
for _, l := range failedLinks {
|
||||
if now-l.CurrentState().Timestamp >= 30000 {
|
||||
lRemove[l.Id.Token] = l
|
||||
}
|
||||
}
|
||||
for _, lr := range lRemove {
|
||||
log.Infof("removing [l/%s]", lr.Id.Token)
|
||||
network.linkController.remove(lr)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Circuit struct {
|
||||
Path []*Router
|
||||
Links []*Link
|
||||
Binding string
|
||||
IngressId string
|
||||
EgressId string
|
||||
}
|
||||
|
||||
func (circuit *Circuit) String() string {
|
||||
if len(circuit.Path) < 1 {
|
||||
return "{}"
|
||||
}
|
||||
if len(circuit.Links) != len(circuit.Path) - 1 {
|
||||
return "{malformed}"
|
||||
}
|
||||
out := fmt.Sprintf("[r/%s]", circuit.Path[0].Id)
|
||||
for i := 0; i < len(circuit.Links); i++ {
|
||||
out += fmt.Sprintf("->[l/%s]", circuit.Links[i].Id.Token)
|
||||
out += fmt.Sprintf("->[r/%s]", circuit.Path[i+1].Id)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (circuit *Circuit) EqualPath(other *Circuit) bool {
|
||||
if len(circuit.Path) != len(other.Path) {
|
||||
return false
|
||||
}
|
||||
if len(circuit.Links) != len(other.Links) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(circuit.Path); i++ {
|
||||
if circuit.Path[i] != other.Path[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(circuit.Links); i++ {
|
||||
if circuit.Links[i] != other.Links[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (circuit *Circuit) EgressRouter() *Router {
|
||||
if len(circuit.Path) > 0 {
|
||||
return circuit.Path[len(circuit.Path)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (circuit *Circuit) CreateRouteMessages(sessionId *identity.TokenId, egressAddress string) ([]*ctrl_pb.Route, error) {
|
||||
var routeMessages []*ctrl_pb.Route
|
||||
if len(circuit.Links) == 0 {
|
||||
// single router path
|
||||
routeMessage := &ctrl_pb.Route{SessionId: sessionId.Token}
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: circuit.IngressId,
|
||||
DstAddress: circuit.EgressId,
|
||||
})
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: circuit.EgressId,
|
||||
DstAddress: circuit.IngressId,
|
||||
})
|
||||
routeMessage.Egress = &ctrl_pb.Route_Egress{
|
||||
Binding: circuit.Binding,
|
||||
Address: circuit.EgressId,
|
||||
Destination: egressAddress,
|
||||
}
|
||||
routeMessages = append(routeMessages, routeMessage)
|
||||
}
|
||||
|
||||
for i, link := range circuit.Links {
|
||||
if i == 0 {
|
||||
// ingress
|
||||
routeMessage := &ctrl_pb.Route{SessionId: sessionId.Token}
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: circuit.IngressId,
|
||||
DstAddress: link.Id.Token,
|
||||
})
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: link.Id.Token,
|
||||
DstAddress: circuit.IngressId,
|
||||
})
|
||||
routeMessages = append(routeMessages, routeMessage)
|
||||
}
|
||||
if i >= 0 && i < len(circuit.Links)-1 {
|
||||
// transit
|
||||
nextLink := circuit.Links[i+1]
|
||||
routeMessage := &ctrl_pb.Route{SessionId: sessionId.Token}
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: link.Id.Token,
|
||||
DstAddress: nextLink.Id.Token,
|
||||
})
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: nextLink.Id.Token,
|
||||
DstAddress: link.Id.Token,
|
||||
})
|
||||
routeMessages = append(routeMessages, routeMessage)
|
||||
}
|
||||
if i == len(circuit.Links)-1 {
|
||||
// egress
|
||||
routeMessage := &ctrl_pb.Route{SessionId: sessionId.Token}
|
||||
routeMessage.Egress = &ctrl_pb.Route_Egress{
|
||||
Binding: circuit.Binding,
|
||||
Address: circuit.EgressId,
|
||||
Destination: egressAddress,
|
||||
}
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: circuit.EgressId,
|
||||
DstAddress: link.Id.Token,
|
||||
})
|
||||
routeMessage.Forwards = append(routeMessage.Forwards, &ctrl_pb.Route_Forward{
|
||||
SrcAddress: link.Id.Token,
|
||||
DstAddress: circuit.EgressId,
|
||||
})
|
||||
routeMessages = append(routeMessages, routeMessage)
|
||||
}
|
||||
}
|
||||
return routeMessages, nil
|
||||
}
|
||||
|
||||
func (circuit *Circuit) usesLink(l *Link) bool {
|
||||
if circuit.Links != nil {
|
||||
for _, o := range circuit.Links {
|
||||
if o == l {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/netfoundry/ziti-foundation/transport/tcp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleCircuit2(t *testing.T) {
|
||||
network, err := NewNetwork(nil, nil, nil, nil)
|
||||
assert.Nil(t, err)
|
||||
|
||||
addr := "tcp:0.0.0.0:0"
|
||||
transportAddr, err := tcp.AddressParser{}.Parse(addr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
r0 := newRouter("r0", "", transportAddr, nil)
|
||||
network.routerController.add(r0)
|
||||
|
||||
r1 := newRouter("r1", "", transportAddr, nil)
|
||||
network.routerController.add(r1)
|
||||
|
||||
l0 := newLink(&identity.TokenId{Token: "l0"})
|
||||
l0.Src = r0
|
||||
l0.Dst = r1
|
||||
l0.addState(newLinkState(Connected))
|
||||
network.linkController.add(l0)
|
||||
|
||||
circuit, err := network.CreateCircuit(r0, r1)
|
||||
assert.NotNil(t, circuit)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(circuit.Path))
|
||||
assert.Equal(t, r0, circuit.Path[0])
|
||||
assert.Equal(t, r1, circuit.Path[1])
|
||||
assert.Equal(t, 1, len(circuit.Links))
|
||||
assert.Equal(t, l0, circuit.Links[0])
|
||||
assert.Equal(t, r1, circuit.EgressRouter())
|
||||
|
||||
s0 := &identity.TokenId{Token: "s0"}
|
||||
routeMessages, err := circuit.CreateRouteMessages(s0, addr)
|
||||
assert.NotNil(t, routeMessages)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(routeMessages))
|
||||
|
||||
// ingress route message
|
||||
rm0 := routeMessages[0]
|
||||
assert.Equal(t, s0.Token, rm0.SessionId)
|
||||
assert.Nil(t, rm0.Egress)
|
||||
assert.Equal(t, 2, len(rm0.Forwards))
|
||||
assert.Equal(t, circuit.IngressId, rm0.Forwards[0].SrcAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm0.Forwards[0].DstAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm0.Forwards[1].SrcAddress)
|
||||
assert.Equal(t, circuit.IngressId, rm0.Forwards[1].DstAddress)
|
||||
|
||||
// egress route message
|
||||
rm1 := routeMessages[1]
|
||||
assert.Equal(t, s0.Token, rm1.SessionId)
|
||||
assert.NotNil(t, rm1.Egress)
|
||||
assert.Equal(t, circuit.EgressId, rm1.Egress.Address)
|
||||
assert.Equal(t, addr, rm1.Egress.Destination)
|
||||
assert.Equal(t, circuit.EgressId, rm1.Forwards[0].SrcAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm1.Forwards[0].DstAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm1.Forwards[1].SrcAddress)
|
||||
assert.Equal(t, circuit.EgressId, rm1.Forwards[1].DstAddress)
|
||||
}
|
||||
|
||||
func TestTransitCircuit2(t *testing.T) {
|
||||
network, err := NewNetwork(nil, nil, nil, nil)
|
||||
assert.Nil(t, err)
|
||||
|
||||
addr := "tcp:0.0.0.0:0"
|
||||
transportAddr, err := tcp.AddressParser{}.Parse(addr)
|
||||
assert.Nil(t, err)
|
||||
|
||||
r0 := newRouter("r0", "", transportAddr, nil)
|
||||
network.routerController.add(r0)
|
||||
|
||||
r1 := newRouter("r1", "", transportAddr, nil)
|
||||
network.routerController.add(r1)
|
||||
|
||||
r2 := newRouter("r2", "", transportAddr, nil)
|
||||
network.routerController.add(r2)
|
||||
|
||||
l0 := newLink(&identity.TokenId{Token: "l0"})
|
||||
l0.Src = r0
|
||||
l0.Dst = r1
|
||||
l0.addState(newLinkState(Connected))
|
||||
network.linkController.add(l0)
|
||||
|
||||
l1 := newLink(&identity.TokenId{Token: "l1"})
|
||||
l1.Src = r1
|
||||
l1.Dst = r2
|
||||
l1.addState(newLinkState(Connected))
|
||||
network.linkController.add(l1)
|
||||
|
||||
circuit, err := network.CreateCircuit(r0, r2)
|
||||
assert.NotNil(t, circuit)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(circuit.Path))
|
||||
assert.Equal(t, r0, circuit.Path[0])
|
||||
assert.Equal(t, r1, circuit.Path[1])
|
||||
assert.Equal(t, r2, circuit.Path[2])
|
||||
assert.Equal(t, 2, len(circuit.Links))
|
||||
assert.Equal(t, l0, circuit.Links[0])
|
||||
assert.Equal(t, l1, circuit.Links[1])
|
||||
assert.Equal(t, r2, circuit.EgressRouter())
|
||||
|
||||
s0 := &identity.TokenId{Token: "s0"}
|
||||
routeMessages, err := circuit.CreateRouteMessages(s0, addr)
|
||||
assert.NotNil(t, routeMessages)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(routeMessages))
|
||||
|
||||
// ingress route message
|
||||
rm0 := routeMessages[0]
|
||||
assert.Equal(t, s0.Token, rm0.SessionId)
|
||||
assert.Nil(t, rm0.Egress)
|
||||
assert.Equal(t, 2, len(rm0.Forwards))
|
||||
assert.Equal(t, circuit.IngressId, rm0.Forwards[0].SrcAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm0.Forwards[0].DstAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm0.Forwards[1].SrcAddress)
|
||||
assert.Equal(t, circuit.IngressId, rm0.Forwards[1].DstAddress)
|
||||
|
||||
// transit route message
|
||||
rm1 := routeMessages[1]
|
||||
assert.Equal(t, s0.Token, rm1.SessionId)
|
||||
assert.Nil(t, rm1.Egress)
|
||||
assert.Equal(t, 2, len(rm1.Forwards))
|
||||
assert.Equal(t, l0.Id.Token, rm1.Forwards[0].SrcAddress)
|
||||
assert.Equal(t, l1.Id.Token, rm1.Forwards[0].DstAddress)
|
||||
assert.Equal(t, l1.Id.Token, rm1.Forwards[1].SrcAddress)
|
||||
assert.Equal(t, l0.Id.Token, rm1.Forwards[1].DstAddress)
|
||||
|
||||
// egress route message
|
||||
rm2 := routeMessages[2]
|
||||
assert.Equal(t, s0.Token, rm2.SessionId)
|
||||
assert.NotNil(t, rm2.Egress)
|
||||
assert.Equal(t, circuit.EgressId, rm2.Egress.Address)
|
||||
assert.Equal(t, transportAddr.String(), rm2.Egress.Destination)
|
||||
assert.Equal(t, circuit.EgressId, rm2.Forwards[0].SrcAddress)
|
||||
assert.Equal(t, l1.Id.Token, rm2.Forwards[0].DstAddress)
|
||||
assert.Equal(t, l1.Id.Token, rm2.Forwards[1].SrcAddress)
|
||||
assert.Equal(t, circuit.EgressId, rm2.Forwards[1].DstAddress)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
type RouterPresenceHandler interface {
|
||||
RouterConnected(r *Router)
|
||||
RouterDisconnected(r *Router)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/netfoundry/ziti-foundation/util/info"
|
||||
)
|
||||
|
||||
type Link struct {
|
||||
Id *identity.TokenId
|
||||
Src *Router
|
||||
Dst *Router
|
||||
state []*LinkState
|
||||
Down bool
|
||||
Cost int
|
||||
SrcLatency int64
|
||||
DstLatency int64
|
||||
}
|
||||
|
||||
func newLink(id *identity.TokenId) *Link {
|
||||
l := &Link{
|
||||
Id: id,
|
||||
state: make([]*LinkState, 0),
|
||||
Down: false,
|
||||
Cost: 1,
|
||||
}
|
||||
l.addState(&LinkState{Mode: Pending, Timestamp: info.NowInMilliseconds()})
|
||||
return l
|
||||
}
|
||||
|
||||
func (link *Link) CurrentState() *LinkState {
|
||||
if link.state == nil || len(link.state) < 1 {
|
||||
return nil
|
||||
}
|
||||
return link.state[0]
|
||||
}
|
||||
|
||||
func (link *Link) addState(s *LinkState) {
|
||||
if link.state == nil {
|
||||
link.state = make([]*LinkState, 0)
|
||||
}
|
||||
link.state = append([]*LinkState{s}, link.state...)
|
||||
}
|
||||
|
||||
type LinkMode byte
|
||||
|
||||
const (
|
||||
Pending LinkMode = iota
|
||||
Connected
|
||||
Failed
|
||||
)
|
||||
|
||||
func (t LinkMode) String() string {
|
||||
if t == Pending {
|
||||
return "Pending"
|
||||
} else if t == Connected {
|
||||
return "Connected"
|
||||
} else if t == Failed {
|
||||
return "Failed"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type LinkState struct {
|
||||
Mode LinkMode
|
||||
Timestamp int64
|
||||
}
|
||||
|
||||
func newLinkState(mode LinkMode) *LinkState {
|
||||
return &LinkState{
|
||||
Mode: mode,
|
||||
Timestamp: info.NowInMilliseconds(),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/netfoundry/ziti-foundation/util/sequence"
|
||||
"github.com/orcaman/concurrent-map"
|
||||
"math"
|
||||
)
|
||||
|
||||
type linkController struct {
|
||||
linkTable *linkTable
|
||||
adjacencyTable *adjacencyTable
|
||||
sequence *sequence.Sequence
|
||||
}
|
||||
|
||||
func newLinkController() *linkController {
|
||||
return &linkController{
|
||||
linkTable: newLinkTable(),
|
||||
adjacencyTable: newAdjacencyTable(),
|
||||
sequence: sequence.NewSequence(),
|
||||
}
|
||||
}
|
||||
|
||||
func (linkController *linkController) add(link *Link) {
|
||||
linkController.linkTable.add(link)
|
||||
linkController.adjacencyTable.add(link)
|
||||
}
|
||||
|
||||
func (linkController *linkController) has(link *Link) bool {
|
||||
return linkController.linkTable.has(link)
|
||||
}
|
||||
|
||||
func (linkController *linkController) get(linkId *identity.TokenId) (*Link, bool) {
|
||||
link, found := linkController.linkTable.get(linkId)
|
||||
return link, found
|
||||
}
|
||||
|
||||
func (linkController *linkController) all() []*Link {
|
||||
return linkController.linkTable.all()
|
||||
}
|
||||
|
||||
func (linkController *linkController) remove(link *Link) {
|
||||
linkController.linkTable.remove(link)
|
||||
linkController.adjacencyTable.remove(link)
|
||||
}
|
||||
|
||||
func (linkController *linkController) allLinksForRouter(routerId string) []*Link {
|
||||
if rlt, found := linkController.adjacencyTable.get(routerId); found {
|
||||
return rlt.allLinksForAllRouters()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (linkController *linkController) connectedNeighborsOfRouter(router *Router) []*Router {
|
||||
neighborMap := make(map[string]*Router)
|
||||
|
||||
links := linkController.allLinksForRouter(router.Id)
|
||||
for _, link := range links {
|
||||
currentState := link.CurrentState()
|
||||
if currentState != nil && currentState.Mode == Connected && !link.Down {
|
||||
if link.Src != router {
|
||||
neighborMap[link.Src.Id] = link.Src
|
||||
}
|
||||
if link.Dst != router {
|
||||
neighborMap[link.Dst.Id] = link.Dst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
neighbors := make([]*Router, 0)
|
||||
for _, r := range neighborMap {
|
||||
neighbors = append(neighbors, r)
|
||||
}
|
||||
return neighbors
|
||||
}
|
||||
|
||||
func (linkController *linkController) leastExpensiveLink(a, b *Router) (*Link, bool) {
|
||||
var selected *Link
|
||||
var cost int64 = math.MaxInt64
|
||||
|
||||
links := linkController.allLinksForRouter(a.Id)
|
||||
for _, link := range links {
|
||||
currentState := link.CurrentState()
|
||||
if currentState != nil && currentState.Mode == Connected && !link.Down {
|
||||
if link.Src == a && link.Dst == b {
|
||||
if link.SrcLatency + link.DstLatency < cost {
|
||||
selected = link
|
||||
}
|
||||
}
|
||||
if link.Dst == a && link.Src == b {
|
||||
if link.SrcLatency + link.DstLatency < cost {
|
||||
selected = link
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if selected != nil {
|
||||
return selected, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (linkController *linkController) missingLinks(routers []*Router) ([]*Link, error) {
|
||||
missingLinks := make([]*Link, 0)
|
||||
for _, srcR := range routers {
|
||||
for _, dstR := range routers {
|
||||
if srcR != dstR && dstR.AdvertisedListener != nil {
|
||||
if _, found := linkController.firstDirectedLink(srcR, dstR); !found {
|
||||
id, err := linkController.sequence.NextHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
link := newLink(&identity.TokenId{Token: id})
|
||||
link.Src = srcR
|
||||
link.Dst = dstR
|
||||
missingLinks = append(missingLinks, link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missingLinks, nil
|
||||
}
|
||||
|
||||
func (linkController *linkController) firstDirectedLink(a, b *Router) (*Link, bool) {
|
||||
// a->b
|
||||
if rlt, found := linkController.adjacencyTable.get(a.Id); found {
|
||||
if links, found := rlt.allLinksForRouter(b.Id); found {
|
||||
for _, link := range links {
|
||||
if link.Src == a && link.Dst == b && link.CurrentState().Mode == Connected {
|
||||
return link, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// b->a
|
||||
if rlt, found := linkController.adjacencyTable.get(b.Id); found {
|
||||
if links, found := rlt.allLinksForRouter(a.Id); found {
|
||||
for _, link := range links {
|
||||
if link.Src == b && link.Dst == a && link.CurrentState().Mode == Connected {
|
||||
return link, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (linkController *linkController) linksInMode(mode LinkMode) []*Link {
|
||||
return linkController.linkTable.allInMode(mode)
|
||||
}
|
||||
|
||||
/*
|
||||
* linkTable
|
||||
*/
|
||||
|
||||
type linkTable struct {
|
||||
links cmap.ConcurrentMap // map[Link.Id.Token]*Link
|
||||
}
|
||||
|
||||
func newLinkTable() *linkTable {
|
||||
return &linkTable{links: cmap.New()}
|
||||
}
|
||||
|
||||
func (lt *linkTable) add(link *Link) {
|
||||
lt.links.Set(link.Id.Token, link)
|
||||
}
|
||||
|
||||
func (lt *linkTable) get(linkId *identity.TokenId) (*Link, bool) {
|
||||
link, found := lt.links.Get(linkId.Token)
|
||||
if link != nil {
|
||||
return link.(*Link), found
|
||||
}
|
||||
return nil, found
|
||||
}
|
||||
|
||||
func (lt *linkTable) has(link *Link) bool {
|
||||
if i, found := lt.links.Get(link.Id.Token); found {
|
||||
if i.(*Link) == link {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (lt *linkTable) all() []*Link {
|
||||
links := make([]*Link, 0)
|
||||
for i := range lt.links.IterBuffered() {
|
||||
links = append(links, i.Val.(*Link))
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
func (lt *linkTable) allInMode(mode LinkMode) []*Link {
|
||||
links := make([]*Link, 0)
|
||||
for i := range lt.links.IterBuffered() {
|
||||
link := i.Val.(*Link)
|
||||
if link.CurrentState().Mode == mode {
|
||||
links = append(links, link)
|
||||
}
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
func (lt *linkTable) remove(link *Link) {
|
||||
lt.links.Remove(link.Id.Token)
|
||||
}
|
||||
|
||||
/*
|
||||
* adjacencyTable
|
||||
*/
|
||||
|
||||
type adjacencyTable struct {
|
||||
adjacency cmap.ConcurrentMap // map[Router.Id.Token]*routerLinksTable
|
||||
}
|
||||
|
||||
func newAdjacencyTable() *adjacencyTable {
|
||||
return &adjacencyTable{adjacency: cmap.New()}
|
||||
}
|
||||
|
||||
func (at *adjacencyTable) add(link *Link) {
|
||||
// src->dst
|
||||
var rlt *routerLinksTable
|
||||
if i, found := at.adjacency.Get(link.Src.Id); found {
|
||||
rlt = i.(*routerLinksTable)
|
||||
} else {
|
||||
rlt = newRouterLinksTable()
|
||||
}
|
||||
rlt.addLinkForRouter(link.Dst.Id, link)
|
||||
at.adjacency.Set(link.Src.Id, rlt)
|
||||
|
||||
// dst->src
|
||||
if i, found := at.adjacency.Get(link.Dst.Id); found {
|
||||
rlt = i.(*routerLinksTable)
|
||||
} else {
|
||||
rlt = newRouterLinksTable()
|
||||
}
|
||||
rlt.addLinkForRouter(link.Src.Id, link)
|
||||
at.adjacency.Set(link.Dst.Id, rlt)
|
||||
}
|
||||
|
||||
func (at *adjacencyTable) get(routerId string) (*routerLinksTable, bool) {
|
||||
i, found := at.adjacency.Get(routerId)
|
||||
if i != nil {
|
||||
return i.(*routerLinksTable), found
|
||||
}
|
||||
return nil, found
|
||||
}
|
||||
|
||||
func (at *adjacencyTable) remove(link *Link) {
|
||||
// src->dst
|
||||
if i, found := at.adjacency.Get(link.Src.Id); found {
|
||||
rlt := i.(*routerLinksTable)
|
||||
rlt.removeLinkFromRouter(link.Dst.Id, link)
|
||||
if rlt.size() > 0 {
|
||||
at.adjacency.Set(link.Src.Id, rlt)
|
||||
} else {
|
||||
at.adjacency.Remove(link.Src.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// dst->src
|
||||
if i, found := at.adjacency.Get(link.Dst.Id); found {
|
||||
rlt := i.(*routerLinksTable)
|
||||
rlt.removeLinkFromRouter(link.Src.Id, link)
|
||||
if rlt.size() > 0 {
|
||||
at.adjacency.Set(link.Dst.Id, rlt)
|
||||
} else {
|
||||
at.adjacency.Remove(link.Dst.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* routerLinksTable
|
||||
*/
|
||||
|
||||
type routerLinksTable struct {
|
||||
routerLinks cmap.ConcurrentMap // map[Router.Id.Token][]*Link
|
||||
}
|
||||
|
||||
func newRouterLinksTable() *routerLinksTable {
|
||||
return &routerLinksTable{routerLinks: cmap.New()}
|
||||
}
|
||||
|
||||
func (rlt *routerLinksTable) addLinkForRouter(routerId string, link *Link) {
|
||||
var links []*Link
|
||||
if i, found := rlt.routerLinks.Get(routerId); found {
|
||||
links = i.([]*Link)
|
||||
} else {
|
||||
links = make([]*Link, 0)
|
||||
}
|
||||
|
||||
links = append(links, link)
|
||||
rlt.routerLinks.Set(routerId, links)
|
||||
}
|
||||
|
||||
func (rlt *routerLinksTable) allLinksForRouter(routerId string) ([]*Link, bool) {
|
||||
if i, found := rlt.routerLinks.Get(routerId); found {
|
||||
return i.([]*Link), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (rlt *routerLinksTable) allLinksForAllRouters() []*Link {
|
||||
linksMap := make(map[string]*Link)
|
||||
for i := range rlt.routerLinks.IterBuffered() {
|
||||
links := i.Val.([]*Link)
|
||||
for _, link := range links {
|
||||
linksMap[link.Id.Token] = link
|
||||
}
|
||||
}
|
||||
|
||||
allLinks := make([]*Link, 0)
|
||||
for _, v := range linksMap {
|
||||
allLinks = append(allLinks, v)
|
||||
}
|
||||
|
||||
return allLinks
|
||||
}
|
||||
|
||||
func (rlt *routerLinksTable) size() int {
|
||||
return rlt.routerLinks.Count()
|
||||
}
|
||||
|
||||
func (rlt *routerLinksTable) removeLinkFromRouter(routerId string, link *Link) {
|
||||
var links []*Link
|
||||
if i, found := rlt.routerLinks.Get(routerId); found {
|
||||
links = i.([]*Link)
|
||||
if len(links) == 1 && links[0] == link {
|
||||
rlt.routerLinks.Remove(routerId)
|
||||
|
||||
} else {
|
||||
i := -1
|
||||
for j, jLink := range links {
|
||||
if jLink == link {
|
||||
i = j
|
||||
break
|
||||
}
|
||||
}
|
||||
if i != -1 {
|
||||
links = append(links[:i], links[i+1:]...)
|
||||
}
|
||||
rlt.routerLinks.Set(routerId, links)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLifecycle(t *testing.T) {
|
||||
linkController := newLinkController()
|
||||
|
||||
r0 := NewRouter("r0", "")
|
||||
r1 := NewRouter("r1", "")
|
||||
l0 := &Link{
|
||||
Id: &identity.TokenId{Token: "l0"},
|
||||
Src: r0,
|
||||
Dst: r1,
|
||||
}
|
||||
|
||||
linkController.add(l0)
|
||||
assert.True(t, linkController.has(l0))
|
||||
|
||||
links := linkController.allLinksForRouter(r0.Id)
|
||||
assert.Equal(t, 1, len(links))
|
||||
assert.Equal(t, l0, links[0])
|
||||
|
||||
links = linkController.allLinksForRouter(r1.Id)
|
||||
assert.Equal(t, 1, len(links))
|
||||
assert.Equal(t, l0, links[0])
|
||||
|
||||
linkController.remove(l0)
|
||||
assert.False(t, linkController.has(l0))
|
||||
|
||||
links = linkController.allLinksForRouter(r0.Id)
|
||||
assert.Equal(t, 0, len(links))
|
||||
|
||||
links = linkController.allLinksForRouter(r1.Id)
|
||||
assert.Equal(t, 0, len(links))
|
||||
}
|
||||
|
||||
func TestNeighbors(t *testing.T) {
|
||||
linkController := newLinkController()
|
||||
|
||||
r0 := newRouter("r0", "", nil, nil)
|
||||
r1 := newRouter("r1", "", nil, nil)
|
||||
l0 := &Link{
|
||||
Id: &identity.TokenId{Token: "l0"},
|
||||
Src: r0,
|
||||
Dst: r1,
|
||||
}
|
||||
l0.addState(newLinkState(Connected))
|
||||
linkController.add(l0)
|
||||
|
||||
neighbors := linkController.connectedNeighborsOfRouter(r0)
|
||||
assert.Equal(t, 1, len(neighbors))
|
||||
assert.Equal(t, r1, neighbors[0])
|
||||
}
|
||||
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/db"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/metrics"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/pb/ctrl_pb"
|
||||
"github.com/netfoundry/ziti-fabric/fabric/trace"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/netfoundry/ziti-foundation/util/concurrenz"
|
||||
"github.com/netfoundry/ziti-foundation/util/sequence"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Network struct {
|
||||
nodeId *identity.TokenId
|
||||
db *db.Db
|
||||
options *Options
|
||||
routerController *routerController
|
||||
routerStore RouterStore
|
||||
routerChanged chan *Router
|
||||
linkController *linkController
|
||||
linkChanged chan *Link
|
||||
serviceController *serviceController
|
||||
sessionController *sessionController
|
||||
sequence *sequence.Sequence
|
||||
metricsEventController metrics.EventController
|
||||
sessionLifeCycleController SessionLifeCycleController
|
||||
traceEventController trace.EventController
|
||||
traceController trace.Controller
|
||||
routerPresenceHandlers []RouterPresenceHandler
|
||||
capabilities []string
|
||||
shutdownChan chan struct{}
|
||||
isShutdown concurrenz.AtomicBoolean
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewNetwork(nodeId *identity.TokenId, options *Options, db *db.Db, metricsCfg *metrics.Config) (*Network, error) {
|
||||
serviceController, err := newServiceController(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
network := &Network{
|
||||
nodeId: nodeId,
|
||||
db: db,
|
||||
options: options,
|
||||
routerController: newRouterController(),
|
||||
routerStore: NewRouterStore(db),
|
||||
routerChanged: make(chan *Router),
|
||||
linkController: newLinkController(),
|
||||
linkChanged: make(chan *Link),
|
||||
serviceController: serviceController,
|
||||
sessionController: newSessionController(),
|
||||
sequence: sequence.NewSequence(),
|
||||
metricsEventController: metrics.NewEventController(metricsCfg),
|
||||
sessionLifeCycleController: NewSessionLifeCyleController(),
|
||||
traceEventController: trace.NewEventController(),
|
||||
traceController: trace.NewController(),
|
||||
shutdownChan: make(chan struct{}),
|
||||
}
|
||||
network.metricsEventController.AddHandler(network)
|
||||
network.AddCapability("ziti.fabric")
|
||||
network.showOptions()
|
||||
return network, nil
|
||||
}
|
||||
|
||||
func (network *Network) GetAppId() *identity.TokenId {
|
||||
return network.nodeId
|
||||
}
|
||||
|
||||
func (network *Network) GetDb() boltz.Db {
|
||||
return network.db
|
||||
}
|
||||
|
||||
func (network *Network) GetRouterStore() RouterStore {
|
||||
return network.routerStore
|
||||
}
|
||||
|
||||
func (network *Network) CreateRouter(router *Router) error {
|
||||
return network.routerStore.create(router)
|
||||
}
|
||||
|
||||
func (network *Network) GetConnectedRouter(routerId string) (*Router, bool) {
|
||||
return network.routerController.get(routerId)
|
||||
}
|
||||
|
||||
func (network *Network) GetRouter(routerId string) (*Router, error) {
|
||||
return network.routerStore.loadOneById(routerId)
|
||||
}
|
||||
|
||||
func (network *Network) AllRouters() ([]*Router, error) {
|
||||
return network.routerStore.all()
|
||||
}
|
||||
|
||||
func (network *Network) AllConnectedRouters() []*Router {
|
||||
return network.routerController.all()
|
||||
}
|
||||
|
||||
func (network *Network) RemoveRouter(router *Router) error {
|
||||
return network.routerStore.remove(router.Id)
|
||||
}
|
||||
|
||||
func (network *Network) GetServiceStore() ServiceStore {
|
||||
return network.serviceController.store
|
||||
}
|
||||
|
||||
func (network *Network) CreateService(service *Service) error {
|
||||
return network.serviceController.create(service)
|
||||
}
|
||||
|
||||
func (network *Network) GetService(serviceId string) (*Service, bool) {
|
||||
return network.serviceController.get(serviceId)
|
||||
}
|
||||
|
||||
func (network *Network) AllServices() ([]*Service, error) {
|
||||
return network.serviceController.all()
|
||||
}
|
||||
|
||||
func (network *Network) RemoveService(id string) error {
|
||||
return network.serviceController.remove(id)
|
||||
}
|
||||
|
||||
func (network *Network) GetLink(linkId *identity.TokenId) (*Link, bool) {
|
||||
return network.linkController.get(linkId)
|
||||
}
|
||||
|
||||
func (network *Network) GetAllLinks() []*Link {
|
||||
return network.linkController.all()
|
||||
}
|
||||
|
||||
func (network *Network) GetAllLinksForRouter(routerId string) []*Link {
|
||||
return network.linkController.allLinksForRouter(routerId)
|
||||
}
|
||||
|
||||
func (network *Network) GetSession(sessionId *identity.TokenId) (*session, bool) {
|
||||
return network.sessionController.get(sessionId)
|
||||
}
|
||||
|
||||
func (network *Network) GetAllSessions() []*session {
|
||||
return network.sessionController.all()
|
||||
}
|
||||
|
||||
func (network *Network) GetMetricsEventController() metrics.EventController {
|
||||
return network.metricsEventController
|
||||
}
|
||||
|
||||
func (network *Network) GetSessionLifeCycleController() SessionLifeCycleController {
|
||||
return network.sessionLifeCycleController
|
||||
}
|
||||
|
||||
func (network *Network) GetTraceEventController() trace.EventController {
|
||||
return network.traceEventController
|
||||
}
|
||||
|
||||
func (network *Network) GetTraceController() trace.Controller {
|
||||
return network.traceController
|
||||
}
|
||||
|
||||
func (network *Network) RouterChanged(r *Router) {
|
||||
network.routerChanged <- r
|
||||
}
|
||||
|
||||
func (network *Network) ConnectedRouter(id string) bool {
|
||||
return network.routerController.has(id)
|
||||
}
|
||||
|
||||
func (network *Network) KnownRouter(id string) (*Router, error) {
|
||||
r, err := network.routerStore.loadOneById(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (network *Network) ConnectRouter(r *Router) {
|
||||
network.routerController.add(r)
|
||||
network.routerChanged <- r
|
||||
|
||||
for _, h := range network.routerPresenceHandlers {
|
||||
h.RouterConnected(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) DisconnectRouter(r *Router) {
|
||||
// 1: remove Links for Router
|
||||
for _, l := range network.linkController.allLinksForRouter(r.Id) {
|
||||
network.linkController.remove(l)
|
||||
network.LinkChanged(l)
|
||||
}
|
||||
// 2: remove Router
|
||||
network.routerController.remove(r)
|
||||
network.routerChanged <- r
|
||||
|
||||
for _, h := range network.routerPresenceHandlers {
|
||||
h.RouterDisconnected(r)
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) LinkConnected(id *identity.TokenId, connected bool) error {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
if l, found := network.linkController.get(id); found {
|
||||
if connected {
|
||||
l.addState(newLinkState(Connected))
|
||||
log.Infof("link [l/%s] connected", id.Token)
|
||||
return nil
|
||||
}
|
||||
l.addState(newLinkState(Failed))
|
||||
log.Infof("link [l/%s] failed", id.Token)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("no such link [l/%s]", id.Token)
|
||||
}
|
||||
|
||||
func (network *Network) LinkChanged(l *Link) {
|
||||
// This is called from Channel.rxer() and thus may not block
|
||||
go func() {
|
||||
network.linkChanged <- l
|
||||
}()
|
||||
}
|
||||
|
||||
func (network *Network) BindService(srcR *Router, token string, serviceId string) error {
|
||||
// 1: Find Service
|
||||
if svc, found := network.serviceController.get(serviceId); found {
|
||||
svc.Egress = srcR.Id
|
||||
svc.EndpointAddress = "hosted:" + token
|
||||
|
||||
return network.serviceController.update(svc)
|
||||
}
|
||||
return errors.New("invalid service")
|
||||
}
|
||||
|
||||
func (network *Network) UnbindService(srcR *Router, token string, serviceId string) error {
|
||||
// 1: Find Service
|
||||
if svc, found := network.serviceController.get(serviceId); found {
|
||||
svc.Egress = network.nodeId.Token // TODO: can't set this to null, so setting it to the controller ID
|
||||
svc.EndpointAddress = "hosted:unbound"
|
||||
|
||||
return network.serviceController.update(svc)
|
||||
}
|
||||
return errors.New("invalid service")
|
||||
}
|
||||
|
||||
func (network *Network) CreateSession(srcR *Router, clientId *identity.TokenId, serviceId string) (*session, error) {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
// 1: Find Service
|
||||
if svc, found := network.serviceController.get(serviceId); found {
|
||||
// 2: Allocate Session Identifier
|
||||
sessionIdHash, err := network.sequence.NextHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionId := &identity.TokenId{Token: sessionIdHash}
|
||||
|
||||
// 3: Get Egress Router
|
||||
if er, found := network.routerController.get(svc.Egress); found {
|
||||
// 4: Create Circuit
|
||||
circuit, err := network.CreateCircuit(srcR, er)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
circuit.Binding = "transport"
|
||||
if svc.Binding != "" {
|
||||
circuit.Binding = svc.Binding
|
||||
} else if strings.HasPrefix(svc.EndpointAddress, "hosted") {
|
||||
circuit.Binding = "edge"
|
||||
} else if strings.HasPrefix(svc.EndpointAddress, "udp") {
|
||||
circuit.Binding = "udp"
|
||||
}
|
||||
|
||||
// 4a: Create Route Messages
|
||||
rms, err := circuit.CreateRouteMessages(sessionId, svc.EndpointAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5: Route Egress
|
||||
err = sendRoute(circuit.Path[len(circuit.Path)-1], rms[len(rms)-1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 6: Create Intermediate Routes
|
||||
for i := 0; i < len(circuit.Path)-1; i++ {
|
||||
err = sendRoute(circuit.Path[i], rms[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 7: Create Session Object
|
||||
ss := &session{
|
||||
Id: sessionId,
|
||||
ClientId: clientId,
|
||||
Service: svc,
|
||||
Circuit: circuit,
|
||||
}
|
||||
network.sessionController.add(ss)
|
||||
network.sessionLifeCycleController.SessionCreated(ss.Id, ss.ClientId, ss.Service.Id, ss.Circuit)
|
||||
|
||||
log.Infof("created session [s/%s] ==> %s", sessionId.Token, ss.Circuit)
|
||||
|
||||
return ss, nil
|
||||
|
||||
}
|
||||
return nil, errors.New("missing egress")
|
||||
}
|
||||
return nil, errors.New("invalid service")
|
||||
}
|
||||
|
||||
func (network *Network) RemoveSession(sessionId *identity.TokenId, now bool) error {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
if ss, found := network.sessionController.get(sessionId); found {
|
||||
for _, r := range ss.Circuit.Path {
|
||||
err := sendUnroute(r, ss.Id, now)
|
||||
if err != nil {
|
||||
log.Errorf("error sending unroute to [r/%s] (%s)", r.Id, err)
|
||||
}
|
||||
}
|
||||
network.sessionController.remove(ss)
|
||||
network.sessionLifeCycleController.SessionDeleted(sessionId)
|
||||
|
||||
log.Infof("removed session [s/%s]", ss.Id.Token)
|
||||
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid session (%s)", sessionId.Token)
|
||||
}
|
||||
|
||||
func (network *Network) StartSessionEgress(sessionId *identity.TokenId) error {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
if ss, found := network.sessionController.get(sessionId); found {
|
||||
terminatingRouter := ss.Circuit.Path[len(ss.Circuit.Path)-1]
|
||||
log.Infof("started session egress [s/%s]", ss.Id.Token)
|
||||
return sendStartXgress(terminatingRouter, sessionId)
|
||||
}
|
||||
return fmt.Errorf("invalid session (%s)", sessionId.Token)
|
||||
}
|
||||
|
||||
func (network *Network) CreateCircuit(srcR, dstR *Router) (*Circuit, error) {
|
||||
ingressId, err := network.sequence.NextHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
egressId, err := network.sequence.NextHash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
circuit := &Circuit{
|
||||
Links: make([]*Link, 0),
|
||||
IngressId: ingressId,
|
||||
EgressId: egressId,
|
||||
Path: make([]*Router, 0),
|
||||
}
|
||||
circuit.Path = append(circuit.Path, srcR)
|
||||
circuit.Path = append(circuit.Path, dstR)
|
||||
|
||||
return network.UpdateCircuit(circuit)
|
||||
}
|
||||
|
||||
func (network *Network) UpdateCircuit(circuit *Circuit) (*Circuit, error) {
|
||||
srcR := circuit.Path[0]
|
||||
dstR := circuit.Path[len(circuit.Path)-1]
|
||||
path, err := network.shortestPath(srcR, dstR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
circuit2 := &Circuit{
|
||||
Path: path,
|
||||
Binding: circuit.Binding,
|
||||
IngressId: circuit.IngressId,
|
||||
EgressId: circuit.EgressId,
|
||||
}
|
||||
|
||||
if len(path) > 1 {
|
||||
for i := 0; i < len(path)-1; i++ {
|
||||
if link, found := network.linkController.leastExpensiveLink(path[i], path[i+1]); found {
|
||||
circuit2.Links = append(circuit2.Links, link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return circuit2, nil
|
||||
}
|
||||
|
||||
func (network *Network) AddRouterPresenceHandler(h RouterPresenceHandler) {
|
||||
network.routerPresenceHandlers = append(network.routerPresenceHandlers, h)
|
||||
}
|
||||
|
||||
func (network *Network) Debug() string {
|
||||
return "oh, wow"
|
||||
}
|
||||
|
||||
func (network *Network) Run() {
|
||||
log := pfxlog.Logger()
|
||||
defer log.Error("exited")
|
||||
log.Info("started")
|
||||
|
||||
for {
|
||||
select {
|
||||
case r := <-network.routerChanged:
|
||||
log.Infof("changed router [r/%s]", r.Id)
|
||||
network.assemble()
|
||||
network.clean()
|
||||
|
||||
case l := <-network.linkChanged:
|
||||
log.Infof("changed link [l/%s]", l.Id.Token)
|
||||
if err := network.rerouteLink(l); err != nil {
|
||||
log.Errorf("unexpected error rerouting link (%s)", err)
|
||||
}
|
||||
|
||||
case <-time.After(time.Duration(network.options.CycleSeconds) * time.Second):
|
||||
network.assemble()
|
||||
network.clean()
|
||||
network.smart()
|
||||
case _, ok := <-network.shutdownChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) Shutdown() {
|
||||
if network.isShutdown.CompareAndSwap(false, true) {
|
||||
close(network.shutdownChan)
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) AddCapability(capability string) {
|
||||
network.lock.Lock()
|
||||
defer network.lock.Unlock()
|
||||
network.capabilities = append(network.capabilities, capability)
|
||||
}
|
||||
|
||||
func (network *Network) GetCapabilities() []string {
|
||||
network.lock.Lock()
|
||||
defer network.lock.Unlock()
|
||||
return network.capabilities
|
||||
}
|
||||
|
||||
func (network *Network) rerouteLink(l *Link) error {
|
||||
log := pfxlog.Logger()
|
||||
log.Infof("link [l/%s] changed", l.Id.Token)
|
||||
|
||||
sessions := network.sessionController.all()
|
||||
for _, s := range sessions {
|
||||
if s.Circuit.usesLink(l) {
|
||||
log.Infof("session [s/%s] uses link [l/%s]", s.Id.Token, l.Id.Token)
|
||||
if err := network.rerouteSession(s); err != nil {
|
||||
log.Errorf("error rerouting session [s/%s], removing", s.Id.Token)
|
||||
if err := network.RemoveSession(s.Id, true); err != nil {
|
||||
log.Errorf("error removing session [s/%s] (%s)", s.Id.Token, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (network *Network) rerouteSession(s *session) error {
|
||||
log := pfxlog.Logger()
|
||||
log.Warnf("rerouting [s/%s]", s.Id.Token)
|
||||
|
||||
if cq, err := network.UpdateCircuit(s.Circuit); err == nil {
|
||||
s.Circuit = cq
|
||||
|
||||
rms, err := cq.CreateRouteMessages(s.Id, s.Service.EndpointAddress)
|
||||
if err != nil {
|
||||
log.Errorf("error creating route messages (%s)", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(cq.Path); i++ {
|
||||
if err := sendRoute(cq.Path[i], rms[i]); err != nil {
|
||||
log.Errorf("error sending route to [r/%s] (%s)", cq.Path[i].Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("rerouted session [s/%s]", s.Id.Token)
|
||||
|
||||
network.sessionLifeCycleController.CircuitUpdated(s.Id, s.Circuit)
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) smartReroute(s *session, cq *Circuit) error {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
s.Circuit = cq
|
||||
|
||||
rms, err := cq.CreateRouteMessages(s.Id, s.Service.EndpointAddress)
|
||||
if err != nil {
|
||||
log.Errorf("error creating route messages (%s)", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(cq.Path); i++ {
|
||||
if err := sendRoute(cq.Path[i], rms[i]); err != nil {
|
||||
log.Errorf("error sending route to [r/%s] (%s)", cq.Path[i].Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("rerouted session [s/%s]", s.Id.Token)
|
||||
|
||||
network.sessionLifeCycleController.CircuitUpdated(s.Id, s.Circuit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (network *Network) AcceptMetrics(metrics *ctrl_pb.MetricsMessage) {
|
||||
log := pfxlog.Logger()
|
||||
|
||||
router, err := network.routerStore.loadOneById(metrics.SourceId)
|
||||
if err != nil {
|
||||
log.Warnf("could not find router [r/%s] while processing metrics", metrics.SourceId)
|
||||
return
|
||||
}
|
||||
|
||||
for _, link := range network.GetAllLinksForRouter(router.Id) {
|
||||
metricId := "link." + link.Id.Token + ".latency"
|
||||
if latency, ok := metrics.Histograms[metricId]; ok {
|
||||
if link.Src.Id == router.Id {
|
||||
link.SrcLatency = int64(latency.Mean)
|
||||
} else if link.Dst.Id == router.Id {
|
||||
link.DstLatency = int64(latency.Mean)
|
||||
} else {
|
||||
log.Warnf("link not for router (wtf?)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendRoute(r *Router, createMsg *ctrl_pb.Route) error {
|
||||
pfxlog.Logger().Debugf("sending create route message to [r/%s] for [s/%s]", r.Id, createMsg.SessionId)
|
||||
|
||||
body, err := proto.Marshal(createMsg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := channel2.NewMessage(int32(ctrl_pb.ContentType_RouteType), body)
|
||||
waitCh, err := r.Control.SendAndWait(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
select {
|
||||
case msg := <-waitCh:
|
||||
if msg.ContentType == channel2.ContentTypeResultType {
|
||||
result := channel2.UnmarshalResult(msg)
|
||||
|
||||
if !result.Success {
|
||||
return errors.New(result.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unexpected response type %v received in reply to route request", msg.ContentType)
|
||||
|
||||
case <-time.After(10 * time.Second):
|
||||
pfxlog.Logger().Errorf("timed out waiting for response to route message from [r/%s] for [s/%s]", r.Id, createMsg.SessionId)
|
||||
return errors.New("timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func sendUnroute(r *Router, sessionId *identity.TokenId, now bool) error {
|
||||
remove := &ctrl_pb.Unroute{
|
||||
SessionId: sessionId.Token,
|
||||
Now: now,
|
||||
}
|
||||
body, err := proto.Marshal(remove)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
removeMsg := channel2.NewMessage(int32(ctrl_pb.ContentType_UnrouteType), body)
|
||||
if err := r.Control.Send(removeMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendStartXgress(r *Router, sessionId *identity.TokenId) error {
|
||||
msg := channel2.NewMessage(int32(ctrl_pb.ContentType_StartXgressType), []byte(sessionId.Token))
|
||||
if err := r.Control.Send(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (network *Network) showOptions() {
|
||||
if jsonOptions, err := json.MarshalIndent(network.options, "", " "); err == nil {
|
||||
pfxlog.Logger().Infof("network = %s", string(jsonOptions))
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (network *Network) GetServiceCache() Cache {
|
||||
return network.serviceController
|
||||
}
|
||||
|
||||
type Cache interface {
|
||||
RemoveFromCache(id string)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
CycleSeconds uint32
|
||||
Smart struct {
|
||||
RerouteFraction float32
|
||||
RerouteCap uint32
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultOptions() *Options {
|
||||
options := &Options{
|
||||
CycleSeconds: 15,
|
||||
}
|
||||
options.Smart.RerouteFraction = 0.02
|
||||
options.Smart.RerouteCap = 4
|
||||
return options
|
||||
}
|
||||
|
||||
func LoadOptions(src map[interface{}]interface{}) (*Options, error) {
|
||||
options := DefaultOptions()
|
||||
|
||||
if value, found := src["cycleSeconds"]; found {
|
||||
if cycleSeconds, ok := value.(int); ok {
|
||||
options.CycleSeconds = uint32(cycleSeconds)
|
||||
} else {
|
||||
return nil, errors.New("invalid value for 'cycleSeconds'")
|
||||
}
|
||||
}
|
||||
|
||||
if value, found := src["smart"]; found {
|
||||
if submap, ok := value.(map[interface{}]interface{}); ok {
|
||||
if value, found := submap["rerouteFraction"]; found {
|
||||
if rerouteFraction, ok := value.(float64); ok {
|
||||
options.Smart.RerouteFraction = float32(rerouteFraction)
|
||||
} else {
|
||||
pfxlog.Logger().Errorf("%p", value)
|
||||
}
|
||||
}
|
||||
|
||||
if value, found := submap["rerouteCap"]; found {
|
||||
if rerouteCap, ok := value.(int); ok {
|
||||
options.Smart.RerouteCap = uint32(rerouteCap)
|
||||
} else {
|
||||
pfxlog.Logger().Errorf("%p", value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pfxlog.Logger().Errorf("invalid or empty 'smart' stanza")
|
||||
}
|
||||
}
|
||||
|
||||
return options, nil
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
)
|
||||
|
||||
func (network *Network) shortestPath(srcR *Router, dstR *Router) ([]*Router, error) {
|
||||
if srcR == nil || dstR == nil {
|
||||
return nil, errors.New("not routable (!srcR||!dstR)")
|
||||
}
|
||||
|
||||
if srcR == dstR {
|
||||
return []*Router{srcR}, nil
|
||||
}
|
||||
|
||||
dist := make(map[*Router]int64)
|
||||
prev := make(map[*Router]*Router)
|
||||
unvisited := make(map[*Router]bool)
|
||||
|
||||
for _, r := range network.routerController.all() {
|
||||
dist[r] = math.MaxInt32
|
||||
unvisited[r] = true
|
||||
}
|
||||
dist[srcR] = 0
|
||||
|
||||
for len(unvisited) > 0 {
|
||||
u := minCost(unvisited, dist)
|
||||
delete(unvisited, u)
|
||||
|
||||
neighbors := network.linkController.connectedNeighborsOfRouter(u)
|
||||
for _, r := range neighbors {
|
||||
if _, found := unvisited[r]; found {
|
||||
cost := int64(r.CostFactor)
|
||||
if l, found := network.linkController.leastExpensiveLink(r, u); found {
|
||||
cost += l.SrcLatency
|
||||
cost += l.DstLatency
|
||||
}
|
||||
|
||||
alt := dist[u] + cost
|
||||
if alt < dist[r] {
|
||||
dist[r] = alt
|
||||
prev[r] = u
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dist: (r2->r1->r0)
|
||||
* r0 = 2 <- r1
|
||||
* r1 = 1 <- r2
|
||||
* r2 = 0 <- nil
|
||||
*/
|
||||
|
||||
routerPath := make([]*Router, 0)
|
||||
p := prev[dstR]
|
||||
for p != nil {
|
||||
routerPath = append([]*Router{p}, routerPath...)
|
||||
p = prev[p]
|
||||
}
|
||||
routerPath = append(routerPath, dstR)
|
||||
|
||||
if routerPath[0] != srcR {
|
||||
return nil, errors.New("not routable (~srcR)")
|
||||
}
|
||||
if routerPath[len(routerPath)-1] != dstR {
|
||||
return nil, errors.New("not routable (~dstR)")
|
||||
}
|
||||
|
||||
return routerPath, nil
|
||||
}
|
||||
|
||||
func minCost(q map[*Router]bool, dist map[*Router]int64) *Router {
|
||||
if dist == nil || len(dist) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
min := int64(math.MaxInt64)
|
||||
var selected *Router
|
||||
for r := range q {
|
||||
d := dist[r]
|
||||
if d <= min {
|
||||
selected = r
|
||||
min = d
|
||||
}
|
||||
}
|
||||
return selected
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
"github.com/netfoundry/ziti-foundation/transport"
|
||||
"github.com/orcaman/concurrent-map"
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
Id string
|
||||
Fingerprint string
|
||||
AdvertisedListener transport.Address
|
||||
Control channel2.Channel
|
||||
CostFactor int
|
||||
}
|
||||
|
||||
func NewRouter(id, fingerprint string) *Router {
|
||||
return &Router{
|
||||
Id: id,
|
||||
Fingerprint: fingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
func newRouter(id string, fingerprint string, advLstnr transport.Address, ctrl channel2.Channel) *Router {
|
||||
return &Router{
|
||||
Id: id,
|
||||
Fingerprint: fingerprint,
|
||||
AdvertisedListener: advLstnr,
|
||||
Control: ctrl,
|
||||
CostFactor: 1,
|
||||
}
|
||||
}
|
||||
|
||||
type routerController struct {
|
||||
connected cmap.ConcurrentMap // map[string]*Router
|
||||
}
|
||||
|
||||
func newRouterController() *routerController {
|
||||
return &routerController{
|
||||
connected: cmap.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *routerController) add(r *Router) {
|
||||
c.connected.Set(r.Id, r)
|
||||
}
|
||||
|
||||
func (c *routerController) has(id string) bool {
|
||||
return c.connected.Has(id)
|
||||
}
|
||||
|
||||
func (c *routerController) get(id string) (*Router, bool) {
|
||||
if t, found := c.connected.Get(id); found {
|
||||
return t.(*Router), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (c *routerController) all() []*Router {
|
||||
routers := make([]*Router, 0)
|
||||
for i := range c.connected.IterBuffered() {
|
||||
routers = append(routers, i.Val.(*Router))
|
||||
}
|
||||
return routers
|
||||
}
|
||||
|
||||
func (c *routerController) count() int {
|
||||
return c.connected.Count()
|
||||
}
|
||||
|
||||
func (c *routerController) remove(r *Router) {
|
||||
c.connected.Remove(r.Id)
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"fmt"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
const (
|
||||
EntityTypeRouters = "routers"
|
||||
FieldFingerprint = "fingerprint"
|
||||
)
|
||||
|
||||
func (router *Router) GetId() string {
|
||||
return router.Id
|
||||
}
|
||||
|
||||
func (router *Router) SetId(id string) {
|
||||
router.Id = id
|
||||
}
|
||||
|
||||
func (router *Router) LoadValues(_ boltz.CrudStore, bucket *boltz.TypedBucket) {
|
||||
router.Fingerprint = bucket.GetStringOrError(FieldFingerprint)
|
||||
}
|
||||
|
||||
func (router *Router) SetValues(ctx *boltz.PersistContext) {
|
||||
ctx.SetString(FieldFingerprint, router.Fingerprint)
|
||||
}
|
||||
|
||||
func (router *Router) GetEntityType() string {
|
||||
return EntityTypeRouters
|
||||
}
|
||||
|
||||
type RouterStore interface {
|
||||
boltz.CrudStore
|
||||
create(router *Router) error
|
||||
update(router *Router) error
|
||||
remove(id string) error
|
||||
all() ([]*Router, error)
|
||||
loadOneById(id string) (*Router, error)
|
||||
LoadOneById(tx *bbolt.Tx, id string) (*Router, error)
|
||||
}
|
||||
|
||||
func NewRouterStore(db boltz.Db) RouterStore {
|
||||
notFoundErrorFactory := func(id string) error {
|
||||
return fmt.Errorf("missing router '%s'", id)
|
||||
}
|
||||
|
||||
store := &routerStoreImpl{
|
||||
db: db,
|
||||
BaseStore: boltz.NewBaseStore(nil, EntityTypeRouters, notFoundErrorFactory, boltz.RootBucket),
|
||||
}
|
||||
store.InitImpl(store)
|
||||
return store
|
||||
}
|
||||
|
||||
type routerStoreImpl struct {
|
||||
db boltz.Db
|
||||
*boltz.BaseStore
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) NewStoreEntity() boltz.BaseEntity {
|
||||
return &Router{}
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) create(router *Router) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.Create(boltz.NewMutateContext(tx), router)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) update(router *Router) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.Update(boltz.NewMutateContext(tx), router, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) remove(id string) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.DeleteById(boltz.NewMutateContext(tx), id)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) loadOneById(id string) (router *Router, err error) {
|
||||
err = store.db.View(func(tx *bbolt.Tx) error {
|
||||
router, err = store.LoadOneById(tx, id)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if router == nil {
|
||||
return nil, fmt.Errorf("missing router '%s'", id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) LoadOneById(tx *bbolt.Tx, id string) (*Router, error) {
|
||||
router := &Router{}
|
||||
if found, err := store.BaseLoadOneById(tx, id, router); !found || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return router, nil
|
||||
}
|
||||
|
||||
func (store *routerStoreImpl) all() ([]*Router, error) {
|
||||
routers := make([]*Router, 0)
|
||||
err := store.db.View(func(tx *bbolt.Tx) error {
|
||||
ids, _, err := store.QueryIds(tx, "true")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, id := range ids {
|
||||
router, err := store.LoadOneById(tx, string(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routers = append(routers, router)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return routers, nil
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-fabric/fabric/controller/db"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/orcaman/concurrent-map"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
Id string
|
||||
Binding string
|
||||
EndpointAddress string
|
||||
Egress string
|
||||
}
|
||||
|
||||
type serviceController struct {
|
||||
cache cmap.ConcurrentMap
|
||||
store ServiceStore
|
||||
}
|
||||
|
||||
func newServiceController(db *db.Db) (*serviceController, error) {
|
||||
return &serviceController{cache: cmap.New(), store: NewServiceStore(db)}, nil
|
||||
}
|
||||
|
||||
func (c *serviceController) create(s *Service) error {
|
||||
err := c.store.create(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.cache.Set(s.Id, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serviceController) update(s *Service) error {
|
||||
err := c.store.update(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.cache.Set(s.Id, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *serviceController) get(id string) (*Service, bool) {
|
||||
if t, found := c.cache.Get(id); found {
|
||||
return t.(*Service), true
|
||||
|
||||
}
|
||||
svc, err := c.store.loadOneById(id)
|
||||
if err != nil {
|
||||
pfxlog.Logger().Errorf("failed loading service (%s)", err)
|
||||
return nil, false
|
||||
}
|
||||
if svc != nil {
|
||||
c.cache.Set(svc.Id, svc)
|
||||
return svc, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (c *serviceController) all() ([]*Service, error) {
|
||||
svcs, err := c.store.all()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svcs, nil
|
||||
}
|
||||
|
||||
func (c *serviceController) remove(id string) error {
|
||||
c.cache.Remove(id)
|
||||
return c.store.remove(id)
|
||||
}
|
||||
|
||||
func (c *serviceController) RemoveFromCache(id string) {
|
||||
c.cache.Remove(id)
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/storage/ast"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"fmt"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
const (
|
||||
EntityTypeServices = "services"
|
||||
FieldServiceBinding = "binding"
|
||||
FieldServiceEndpoint = "endpoint"
|
||||
FieldServiceEgress = "egress"
|
||||
)
|
||||
|
||||
func (service *Service) GetId() string {
|
||||
return service.Id
|
||||
}
|
||||
|
||||
func (service *Service) SetId(id string) {
|
||||
service.Id = id
|
||||
}
|
||||
|
||||
func (service *Service) LoadValues(_ boltz.CrudStore, bucket *boltz.TypedBucket) {
|
||||
service.Binding = bucket.GetStringWithDefault(FieldServiceBinding, "")
|
||||
service.EndpointAddress = bucket.GetStringWithDefault(FieldServiceEndpoint, "")
|
||||
service.Egress = bucket.GetStringWithDefault(FieldServiceEgress, "")
|
||||
}
|
||||
|
||||
func (service *Service) SetValues(ctx *boltz.PersistContext) {
|
||||
ctx.SetString(FieldServiceBinding, service.Binding)
|
||||
ctx.SetString(FieldServiceEndpoint, service.EndpointAddress)
|
||||
ctx.SetString(FieldServiceEgress, service.Egress)
|
||||
}
|
||||
|
||||
func (service *Service) GetEntityType() string {
|
||||
return EntityTypeServices
|
||||
}
|
||||
|
||||
type ServiceStore interface {
|
||||
boltz.CrudStore
|
||||
create(service *Service) error
|
||||
update(svc *Service) error
|
||||
remove(id string) error
|
||||
all() ([]*Service, error)
|
||||
loadOneById(id string) (*Service, error)
|
||||
LoadOneById(tx *bbolt.Tx, id string) (*Service, error)
|
||||
}
|
||||
|
||||
func NewServiceStore(db boltz.Db) ServiceStore {
|
||||
notFoundErrorFactory := func(id string) error {
|
||||
return fmt.Errorf("missing service '%s'", id)
|
||||
}
|
||||
|
||||
store := &serviceStoreImpl{
|
||||
db: db,
|
||||
BaseStore: boltz.NewBaseStore(nil, EntityTypeServices, notFoundErrorFactory, boltz.RootBucket),
|
||||
}
|
||||
store.InitImpl(store)
|
||||
store.AddSymbol(FieldServiceBinding, ast.NodeTypeString)
|
||||
store.AddSymbol(FieldServiceEndpoint, ast.NodeTypeString)
|
||||
store.AddSymbol(FieldServiceEgress, ast.NodeTypeString)
|
||||
return store
|
||||
}
|
||||
|
||||
type serviceStoreImpl struct {
|
||||
db boltz.Db
|
||||
*boltz.BaseStore
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) NewStoreEntity() boltz.BaseEntity {
|
||||
return &Service{}
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) create(service *Service) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.Create(boltz.NewMutateContext(tx), service)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) update(service *Service) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.Update(boltz.NewMutateContext(tx), service, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) remove(id string) error {
|
||||
return store.db.Update(func(tx *bbolt.Tx) error {
|
||||
return store.DeleteById(boltz.NewMutateContext(tx), id)
|
||||
})
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) loadOneById(id string) (service *Service, err error) {
|
||||
err = store.db.View(func(tx *bbolt.Tx) error {
|
||||
service, err = store.LoadOneById(tx, id)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if service == nil {
|
||||
return nil, fmt.Errorf("missing service '%s'", id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) LoadOneById(tx *bbolt.Tx, id string) (*Service, error) {
|
||||
service := &Service{}
|
||||
if found, err := store.BaseLoadOneById(tx, id, service); !found || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func (store *serviceStoreImpl) all() ([]*Service, error) {
|
||||
services := make([]*Service, 0)
|
||||
err := store.db.View(func(tx *bbolt.Tx) error {
|
||||
ids, _, err := store.QueryIds(tx, "true")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, id := range ids {
|
||||
service, err := store.LoadOneById(tx, string(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services = append(services, service)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/orcaman/concurrent-map"
|
||||
)
|
||||
|
||||
type session struct {
|
||||
Id *identity.TokenId
|
||||
ClientId *identity.TokenId
|
||||
Service *Service
|
||||
Circuit *Circuit
|
||||
}
|
||||
|
||||
func (s *session) latency() int64 {
|
||||
var latency int64
|
||||
for _, l := range s.Circuit.Links {
|
||||
latency += l.SrcLatency
|
||||
latency += l.DstLatency
|
||||
}
|
||||
return latency
|
||||
}
|
||||
|
||||
type sessionController struct {
|
||||
sessions cmap.ConcurrentMap // map[string]*Session
|
||||
sessionsByService cmap.ConcurrentMap // map[string]*Sessions
|
||||
}
|
||||
|
||||
func newSessionController() *sessionController {
|
||||
return &sessionController{
|
||||
sessions: cmap.New(),
|
||||
sessionsByService: cmap.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *sessionController) add(sn *session) {
|
||||
c.sessions.Set(sn.Id.Token, sn)
|
||||
|
||||
if !c.sessionsByService.Has(sn.Service.Id) {
|
||||
c.sessionsByService.Set(sn.Service.Id, cmap.New())
|
||||
}
|
||||
t, _ := c.sessionsByService.Get(sn.Service.Id)
|
||||
sessionsForService := t.(cmap.ConcurrentMap)
|
||||
sessionsForService.Set(sn.Id.Token, sn)
|
||||
}
|
||||
|
||||
func (c *sessionController) get(id *identity.TokenId) (*session, bool) {
|
||||
if t, found := c.sessions.Get(id.Token); found {
|
||||
return t.(*session), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (c *sessionController) all() []*session {
|
||||
sessions := make([]*session, 0)
|
||||
for i := range c.sessions.IterBuffered() {
|
||||
sessions = append(sessions, i.Val.(*session))
|
||||
}
|
||||
return sessions
|
||||
}
|
||||
|
||||
func (c *sessionController) remove(sn *session) {
|
||||
c.sessions.Remove(sn.Id.Token)
|
||||
|
||||
if t, found := c.sessionsByService.Get(sn.Service.Id); found {
|
||||
sessionsForService := t.(cmap.ConcurrentMap)
|
||||
sessionsForService.Remove(sn.Id.Token)
|
||||
if sessionsForService.Count() < 1 {
|
||||
c.sessionsByService.Remove(sn.Service.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
)
|
||||
|
||||
type SessionLifeCycleListener interface {
|
||||
SessionCreated(sessionId *identity.TokenId, clientId *identity.TokenId, serviceId string, circuit *Circuit)
|
||||
SessionDeleted(sessionId *identity.TokenId)
|
||||
CircuitUpdated(sessionId *identity.TokenId, circuit *Circuit)
|
||||
}
|
||||
|
||||
// SessionLifeCycleController allows for sending session changes to multiple Listeners
|
||||
type SessionLifeCycleController interface {
|
||||
SessionLifeCycleListener
|
||||
|
||||
// AddListener adds the given listener to the controller
|
||||
AddListener(listener SessionLifeCycleListener)
|
||||
|
||||
// RemoveListener removes the given listener from the controller
|
||||
RemoveListener(listener SessionLifeCycleListener)
|
||||
|
||||
// Shutdown stops the controller
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
// NewSessionLifeCycleController creates a new SessionLifeCycleController instance
|
||||
func NewSessionLifeCyleController() SessionLifeCycleController {
|
||||
controller := &sessionLifeCycleControllerImpl{
|
||||
changeChan: make(chan sessionLifeCycleControllerChange, 1),
|
||||
eventChan: make(chan sessionLifeCycleEvent, 25),
|
||||
listeners: make(map[SessionLifeCycleListener]SessionLifeCycleListener),
|
||||
}
|
||||
|
||||
go controller.run()
|
||||
return controller
|
||||
}
|
||||
|
||||
type sessionLifeCycleControllerImpl struct {
|
||||
changeChan chan sessionLifeCycleControllerChange
|
||||
eventChan chan sessionLifeCycleEvent
|
||||
listeners map[SessionLifeCycleListener]SessionLifeCycleListener
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) SessionCreated(sessionId *identity.TokenId, clientId *identity.TokenId, serviceId string, circuit *Circuit) {
|
||||
event := &sessionCreatedEvent{
|
||||
sessionId: sessionId,
|
||||
clientId: clientId,
|
||||
serviceId: serviceId,
|
||||
circuit: circuit,
|
||||
}
|
||||
controller.eventChan <- event
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) SessionDeleted(sessionId *identity.TokenId) {
|
||||
event := &sessionDeletedEvent{
|
||||
sessionId: sessionId,
|
||||
}
|
||||
controller.eventChan <- event
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) CircuitUpdated(sessionId *identity.TokenId, circuit *Circuit) {
|
||||
event := &sessionCircuitEvent{
|
||||
sessionId: sessionId,
|
||||
circuit: circuit,
|
||||
}
|
||||
controller.eventChan <- event
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) AddListener(listener SessionLifeCycleListener) {
|
||||
controller.changeChan <- sessionLifeCycleControllerChange{listener, sessionLifeCycleControllerAddListener}
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) RemoveListener(listener SessionLifeCycleListener) {
|
||||
controller.changeChan <- sessionLifeCycleControllerChange{listener, sessionLifeCycleControllerRemoveListener}
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) Shutdown() {
|
||||
controller.changeChan <- sessionLifeCycleControllerChange{nil, sessionLifeCycleControllerShutdown}
|
||||
}
|
||||
|
||||
func (controller *sessionLifeCycleControllerImpl) run() {
|
||||
running := true
|
||||
for running {
|
||||
select {
|
||||
case change := <-controller.changeChan:
|
||||
if sessionLifeCycleControllerAddListener == change.changeType {
|
||||
controller.listeners[change.listener] = change.listener
|
||||
} else if sessionLifeCycleControllerRemoveListener == change.changeType {
|
||||
delete(controller.listeners, change.listener)
|
||||
} else if sessionLifeCycleControllerShutdown == change.changeType {
|
||||
running = false
|
||||
}
|
||||
case event := <-controller.eventChan:
|
||||
event.handle(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type sessionLifecycleControllerChangeType uint8
|
||||
|
||||
const (
|
||||
sessionLifeCycleControllerAddListener = iota
|
||||
sessionLifeCycleControllerRemoveListener
|
||||
sessionLifeCycleControllerShutdown
|
||||
)
|
||||
|
||||
type sessionLifeCycleControllerChange struct {
|
||||
listener SessionLifeCycleListener
|
||||
changeType sessionLifecycleControllerChangeType
|
||||
}
|
||||
|
||||
type sessionLifeCycleEvent interface {
|
||||
handle(controller *sessionLifeCycleControllerImpl)
|
||||
}
|
||||
|
||||
type sessionCreatedEvent struct {
|
||||
sessionId *identity.TokenId
|
||||
clientId *identity.TokenId
|
||||
serviceId string
|
||||
circuit *Circuit
|
||||
}
|
||||
|
||||
func (event *sessionCreatedEvent) handle(controller *sessionLifeCycleControllerImpl) {
|
||||
for _, handler := range controller.listeners {
|
||||
go handler.SessionCreated(event.sessionId, event.clientId, event.serviceId, event.circuit)
|
||||
}
|
||||
}
|
||||
|
||||
type sessionDeletedEvent struct {
|
||||
sessionId *identity.TokenId
|
||||
}
|
||||
|
||||
func (event *sessionDeletedEvent) handle(controller *sessionLifeCycleControllerImpl) {
|
||||
for _, handler := range controller.listeners {
|
||||
go handler.SessionDeleted(event.sessionId)
|
||||
}
|
||||
}
|
||||
|
||||
type sessionCircuitEvent struct {
|
||||
sessionId *identity.TokenId
|
||||
circuit *Circuit
|
||||
}
|
||||
|
||||
func (event *sessionCircuitEvent) handle(controller *sessionLifeCycleControllerImpl) {
|
||||
for _, handler := range controller.listeners {
|
||||
go handler.CircuitUpdated(event.sessionId, event.circuit)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/identity/identity"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func (network *Network) smart() {
|
||||
log := pfxlog.Logger()
|
||||
log.Debugf("smart network processing")
|
||||
|
||||
/*
|
||||
* Order sessions in decreasing overall latency order
|
||||
*/
|
||||
sessions := network.GetAllSessions()
|
||||
log.Debugf("observing [%d] sessions", len(sessions))
|
||||
|
||||
sessionLatencies := make(map[*identity.TokenId]int64)
|
||||
var orderedSessions []*identity.TokenId
|
||||
for _, s := range sessions {
|
||||
sessionLatencies[s.Id] = s.latency()
|
||||
orderedSessions = append(orderedSessions, s.Id)
|
||||
}
|
||||
|
||||
sort.SliceStable(orderedSessions, func(i, j int) bool {
|
||||
iId := orderedSessions[i]
|
||||
jId := orderedSessions[j]
|
||||
return sessionLatencies[jId] < sessionLatencies[iId]
|
||||
})
|
||||
/* */
|
||||
|
||||
/*
|
||||
* Develop candidates for rerouting.
|
||||
*/
|
||||
newCircuits := make(map[*session]*Circuit)
|
||||
var candidates []*session
|
||||
count := 0
|
||||
ceiling := int(float32(len(sessions)) * network.options.Smart.RerouteFraction)
|
||||
if ceiling < 1 {
|
||||
ceiling = 1
|
||||
}
|
||||
if ceiling > int(network.options.Smart.RerouteCap) {
|
||||
ceiling = int(network.options.Smart.RerouteCap)
|
||||
}
|
||||
log.Debugf("smart reroute ceiling [%d]", ceiling)
|
||||
for _, sId := range orderedSessions {
|
||||
if session, found := network.GetSession(sId); found {
|
||||
if updatedCircuit, err := network.UpdateCircuit(session.Circuit); err == nil {
|
||||
if !updatedCircuit.EqualPath(session.Circuit) {
|
||||
if count < ceiling {
|
||||
count++
|
||||
candidates = append(candidates, session)
|
||||
newCircuits[session] = updatedCircuit
|
||||
log.Infof("rerouting [s/%s] [l:%d] %s ==> %s", session.Id.Token, sessionLatencies[session.Id], session.Circuit.String(), updatedCircuit.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* */
|
||||
|
||||
/*
|
||||
* Reroute.
|
||||
*/
|
||||
for _, session := range candidates {
|
||||
if err := network.smartReroute(session, newCircuits[session]); err != nil {
|
||||
log.Errorf("error rerouting [s/%s] (%s)", session.Id.Token, err)
|
||||
}
|
||||
}
|
||||
/* */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Copyright 2019 Netfoundry, Inc.
|
||||
|
||||
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
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ctrl_msg
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-foundation/channel2"
|
||||
)
|
||||
|
||||
const (
|
||||
ContentTypeSessionSuccessType = 1001
|
||||
ContentTypeSessionFailedType = 1016
|
||||
|
||||
SessionSuccessAddressHeader = 1100
|
||||
)
|
||||
|
||||
func NewSessionSuccessMsg(sessionId, address string) *channel2.Message {
|
||||
msg := channel2.NewMessage(ContentTypeSessionSuccessType, []byte(sessionId))
|
||||
msg.Headers[SessionSuccessAddressHeader] = []byte(address)
|
||||
return msg
|
||||
}
|
||||
|
||||
func NewSessionFailedMsg(message string) *channel2.Message {
|
||||
return channel2.NewMessage(ContentTypeSessionFailedType, []byte(message))
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Phase 12: Smart Routing 1
|
||||
|
||||
Ziti Fabric 0.4 includes an initial, experimental implementation of "smart routing".
|
||||
|
||||
Smart routing continually measures the latency between established links in the overlay mesh. The latency data is used in these ways:
|
||||
|
||||
1. When establishing a "circuit" ("path" across the mesh) for a new session, the current latency data is used as a component of the overall "cost" of each candidate path. The cost is fed into the shortest path computation, which uses that data to select the least expensive path across the mesh. So, when new sessions are created, they're given the current least expensive path across the mesh.
|
||||
|
||||
2. The controller periodically scans the network, looking for the sessions experiencing the highest amount of latency. A portion of the sessions with the most latency have new paths computed, and if a session's newly-computed path is different then its current path, that session will be dynamically "optimized" onto the new path.
|
||||
|
||||
This is an experimental implementation. It _should_ result in relatively balanced network utilization, along with some amount of the active network sessions experiencing better then average performance. These algorithms need testing and feedback from real world workloads.
|
||||
|
||||
Keep in mind that the "cost" attribute on each link is user-settable (see the `ziti-fabric link set-cost` tool), and will be added to the link cost considered by the controller. By smart utilization of the link cost, you can directly influence the decisions made by the smart routing algorithms.
|
||||
|
||||
Setting the link cost will provoke the controller to immediately re-consider the routes for each of the sessions currently traversing the adjusted link. If better paths are available for those sessions, they will be re-routed.
|
||||
|
||||
## Network Scaling
|
||||
|
||||
This style of smart routing is intended to dovetail with a scaling strategy where additional network capacity (routers) is spun up and made available as the network workload increases. Smart routing will see the new, non-latent capacity and begin redirecting traffic to it, re-balancing the network.
|
||||
|
||||
There are quite a number of different strategies that are possible for selecting locations to site additional mesh capacity. The work around exploring and understanding those strategies needs to be coordinated with the design of the smart routing and network optimization algorithms present in Ziti. The "fablab" project currently exists to create tooling and infrastructure to explore these kinds of scenarios. We also encourage you to experiment.
|
||||
|
||||
As overall network volume decreases, the additional capacity can be removed from the overlay mesh, and smart routing will again optimize the sessions to best take advantage of performance available in the mesh topology.
|
||||
|
||||
## Configuration
|
||||
|
||||
There are a couple of configuration settings for tuning how smart routing behaves on your network:
|
||||
|
||||
network:
|
||||
cycleSeconds: 15
|
||||
smart:
|
||||
rerouteFraction: 0.02
|
||||
rerouteCap: 4
|
||||
|
||||
The above stanza goes into your controller's YAML configuration file.
|
||||
|
||||
The `cycleSeconds` parameter controls how frequently the controller will scan the network, looking for active sessions to be optimized.
|
||||
|
||||
The `rerouteFraction` parameter controls the fraction of the total number of sessions to be considered for optimization. The sessions are scanned in descending order of their overall latency, and the worst `rerouteFraction` will be considered.
|
||||
|
||||
The `rerouteCap` parameter defines the upper limit on the total number of sessions to be considered for optimization, even if `rerouteFraction` would select more sessions. This allows an overall cap to set on the number of sessions to be optimized.
|
||||
|
||||
By tuning the controller scan cycle rate (`cycleSeconds`), you can control how frequently your network will be optimized. This is the primary configuration control, which determines how quickly the smart routing algorithms will respond to changing network weather. This performance will need to be balanced against controller CPU burn, and the additional control plane bandwidth required to implement the changing session routing.
|
||||
|
||||
The current implementation is missing a configuration setting, which determines how frequently latency probes are performed on the overlay mesh links. Latency probes are currently performed on 10 second intervals. There probably is not much point in reducing `network.cycleSeconds` below `10`, until the latency probe interval can be configured. We expect this, along with other additional configuation settings, will be available very soon.
|
||||
|
||||
## What's Next?
|
||||
|
||||
Research for the next version of these algorithms is currently underway. We expect the next iteration to include cost considerations and targets around bandwidth metrics.
|
||||
|
||||
We would love your feedback. Please let us know how our current smart routing implementation performs on your real world workloads. If you have ideas for additional capabilities, please let us know!
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
v: 2
|
||||
|
||||
identity:
|
||||
cert: fabric/etc/ca/intermediate/certs/001-client.cert.pem
|
||||
server_cert: fabric/etc/ca/intermediate/certs/001-server.cert.pem
|
||||
key: fabric/etc/ca/intermediate/private/001.key.pem
|
||||
ca: fabric/etc/ca/intermediate/certs/ca-chain.cert.pem
|
||||
|
||||
# Configure the forwarder options
|
||||
#
|
||||
forwarder:
|
||||
# How frequently does the forwarder probe the link latency. This will ultimately determine the resolution of the
|
||||
# responsiveness available to smart routing. This resolution comes at the expense of bandwidth utilization for the
|
||||
# probes, control plane utilization, and CPU utilization processing the results.
|
||||
#
|
||||
latencyProbeInterval: 1000
|
||||
|
||||
#trace:
|
||||
# path: 001.trace
|
||||
|
||||
#profile:
|
||||
# memory:
|
||||
# path: 001.memprof
|
||||
# cpu:
|
||||
# path: 001.cpuprof
|
||||
|
||||
ctrl:
|
||||
endpoint: tls:127.0.0.1:6262
|
||||
|
||||
listeners:
|
||||
- binding: proxy
|
||||
address: tcp:0.0.0.0:1122
|
||||
service: ssh
|
||||
|
||||
- binding: proxy
|
||||
address: tcp:0.0.0.0:10001
|
||||
service: mgmt
|
||||
|
||||
- binding: transport
|
||||
address: tls:0.0.0.0:7001
|
||||
options:
|
||||
retransmission: true
|
||||
randomDrops: true
|
||||
drop1InN: 5000
|
||||
|
||||
- binding: udp
|
||||
address: udp:0.0.0.0:7002
|
||||
options:
|
||||
retransmission: true
|
||||
randomDrops: true
|
||||
drop1InN: 5000
|
||||
|
||||
# xctrl_example
|
||||
#
|
||||
#example:
|
||||
# delay: 1
|
||||
@@ -0,0 +1,21 @@
|
||||
v: 2
|
||||
|
||||
identity:
|
||||
cert: fabric/etc/ca/intermediate/certs/002-client.cert.pem
|
||||
server_cert: fabric/etc/ca/intermediate/certs/002-server.cert.pem
|
||||
key: fabric/etc/ca/intermediate/private/002.key.pem
|
||||
ca: fabric/etc/ca/intermediate/certs/ca-chain.cert.pem
|
||||
|
||||
#trace:
|
||||
# path: 002.trace
|
||||
|
||||
ctrl:
|
||||
endpoint: tls:127.0.0.1:6262
|
||||
|
||||
link:
|
||||
listener: quic:127.0.0.1:6002
|
||||
|
||||
listeners:
|
||||
- binding: transport
|
||||
address: tls:0.0.0.0:7002 # make sure we don't conflict with router 001
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
v: 2
|
||||
|
||||
identity:
|
||||
cert: fabric/etc/ca/intermediate/certs/003-client.cert.pem
|
||||
server_cert: fabric/etc/ca/intermediate/certs/003-server.cert.pem
|
||||
key: fabric/etc/ca/intermediate/private/003.key.pem
|
||||
ca: fabric/etc/ca/intermediate/certs/ca-chain.cert.pem
|
||||
|
||||
# Configure the forwarder options
|
||||
#
|
||||
forwarder:
|
||||
# How frequently does the forwarder probe the link latency. This will ultimately determine the resolution of the
|
||||
# responsiveness available to smart routing. This resolution comes at the expense of bandwidth utilization for the
|
||||
# probes, control plane utilization, and CPU utilization processing the results.
|
||||
#
|
||||
latencyProbeInterval: 1000
|
||||
|
||||
#trace:
|
||||
# path: 003.trace
|
||||
|
||||
#profile:
|
||||
# memory:
|
||||
# path: 003.memprof
|
||||
# intervalMs: 5000
|
||||
|
||||
ctrl:
|
||||
endpoint: tls:127.0.0.1:6262
|
||||
|
||||
dialers:
|
||||
- binding: transport
|
||||
options:
|
||||
retransmission: true
|
||||
randomDrops: false
|
||||
drop1InN: 5000
|
||||
@@ -0,0 +1,25 @@
|
||||
v: 2
|
||||
|
||||
identity:
|
||||
cert: fabric/etc/ca/intermediate/certs/004-client.cert.pem
|
||||
server_cert: fabric/etc/ca/intermediate/certs/004-server.cert.pem
|
||||
key: fabric/etc/ca/intermediate/private/004.key.pem
|
||||
ca: fabric/etc/ca/intermediate/certs/ca-chain.cert.pem
|
||||
|
||||
# Configure the forwarder options
|
||||
#
|
||||
forwarder:
|
||||
# How frequently does the forwarder probe the link latency. This will ultimately determine the resolution of the
|
||||
# responsiveness available to smart routing. This resolution comes at the expense of bandwidth utilization for the
|
||||
# probes, control plane utilization, and CPU utilization processing the results.
|
||||
#
|
||||
latencyProbeInterval: 1000
|
||||
|
||||
#trace:
|
||||
# path: 004.trace
|
||||
|
||||
ctrl:
|
||||
endpoint: tls:127.0.0.1:6262
|
||||
|
||||
link:
|
||||
listener: quic:127.0.0.1:6004
|
||||
@@ -0,0 +1,35 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGFjCCA/6gAwIBAgIJAOq4qnKYsnlbMA0GCSqGSIb3DQEBCwUAMIGXMQswCQYD
|
||||
VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEjAQBgNVBAcMCUNoYXJs
|
||||
b3R0ZTETMBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UECwwgTmV0Rm91bmRyeSBD
|
||||
ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMEk5ldEZvdW5kcnkgUm9vdCBD
|
||||
QTAeFw0xODA1MTgxNjU0NDdaFw0zODA1MTMxNjU0NDdaMIGXMQswCQYDVQQGEwJV
|
||||
UzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEjAQBgNVBAcMCUNoYXJsb3R0ZTET
|
||||
MBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZp
|
||||
Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMEk5ldEZvdW5kcnkgUm9vdCBDQTCCAiIw
|
||||
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMqr9dr7vj0KvdYkZgMMgS00ohGd
|
||||
MVzpN6JFKb87uEbb7U2uH905uNkm4OOyilY/w0UD8PCU3ISmFgoB5LAcOa77icV3
|
||||
qJ+h4MTaVirps2EtyA34DcyU3k+Fvauc7fZhhnAdcZai/6O13aBorR9awfwJDGfq
|
||||
fa/uq88xN5gU/yniOpNnDZu9lbD4sxhMULLnjUMWpAtBqwyDXSZdEBVc7s5r3L4P
|
||||
Wt7XMurjBLq7wi0mgrN+a9mQy8P3QL+1Di7SIlovsYHZIT0w48N4ZW+mehIAiRJW
|
||||
a9ENQCPbH0+66TKTOgvU4BbNzkKD7kvFGYt6NUTs+89wdpO01qDa1EPDa9sx4Uo3
|
||||
w29AfVBhxo9Zl7hWX1voMC5NoflE33X0f8X5kfKNnJtU/ALXiV+Wd4grI3LwkRX9
|
||||
gwhsQANae6J53MN6GTY6mf7T71mvZf/F+MKjyJYcVs1pWdBfvB1Fo6jvzeUSi6dy
|
||||
p7joUMEsGnIC4ModCkhPcwryuQL/XIE3Gwfji8zB5Rm4rS7s8L0oe2alB+5+VgZ/
|
||||
EDfiRjpZTePPJAd62gtiOjFOo0QSO4anDLajWPtFoIEQUhtiWeVuGkRYVNpB/3rP
|
||||
YZDqbVTfLsnIN+UdK70WjUk2QbepeyMPB1r/pbs1ElGB0WuGc7CubsXov1fg/Uef
|
||||
NT9UkvrovA+aIdWNAgMBAAGjYzBhMB0GA1UdDgQWBBRB8+kUbjrl49psAMznlIp3
|
||||
1nor6TAfBgNVHSMEGDAWgBRB8+kUbjrl49psAMznlIp31nor6TAPBgNVHRMBAf8E
|
||||
BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAJ9TvhopZ
|
||||
E5rGe57y1lvk8WQRucNFxGspdGGem0DS+uAHjJ2djFf2EQFkPyjo8HLet7C+XmZ5
|
||||
I4ETrPJvgkPzSUd3MdJUUjBvOw054SMKyW/88D/dj4nsMK3qA80wN5i4Syx2p5KI
|
||||
yhjPaCe96fh+VIwqBMAl3f9KlWuffkfNeJT0ySYVWk8QydNy06PD4mdwKQbn4P03
|
||||
Xh3G2Bn+1R9sf4ZR+HIZXFF0+tfkpCoDJqkx8Roxddrwo2zs8b6wOJJYj5KD2NQa
|
||||
3GCR8p1U20Vb5AxfLLt5PeJc8D7WvaEUCGB8hoa0ElSHE8cyEq2NsCABf7r7YPcY
|
||||
BtoPX6VxAeEqvLeHKBDc5fv0UlbrPI9LS2JX8t+i8epf/fH2rk9NUE7AQ5Lb8sJz
|
||||
hHYztL4cg9/h5In6cfi4Ih0njZYKuiv+ZGy4vuB4KSyLvQYe4LKc/jKpAWzO79S1
|
||||
sESw3yWhOcuk4ifFoYHVjxQ+bXhvYujX/ceSgxWHT9RocnROadnWvuZ8aF9HIBlh
|
||||
F29PWwH4RvhvkDbMRmqxNz0jAU6GcjhmKU+hnmzbF6OqtXDcZK+i8SF2mutCa/G6
|
||||
H5VDbfL/7/jP1vbFbIO7bNW94HjCGo97auSDEmsSXgZ8uTYNb503qPzdmXiU+hRl
|
||||
jDOQLqtoJofIWUChpNurPQfqu9UljEk9LpQ=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1 @@
|
||||
V 280515165723Z 1000 unknown /C=US/ST=North Carolina/O=NetFoundry/OU=NetFoundry Certificate Authority/CN=NetFoundry Intermediate CA
|
||||
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtzCCAp+gAwIBAgICEA0wDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5Mjg0MFoX
|
||||
DTI4MDgxMDE5Mjg0MFowczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDEwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDbqcpLyr/yZFw2YxOy1RKhO/jw4ra8Z15KdEHN
|
||||
bz5hcNlT6dmVFQj4sBW9AsB06ynqzrO5cKjnWF/LZXzTRGlDUmxmKZOZCcb4NVy/
|
||||
4fwWNN8IBuJQBrrz1qTMBJaG4DRbZ+zTICrb2EJGJyNFZbNKvlRQzn4xMjMm57Up
|
||||
v2enImy8BHUWahjkcCG/uXPTJzjupTweRI34DPxTU2q3hH7zwocdFMe/mkzShMb1
|
||||
qwj33BByHWzSK60NawE140li24v3ELLhre/C6cZSV1Nyk4U9jreSeaQ/uj5cmk08
|
||||
dPnCeBcTqMIwhAOihMYM3vqhOZbNfssr7gXd0/8bv/7P6JGpAgMBAAGjPDA6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcEfwAA
|
||||
AYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAgEAmPpB0t/nGnpJ8zS01256g0P1UjwI
|
||||
GOj8DF4XhQVChDk+9VYEg1DIvku52m1F7Wxgp8q2ELTEjnywZrK/VD4sos0cWuID
|
||||
f4DYsUqdM8gGHc5uVY/eubWtcWAo7qegrfdq+S6MD8DqdiCnBTe5xruWBaZhm9aP
|
||||
lwPpVSqDVTGyjV9wLB/mNc0xOEYg0fenS0UbHZAlDWHHCZQmkMnW1bU07qxKfu0i
|
||||
/1Ok0H0w/kEIxv6LuSSxPJQ9yvy9eB+2HypdeQl4kuZzue/tXrLn20MhWHPaJZjr
|
||||
BUDcLYg7Badd2lyySh4T5eSY1XyEPogHCx8XMWRixjkaWgdZpriVgf1g7wXc6W6G
|
||||
fD9pxQyQ1pq3zL9rbWWzyrmp4gwOsAOq1HwmGJtHI9qVU3VxSrbZCF9bnYTRdIpS
|
||||
UNWMqOv5uuYspKzcYl2FFdGUd3QQ5ExSsFRZ2+xjfDyhlPOOuJtb3RK3HoY35Gjg
|
||||
DWB3mU331H+UtCE8oCs5nKQcS0iH86D+CnqJkkvQHSVH+QV4JU202x+Ym0q3aaqy
|
||||
AuE5Nj5ybnrN/WsL3YYkpbIYZAvGWnvHGYOLjs7caLBwv2vcfibAsPX4m+OhJfuU
|
||||
0zCzTCS6fzf/Jg9R1p7392CESYfJ34eVuda7ctWZrMXFyGsxeydCO2TTdDjRolO/
|
||||
tToiRRetrmH3JcY=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvjCCAqagAwIBAgICEAkwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjcyNVoX
|
||||
DTI4MDgxMDE5MjcyNVowejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDEtc2VydmVyMIIBIjAN
|
||||
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA26nKS8q/8mRcNmMTstUSoTv48OK2
|
||||
vGdeSnRBzW8+YXDZU+nZlRUI+LAVvQLAdOsp6s6zuXCo51hfy2V800RpQ1JsZimT
|
||||
mQnG+DVcv+H8FjTfCAbiUAa689akzASWhuA0W2fs0yAq29hCRicjRWWzSr5UUM5+
|
||||
MTIzJue1Kb9npyJsvAR1FmoY5HAhv7lz0yc47qU8HkSN+Az8U1Nqt4R+88KHHRTH
|
||||
v5pM0oTG9asI99wQch1s0iutDWsBNeNJYtuL9xCy4a3vwunGUldTcpOFPY63knmk
|
||||
P7o+XJpNPHT5wngXE6jCMIQDooTGDN76oTmWzX7LK+4F3dP/G7/+z+iRqQIDAQAB
|
||||
ozwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhv
|
||||
c3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAInGp9pJYVCUJErrsart
|
||||
M5vtK/Mm2qBpbpcdj8Gnokh3ubL5rY0MjpOz5AWj0c4wFgV28EdAncjXEor4VOEI
|
||||
JgsbTm3STNJnA9BT7vAwNezbl1N6jOTh8vUrjaSx5AsWVbah6nZX8rfc9db/m+zd
|
||||
iYedN0VJF9Fi6wrK2CssDkbYc6PNrK/lhgyWAcacQdthZTWmqmObNToAY1FNk6m0
|
||||
OHXW0ipuRFqNRUw6snU9+SqbcOnCqKtpAan+YfNj8cXuiytjxGfQVpQVsp9zdXqX
|
||||
efkc13iKcJ46GLkWcWrjWKkVt3EjUbaWENECmz4/Nd1LgzmEaTwVUCxtAlVnKk7P
|
||||
oW5dgJQpWk5chP0XidyvwiKf2iC/fck+drj7f+iJDd26pZ1LFvlA7MO9eYu5HpWQ
|
||||
tL4dF2MnubU98Hg3m/ryygLZh7I2rvPsx8/g1m8LYhiJ4QFkXKdZ8IQ1daqUtUmr
|
||||
ooH++0C6r9fNgyEbhGMungcC5DHP58CofDJuoUyYhUyNpQgq/XWKx23epQiOgnJm
|
||||
rb3AB8X3TE40LneNfKdS+BNq4q2s/GYrI0BfmZ1BXjH0YgR0iLv1PZl+0L7++RHO
|
||||
wE6kjuIs64UCkzIzaNByVUuAVRRqZUV0j6U07ONovqhPSNwky4h8VBaTLHWOfK4Q
|
||||
k0H8p9E549WS07pfmKIgoKvh
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtzCCAp+gAwIBAgICEA4wDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjkwM1oX
|
||||
DTI4MDgxMDE5MjkwM1owczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDIwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQDGfv6XkzO866Bi+rVZNGHtOjxXZE0HW5rwaxVQ
|
||||
3zMtk/8Elrlyr6ZuguObyUfLJdnScvirjaGbUqm6XTL7H9yRUKBshQZDtaci6XRm
|
||||
4gq21X7pQ0f1oUmsW5q+dDqbJ8JJ+HbEhbPH7MmZfsTLIASWMKK/pEzTf9t98fyN
|
||||
4LJO/Yr++PmE7ZEz+YRwGphSupWEatLlfRh7XviihxKcXTiH8Z/qD8A6W8lngu2d
|
||||
HFU7VXiBITPwvx/GeanahwduqpnZJNWaCAA7h0MCCatJ01ITGGPgsBCfJWyezBw8
|
||||
CAyLWYL/dlauaq1q5Xg/Bp8V6HddEy20QypRxdY/kPobAcVPAgMBAAGjPDA6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcEfwAA
|
||||
AYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAgEAAA9Str4WlbxQaKuzZ38glD9jjkCE
|
||||
tA9jwCJnNv5uh1o4z4RFLPK4s9EsY28g13LRKTm5ft0ndO4ofTb0xUDH9ddeTjsY
|
||||
QtXrzrh79MzH9IIIyej8YubRqeVeQdR0a0RoG4IACziaA3hrZlIDbM7xxrXKYVzC
|
||||
dvV7epVT1bO4TrIf96/JwHBBtbWBi+GedOtPgAxlFQ99nvlPEeKIEmp9kv111Ot/
|
||||
WpawpVE6EALDFAS7rT3zU2t/9qHtWb6i6QMGdJ/WKsHVOOMRMhR86tYKxYz1M4Ux
|
||||
NI/2GQCdYSmbmzAdKKWWrrTCMal6MjhPjWnFyjXUgUkSuIyfJ8U5MQ/0hI8BF3K5
|
||||
SqH96WVoKGud0ohPC2bjdZ8XqRHvBU6nhJ5pnNA8YjMevombwMWOAVpYjfnCJK39
|
||||
hODeOiwdDm0AWDJ18wcAnyJH+aX6L50y2BWhE2Gc90P2kqA6YgRCAy2rwBRvDNua
|
||||
yPGSyHJfNbyQ8e6tVbWDEkIQkP1A0uDD3SxoWNcxOeAmtQV6Ig779pxZ+GqHKR57
|
||||
bJ5wJjFJsPRgHz/ViP11IMffldb+6tvMKR4iVZO2eZ9GPqIwxXF154pKR2lL+mvV
|
||||
3I9kBfkYLd4Z61hTmCAJpZaIlVTGsjLAU2W56m/OOI8piaZ/UUMMrFiVtKuFp6kF
|
||||
OcrllxHkVaVgFbA=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvjCCAqagAwIBAgICEAowDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjczNloX
|
||||
DTI4MDgxMDE5MjczNlowejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDItc2VydmVyMIIBIjAN
|
||||
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxn7+l5MzvOugYvq1WTRh7To8V2RN
|
||||
B1ua8GsVUN8zLZP/BJa5cq+mboLjm8lHyyXZ0nL4q42hm1Kpul0y+x/ckVCgbIUG
|
||||
Q7WnIul0ZuIKttV+6UNH9aFJrFuavnQ6myfCSfh2xIWzx+zJmX7EyyAEljCiv6RM
|
||||
03/bffH8jeCyTv2K/vj5hO2RM/mEcBqYUrqVhGrS5X0Ye174oocSnF04h/Gf6g/A
|
||||
OlvJZ4LtnRxVO1V4gSEz8L8fxnmp2ocHbqqZ2STVmggAO4dDAgmrSdNSExhj4LAQ
|
||||
nyVsnswcPAgMi1mC/3ZWrmqtauV4PwafFeh3XRMttEMqUcXWP5D6GwHFTwIDAQAB
|
||||
ozwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhv
|
||||
c3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAKoioClffib8U2RlOXTD
|
||||
oPc5FWW6pPQoYP8Acy67G96Pacudy7wLWO7TI1s5KQyceyz5ZNmITtfXMgxJbCJv
|
||||
Gd36fikb2iqlfMM89JWz17M5wTpZ83DRNLqDEL5NkEy6DZmnMd/w/saRvc2ZYsul
|
||||
CaNsK9xQBgwesYMC80stTzpiw8p1sDh/JDjMDq+NodNtxgFN4nm7wIbmRRS2V1si
|
||||
jfSAPK3cMyMNEGp/2C5ELpEq2kbHX/J4GOlva5c2g6Jte6sz328pCSmklNnGpjZL
|
||||
HsSvXp4YUFwlcsF68qg9z/XRMvjodxQL5Jgz7Wz07lSIkqmRjZbECXXmdkyml3+E
|
||||
zB2xIEzTbSG38tKOZ9bJ0KN7wPVUgZzIxX96/12a2q+fVVtKkVVQ/Yd/M9CpP8Yh
|
||||
PRAznJppvYxdVpGIFyyD28b1K9TH3Hgo6W5GzJCqDf2tr+xVsLyoFu+ctBj9OKoT
|
||||
yVW99v23d8iNiB4Kj4CIXIu7gbp4iJ1FbjBzubDVQnjwTkv3KnW6oOXSPN6rAg3+
|
||||
Pa/fizIAw5ScWg8IV3jrVrQm5XOr6GN5dh42f9Pd5BSjKO6uL5asKPD6hptAKdYz
|
||||
DTs13LHwtimowZuhZ0+fmthHMLTCygkXUwLmDEka6Mqivhr4zdBjVY1qQefOjm2W
|
||||
i8pWD20RqNu3F2f0HL6JZQ1/
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtzCCAp+gAwIBAgICEA8wDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjkxM1oX
|
||||
DTI4MDgxMDE5MjkxM1owczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDMwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQCcg8MIdQyQgc/av7DR8Ulx8ysYWGrT8wIoV515
|
||||
O2Vn5V3PGNJqosNzOyVmPRhRxN1Bmutj39CA53Jnjb1BgH4e5WEdqWoW2pfuf2fk
|
||||
kx0zgoxRbiOFT1+SmcUKQo9m6PfsAGuLUuW2cvPLNk6SPHuGbcvPkP8jUqjsP9ut
|
||||
ewVGTiJto18SbOANg7PuVA76feeYPOitaDaX8kAGTsaNMEz/lriPCwzqrwpCfw+I
|
||||
5QW91u/T52o/O4REKCno1/I3FJpk3LbEAYiGUtXOVlv7/HBj4BfCCpdcIA9P7TYk
|
||||
v1dtadylT4G1lnXz+OoOUFvvIoFBaNB/x4zDVvIpncpuz/CJAgMBAAGjPDA6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcEfwAA
|
||||
AYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAgEAqfnYmdpLwOKsqoh8EXMdsa9AQeRy
|
||||
MiqZEpyA6tCkfthC1qzFDr4L5Gb5eXZI0Xo0yYMTvMx2oaP/zu81EEvsj6L5Tnig
|
||||
eaZqqm7DlUp42FQOdikv2OTctuZ2y1QAsE4+zStawE7il4ED5C2cTDbVBZccJa2X
|
||||
jl7WB4505Ucec+fmgX7lQB99/NF5Ca9cCnvhb71waTPsV9GTXTBYPvd44N2g/o7y
|
||||
Wq/3ldqMkdj2TrPTWjVxXfDD6CtHCAyXpJmab6tHSbiquYyHxBVgcJgxrlxxpH4U
|
||||
/xdYPjRHqXh02q42Pm0MwIp05NdcxcUv+H+9YKlqr9Mz7zZdbjb22QbfZr+59xwd
|
||||
V4QW+EhEV0OWcAvkbULosSolm6EZX3QmfET53rZqlXf2FSTSF+J6DhQ0hCIIk86D
|
||||
5Sd+gHO2xPieFtFD4DdcW/RLa7a5csIFg919zpADT3XOc9bM27gcBc1uc5h9Ov+/
|
||||
KzGRcnobI4f5sRgAJumLMgVF1iIE94QJpC07zmzy6t9GEJ3z2t24v58Ai6h4THg0
|
||||
CTa7FCZzcvNX7dTu3tueS23NJtQNMq89sOJiyrXFi/8+sgnqz+ed3QMtPpU6j6bf
|
||||
WSXtC7GDkumLYMxnQm7v9eVjO4EkC+2dOfIZBDI+nrGXXw0OpDptXgGQEmFC3ie4
|
||||
2M821rvVbFSjhDU=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvjCCAqagAwIBAgICEAswDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5Mjc0OVoX
|
||||
DTI4MDgxMDE5Mjc0OVowejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDMtc2VydmVyMIIBIjAN
|
||||
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIPDCHUMkIHP2r+w0fFJcfMrGFhq
|
||||
0/MCKFedeTtlZ+VdzxjSaqLDczslZj0YUcTdQZrrY9/QgOdyZ429QYB+HuVhHalq
|
||||
FtqX7n9n5JMdM4KMUW4jhU9fkpnFCkKPZuj37ABri1LltnLzyzZOkjx7hm3Lz5D/
|
||||
I1Ko7D/brXsFRk4ibaNfEmzgDYOz7lQO+n3nmDzorWg2l/JABk7GjTBM/5a4jwsM
|
||||
6q8KQn8PiOUFvdbv0+dqPzuERCgp6NfyNxSaZNy2xAGIhlLVzlZb+/xwY+AXwgqX
|
||||
XCAPT+02JL9XbWncpU+BtZZ18/jqDlBb7yKBQWjQf8eMw1byKZ3Kbs/wiQIDAQAB
|
||||
ozwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhv
|
||||
c3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAHyJ6NQTPGg/CJTC/9nb
|
||||
KHaMra0aFLnvNUFXCiRsLXY7VNx7Z8HsWkm6TrTsTPIu3deMxfg4Rvxc0vDDsl2p
|
||||
YU3rjUNMpzWZQXj2mNO1cPdG30fAIWNCc5qiGXoI2eJjEDM5QXyLMVqneTg7PQ0g
|
||||
cAnf6h6FLmifhdR5e/VZPEG9mEhubETevmIq4lSqQ1lopMjihT1fC9l+a/WaQXxa
|
||||
Ic6Uq9vHdGONFgvjsnjXN8py/zKw303mnAXOEHiaznyxJ2+5UjZ7IYxcO5p6soJR
|
||||
XkkHIv/WyAM+kfljvzVjxx2jTwV15L+399T0x8g5F0fjwd5c0H05JcOfpVB1gPq6
|
||||
HZ+B1wyRs5xNQtYJ9On8KIW1Y21fzjUhKglhGrZ3148DB9WJ/Fk7CJUEuTk37E1L
|
||||
LIhI4/ml1fvE2VNmPabI7xjMtFRaALRKmAhGINnI/guAKHYJqcSQIBIJfOTrXYx1
|
||||
Z2SrT0sUre2toVBNzyyI68m7eGOYaMCTOUL5gCI/SXf3r4LKhNitVow8Rw3Xt1il
|
||||
9xRxZ6SzTs065kjJys4Tuw4a+NF21PVq4dD/HVVabQRDf/6OubjAARo4FyomWsyy
|
||||
nkWwIoZi21e2F+RM5rnuXUuZ7/eV6dJPfBQ2E4y4E0qE+vfNZpMi6OnJ1xdTfTx+
|
||||
z9e60k+pZ+r/ozXQ2srE4ZvZ
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtzCCAp+gAwIBAgICEBAwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjkyNFoX
|
||||
DTI4MDgxMDE5MjkyNFowczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDQwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQCqBDdOcSnf0fCctQwn+yyjygU3qqx74bQEpNh0
|
||||
YEstPxbqOrGzkUUV6vIqMAfyQDcEAaXbxh35/W4ms73waN/+swYDkQVbUn31qB7n
|
||||
psm/wqTz6NVUJ0r20KFJMVoGtfqO991gl1r/xFT6gc7+v+hGj+6iAuMED7v3xFA7
|
||||
qNRD8N+iNzq2ArdUX4OfMN0d2y1Zq5sBqicA3vMV91+KDvKfmQRfGFkvyW6Y1S30
|
||||
WDEWHVCgvmnnw9l8+A8kdEe5/YQbBe5bwdaLYCtv8h6Jz16Ok7jBbrrasYbpcsD8
|
||||
wOI5CnyuV7wKcSFO/vcEO/P3YYqL65puKGKVMteyige4/rpvAgMBAAGjPDA6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcEfwAA
|
||||
AYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAgEAe6zSSoa8HWmjvtV6+aktA9vUgrHz
|
||||
uUtw3OFM/4Gg2U/M1pDirBobh/EZwDqeTNqVFLBibMAWj3V0mND+SLm0V36hOFiE
|
||||
lcnYSJXYoErJ7LLScUfRjPZdu9JhNl8DoQ8NgbHewVZhecA1MbUsTCbSNsufREM8
|
||||
JYbd9+C52N4hqdfxuT+8imGE1Tg3/9CcldukVC4XNBhSYskhy7zMf6UNvTpBH3EO
|
||||
434fraxCjgnPiQJq5S6Bq3Oq1Kbr0o/l7gLNIzz/KlOBJQsVIPExFEMQ7kZQzDQh
|
||||
AmvuoRJEWB3fdYYmxGPOB/pJH8OIjyzcyC3XNDtyz51alXD3G40GHECO0Gnb/Tvo
|
||||
kKODky2nPWrlVuoY6R6bQsFojsUQJSifz3p6jUE2Cpv3/axg0juumJKaaDJqoxVN
|
||||
Bp1vGS+IIcj6nZEyfuUCRkaBAssUKXC2i1uTeoyovsBkjOef9fyclN5ym9/fsyUV
|
||||
AnWxwpxIrfG26AeV2nenRLFUqzvP5xJNF1HBwijmOdYn2tlBImxv8ziRe7JhUyxE
|
||||
fXiqFyEgaPDJ3SgDEIzmYd1tt7vqzpqJHQOe4hJDoga5q+qX8IJOJEz2vy6E9sm9
|
||||
tGdVTvJG0422Hlk6OZcitD+zavn8KjVQ8mMszbm3LurjBYO3830KhAWrOiN6f8gg
|
||||
X6sIXw8/4UKo5d0=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvjCCAqagAwIBAgICEAwwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5MjgwNFoX
|
||||
DTI4MDgxMDE5MjgwNFowejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDQtc2VydmVyMIIBIjAN
|
||||
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqgQ3TnEp39HwnLUMJ/sso8oFN6qs
|
||||
e+G0BKTYdGBLLT8W6jqxs5FFFeryKjAH8kA3BAGl28Yd+f1uJrO98Gjf/rMGA5EF
|
||||
W1J99age56bJv8Kk8+jVVCdK9tChSTFaBrX6jvfdYJda/8RU+oHO/r/oRo/uogLj
|
||||
BA+798RQO6jUQ/Dfojc6tgK3VF+DnzDdHdstWaubAaonAN7zFfdfig7yn5kEXxhZ
|
||||
L8lumNUt9FgxFh1QoL5p58PZfPgPJHRHuf2EGwXuW8HWi2Arb/Ieic9ejpO4wW66
|
||||
2rGG6XLA/MDiOQp8rle8CnEhTv73BDvz92GKi+uabihilTLXsooHuP66bwIDAQAB
|
||||
ozwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhv
|
||||
c3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAEPPwvTShn9x9E0um/Rj
|
||||
HNjGzcuShd0E/tWlUHnn9F1i6Bz0SlbYngbxIiQUxgmraRtzH5wH4Z01xE6vdA6S
|
||||
unckj1XyhwGTV+pufxSkRk6Ox67MZjjXOst36hyQjWNsNf3xDaPFxAvxqWqaMJdf
|
||||
mHAUlDiXIw7kbuZM/eBGx97wNf2F1YPSnvcfPir5ZhGKg4K7ZIlV0Opvemwgqf0s
|
||||
vjkQPRpnILfrInQbOlnFEDMh/tMN6eIEGPDX1MjmMS9cckr5ZacevrjlsNyuM7C/
|
||||
QrVuYHFJ9Le1Eum6GjzMGILUxADoc3r1UgDfaysIaru02lefnhfNeOYixjvV3Dkc
|
||||
rGH3Vtwc4a8M85qh7oKlJ4+f1e3Qn01LmDlD8Y99a30ebbtfApCCUbHJerXoG9Cy
|
||||
J7hcFyO6ZBcTHfVWsHjAoL2oojdo6smbf+7pR8+pxAdnExRsI3sioaw9nnKPCOz2
|
||||
T6NzlbvCts3d2Tpi9eJg2t+uxA02e+qxC+MIk+/xlZ41VvIkUsB4wQzK5nBpziCs
|
||||
wGCzR/C0uHFUVPubQd0oB5Hh09Z4Dbff28m1N/Aqkty8SQGwz9sJAWVDN60cBGIj
|
||||
f+NhitZf6ERhoZUDODuhcuNmCilmZn9inPIGgtMVhtWpFXIB3eSoMSHKUWyFeOfj
|
||||
mv9NYvwrZkt0PCGOxCtwXAYV
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,70 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGBjCCA+6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTESMBAGA1UEBwwJQ2hhcmxvdHRlMRMw
|
||||
EQYDVQQKDApOZXRGb3VuZHJ5MSkwJwYDVQQLDCBOZXRGb3VuZHJ5IENlcnRpZmlj
|
||||
YXRlIEF1dGhvcml0eTEbMBkGA1UEAwwSTmV0Rm91bmRyeSBSb290IENBMB4XDTE4
|
||||
MDUxODE2NTcyM1oXDTI4MDUxNTE2NTcyM1owgYsxCzAJBgNVBAYTAlVTMRcwFQYD
|
||||
VQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UE
|
||||
CwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNVBAMMGk5l
|
||||
dEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
|
||||
MIICCgKCAgEAsb1EPhMUweS9WpjT7L54xAOmZqugJ6fhSrFfLUwNUy172q+ASvZT
|
||||
pT1zKIPcZpGmPB3TX2bHaAR67BbRkUR11JgWE3U8+FsGrYmPZtaKM6fg8Mh0WZ41
|
||||
oMYQNJyQixOktrgqfybyJoT5PeT5AA7QQmd8mku2X9nkAu6gWPf2nHNc7SeQdijm
|
||||
yQQaVK3oqyaxOzWzsU/XbfMEz/ObkefUxgt5Z6jlK0xcW0Q+QgtawMKLUiuo6obW
|
||||
RPcl7Hm9Sze8XJS5pbvS5JkUszxoRZuDVHZylrlHIpA/IL+BnvS+M7SP28UWe9sk
|
||||
rv/s6ACpJtuPJ1EYf5fakugOpY7i+hq7YNi//csbc49Qjn2OtttrR7JcTaHUEU1I
|
||||
/tQbQGAtNkI4pJjRVUdDawQFQlWHZD1COixNLErs2HzAI00DhLrY6SKITI/kjN0X
|
||||
x010XdMcdfay0PLWm6RwxiRmMQFL4GNIC895NF1q6xV4W4rWgqUNlcvKpy+i1chW
|
||||
pRbUHe16ul0qh10fcESrRvAbXn5YrQJLrwbSr+85ubN8lYdNLE0qg2cIXZlUilar
|
||||
ZZzWghtCe+KkUpjfRuAi/CqfSwNK3QXEfeVEK6S49mHeSekOizFIw7fmDhCz9vXw
|
||||
MOnbryRSLEJks0gIRcSDVChXheAqC98y4kcQdniNWFnqJXoqA+rrSokCAwEAAaNm
|
||||
MGQwHQYDVR0OBBYEFK8UXC/sq6dGVFAqEXHsQDzqzwuUMB8GA1UdIwQYMBaAFEHz
|
||||
6RRuOuXj2mwAzOeUinfWeivpMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
|
||||
BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBDAAaOE2Nbb49eOjyTNxIeOB+ZKQjJ
|
||||
1hUEgRrootAA8NYbtKW/vyxTWnNi5XOGXd4DFS9OKZ0mL/7NyLc0mbTwPH2ZT8KT
|
||||
PUTSCpo6yktZ/7TMjyAtWZiOMg2EH+6m/nlNSXk/v5fb8+JQLdZfpxoA017dHh3t
|
||||
c8l7KOskCZNwQHgF/YMXrPXUNbsGkXRuJLtpjPw5O9GvPys7p+a1aJH1WCTly9zf
|
||||
B6j+rMF+UGCPDT30sxitVlohik83j6pKLgEAP/gi8nJbILlTP7ce+gJeHR2tfDvm
|
||||
K91X6QgCF2STUFBU7/9H1/pPRRykOxQpAd8xqSgqGEyp9Ie4tysZjwoUEnG8IVJ5
|
||||
ykrIFximvnb4B+LABV9WEo08n8m1R8wEryrISi8fBPn3Pr5nuayOfFLa15CLTkZF
|
||||
40FN8ika1qNZy8bWRDwTZJQUUb7VCheRWcMwdZdNmhl3J+VZLpQ+ruW7b2ajwacH
|
||||
z5NwBHKNcmxXb/4vHq/BnlcayHnSqT6036+OZQ+owDegcYmWV6LaM7xLErjHz2EE
|
||||
38M2YSiW5SU1zluDe+iHb6l3Gd3Fj/X1gkMWFgYh0XPMSUSyimLNYzy4THKzmWlc
|
||||
QNFoLLiIDbLrMt+vk+vBkIsNTTPXRJOFPBhmIF6uIUj+2YhzNotX/pQtqMKms3pP
|
||||
lmHqdH6biwygEQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGFjCCA/6gAwIBAgIJAOq4qnKYsnlbMA0GCSqGSIb3DQEBCwUAMIGXMQswCQYD
|
||||
VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEjAQBgNVBAcMCUNoYXJs
|
||||
b3R0ZTETMBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UECwwgTmV0Rm91bmRyeSBD
|
||||
ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMEk5ldEZvdW5kcnkgUm9vdCBD
|
||||
QTAeFw0xODA1MTgxNjU0NDdaFw0zODA1MTMxNjU0NDdaMIGXMQswCQYDVQQGEwJV
|
||||
UzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEjAQBgNVBAcMCUNoYXJsb3R0ZTET
|
||||
MBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZp
|
||||
Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMEk5ldEZvdW5kcnkgUm9vdCBDQTCCAiIw
|
||||
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMqr9dr7vj0KvdYkZgMMgS00ohGd
|
||||
MVzpN6JFKb87uEbb7U2uH905uNkm4OOyilY/w0UD8PCU3ISmFgoB5LAcOa77icV3
|
||||
qJ+h4MTaVirps2EtyA34DcyU3k+Fvauc7fZhhnAdcZai/6O13aBorR9awfwJDGfq
|
||||
fa/uq88xN5gU/yniOpNnDZu9lbD4sxhMULLnjUMWpAtBqwyDXSZdEBVc7s5r3L4P
|
||||
Wt7XMurjBLq7wi0mgrN+a9mQy8P3QL+1Di7SIlovsYHZIT0w48N4ZW+mehIAiRJW
|
||||
a9ENQCPbH0+66TKTOgvU4BbNzkKD7kvFGYt6NUTs+89wdpO01qDa1EPDa9sx4Uo3
|
||||
w29AfVBhxo9Zl7hWX1voMC5NoflE33X0f8X5kfKNnJtU/ALXiV+Wd4grI3LwkRX9
|
||||
gwhsQANae6J53MN6GTY6mf7T71mvZf/F+MKjyJYcVs1pWdBfvB1Fo6jvzeUSi6dy
|
||||
p7joUMEsGnIC4ModCkhPcwryuQL/XIE3Gwfji8zB5Rm4rS7s8L0oe2alB+5+VgZ/
|
||||
EDfiRjpZTePPJAd62gtiOjFOo0QSO4anDLajWPtFoIEQUhtiWeVuGkRYVNpB/3rP
|
||||
YZDqbVTfLsnIN+UdK70WjUk2QbepeyMPB1r/pbs1ElGB0WuGc7CubsXov1fg/Uef
|
||||
NT9UkvrovA+aIdWNAgMBAAGjYzBhMB0GA1UdDgQWBBRB8+kUbjrl49psAMznlIp3
|
||||
1nor6TAfBgNVHSMEGDAWgBRB8+kUbjrl49psAMznlIp31nor6TAPBgNVHRMBAf8E
|
||||
BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAJ9TvhopZ
|
||||
E5rGe57y1lvk8WQRucNFxGspdGGem0DS+uAHjJ2djFf2EQFkPyjo8HLet7C+XmZ5
|
||||
I4ETrPJvgkPzSUd3MdJUUjBvOw054SMKyW/88D/dj4nsMK3qA80wN5i4Syx2p5KI
|
||||
yhjPaCe96fh+VIwqBMAl3f9KlWuffkfNeJT0ySYVWk8QydNy06PD4mdwKQbn4P03
|
||||
Xh3G2Bn+1R9sf4ZR+HIZXFF0+tfkpCoDJqkx8Roxddrwo2zs8b6wOJJYj5KD2NQa
|
||||
3GCR8p1U20Vb5AxfLLt5PeJc8D7WvaEUCGB8hoa0ElSHE8cyEq2NsCABf7r7YPcY
|
||||
BtoPX6VxAeEqvLeHKBDc5fv0UlbrPI9LS2JX8t+i8epf/fH2rk9NUE7AQ5Lb8sJz
|
||||
hHYztL4cg9/h5In6cfi4Ih0njZYKuiv+ZGy4vuB4KSyLvQYe4LKc/jKpAWzO79S1
|
||||
sESw3yWhOcuk4ifFoYHVjxQ+bXhvYujX/ceSgxWHT9RocnROadnWvuZ8aF9HIBlh
|
||||
F29PWwH4RvhvkDbMRmqxNz0jAU6GcjhmKU+hnmzbF6OqtXDcZK+i8SF2mutCa/G6
|
||||
H5VDbfL/7/jP1vbFbIO7bNW94HjCGo97auSDEmsSXgZ8uTYNb503qPzdmXiU+hRl
|
||||
jDOQLqtoJofIWUChpNurPQfqu9UljEk9LpQ=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvzCCAqegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDUxODE3MDMwN1oX
|
||||
DTI4MDUxNTE3MDMwN1owezELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRQwEgYDVQQDDAtjdHJsX2NsaWVudDCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGXmeb1l8EjH6EbDgY8UU66MFB4
|
||||
2THjA6DwHRaU8TVaGUqM0HUwA6o1oOuDDaq0WGExVTW80UnQC9PoGKO630JXAIh1
|
||||
ouLIGLCTRwzuHeDdFqh94w/U8bpt8UmdCwM4B9SAbZNWJtzQlR1bH/7NdujyQHhr
|
||||
064hESpQeXERt5JD9kEnTaDTBmRBS2Va/piq+O7os8Xdxwm//5CgFJ4mY+Jx2M97
|
||||
brH5vo9gWI2lWHo3MrZS2CryNnYv3KETwpsz7FnSab67sch1yg0Y1ewpjXpytNNv
|
||||
PjDN9FmP2DPcV2pecZur13y5urhv73sOYrFIZeO0c2ZwpPYQ5H11jpEYv0sCAwEA
|
||||
AaM8MDowCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIAYDVR0RBBkwF4IJbG9jYWxo
|
||||
b3N0hwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBCwUAA4ICAQCOuukYQ6cgstNbbYVe
|
||||
xJsKRRdLqIdkHthH4dCtOaB5MxIH+n8CpAWwZcepbf6/RsPnsE54kVw1rJwgbWxY
|
||||
Leyl5iVyuSzQ2NtiJOJAqHiKWLi965bs8e7rHEK/k6AnRpCaqXWZKUMSgFJ1wyLn
|
||||
B602AE9OHkXgXumNyjE1IVP30BKd4DYOtB33Z3J77F3UIcaDcaU6IJThVO4VmLle
|
||||
Fv4Vnw8iMvMfAy0FuwAahHEshFW53HW5ZSoi4a8BcwRNy17xQpGKjAOw4naOWe+H
|
||||
A1T2ayKAGMA9jFcXKn7+lfTSgYdwmhKUGMQTlsqdpHktvBjQUFyPcvMt99AI5Amy
|
||||
0MNaTQ/tXr6lb3ws40YFOqjD7VKhJcoqcwHqX0xXfI7X0zYNY3DGVTkvUnWTDcle
|
||||
pF3O6ZKllbL6LKFkJXJRVhqOuomsAuho+vi2A3la/PBcF48z4M0aH8j6HGftzgNe
|
||||
AS0Ys5iOqJhr1qdBils6hSL84cCsNYyHG+V95jdwNepSOOBqc5+OydFoUjFQScK3
|
||||
Q3bjV7T59N11yCMOJzukrJorGtUr/nRdQPcEsCQlvGj60+kx3FEygBIpeiZy5AAS
|
||||
h7KoWY1Sh2l4YW0Oh4AmeLDY0ryBXDafgAuwGFh7zENLBjDitdpFSuo+d/YksOnG
|
||||
CR1KiiHDLLh/aqOiR7T0/HKFqg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEuDCCAqCgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDUxODE3MDE1MFoX
|
||||
DTI4MDUxNTE3MDE1MFowdDELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQ0wCwYDVQQDDARjdHJsMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsZeZ5vWXwSMfoRsOBjxRTrowUHjZMeMDoPAd
|
||||
FpTxNVoZSozQdTADqjWg64MNqrRYYTFVNbzRSdAL0+gYo7rfQlcAiHWi4sgYsJNH
|
||||
DO4d4N0WqH3jD9Txum3xSZ0LAzgH1IBtk1Ym3NCVHVsf/s126PJAeGvTriERKlB5
|
||||
cRG3kkP2QSdNoNMGZEFLZVr+mKr47uizxd3HCb//kKAUniZj4nHYz3tusfm+j2BY
|
||||
jaVYejcytlLYKvI2di/coRPCmzPsWdJpvruxyHXKDRjV7CmNenK0028+MM30WY/Y
|
||||
M9xXal5xm6vXfLm6uG/vew5isUhl47RzZnCk9hDkfXWOkRi/SwIDAQABozwwOjAJ
|
||||
BgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhvc3SHBH8A
|
||||
AAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAGH1o/uGn8QdwnM9LyoGfaDKCLYZ
|
||||
p2w+9Bhpbm1RcOgg8Srw6yJHQHrDJgVAH6YYDaueS1TTiUNOUDmHLBuX4AGPga6h
|
||||
8sxVsB0faYqM82yDXO/wQdw5FmcvBNFpchK5R72L7NSRshdq/VUL+FsWdQw58uLn
|
||||
s6QDfMme3fU0WRQ5vAkSEm057BKeBXviRT9xNcnYMTlqZaQE2pEdzPG8xicBJNvL
|
||||
V5zP4HOi63/it2Tv1M2YXVcriBXJkx023CHKZ4tm2enqVofZLyjvzqLTeNuJc0jV
|
||||
zwjBpp4hG/dNc4p9kl1fQOcd7N6EfBggQy3f89J2W5X4AXBgCjxcubj3pg2q2qV6
|
||||
83d45xD4K1HJFRlgpxg26Z/e09GL4yUdST77elv+SKaYNSOuyzOu+IoBv8GHEnH4
|
||||
QqbW8/56taQ9bUSGw+r8yvv7uw69bPig1OnAc9hZ4cc4yOVnzW7L98OeKae/XR5I
|
||||
Ewv1kvrv7ISsYKjSOIGtcQLZ2/xoHsf3xJrZ14viG2OCoRj93P18xod2yi2Vgr2Y
|
||||
uBdknNjcV3SVv4dsbU8bMSHTThlQM5qrPZHlnbQjncWwXesLCUqeL0O7Tzz6lGT6
|
||||
rpD1hgO9R3c9Vmqa5g+Anqbv50YTt+57M5NcLtHTAdfWIOa92LZF8FOpqTE405A/
|
||||
xLJv+nDUo0iraA3w
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEuzCCAqOgAwIBAgICEBEwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5NDQ0MFoX
|
||||
DTI4MDgxMDE5NDQ0MFowdzELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRAwDgYDVQQDDAdkb3R6ZWV0MIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtMRtlGukei2+nYGjLbgvSn2JNZO7HGm2
|
||||
Tbh4/VfZ9GJquE4iyGoRenNgyEP1LdoBkYlFGrerxO9cOR4o2iPNg1IhnOp96SxP
|
||||
IE5ogg7pfU9waewlOhULjBwdPDa/cmBIwV80eDX6X7jAsSWtCxnaB7QwTJNRzM0I
|
||||
9456QKEpzrOHv9kEUzeaulD/T5eFGRAUEES1h1JdVp+Ay6ZzbE4n208VdNEDV1bm
|
||||
61VQ5RSbzCRTvoIE2xBwt8YtBlulz4aof/Wm0dR5zzcQqXeNrU4W3jwpzycSEyop
|
||||
5nBoYrWmjg6r8oZ7PVPTMD+AsBFfzCecrTGCOSdHNWf+p5F1KLvZiwIDAQABozww
|
||||
OjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhvc3SH
|
||||
BH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAKAGn986vhFHlxQ1bG0+hQdu
|
||||
vrSG7E45Y81AuospC7ABm74Zny/zg3choeVTcoZoKmZhKAPizX5LMbkML6x/kjQt
|
||||
jbZFeez6Q1LAn5IdiDlLUXY46/HubClF/gfAaJcQP9h2CQfqhqsl5eVqfbcz3fSB
|
||||
MMZYuAs6DcaJcS2u6rIXmH89F69bs83o0kdiMTFyC35WXzh1d0lqbi0p29Bc5Btd
|
||||
eEgbHEqyP2oYASCI7hSeMhIu0kRhUsGDvBER6Sag6k/L7t6lrQ/r1EP2ss0ycheV
|
||||
ShdCaX3oikH9LFk9hSBTGf0HGxwku54GFRU3ch+EeRHd6iJj6cVKuPV7cpmNFSF+
|
||||
n34byUC01fbjLhlszJIGIt01R+9CercU8MyoD7+TmzY90yu1PFZ7B9jDqkkUqSyQ
|
||||
HPE/diq0Is/RoI0q5HL6bqk+/HwQQ9XcvCsC2kbijtGVMMhBRl7m2GMyiFtWlhVu
|
||||
trNWaOj9tXlbBIkERgDWRteCkMgU6zjbKvqepQC5WAkvu0LnhpbhTXqjaNGZqBio
|
||||
1j/BKp+6ozb1Jamv4C0/rmEMBRH5Z+X9vqDmkAwLJb7wZySrFBQchvKnPnwHUQv0
|
||||
JniImSdIKbiAakU4v6wMCft6tDvDmWKuluN3JmAVz00y9/vbVwMFdrRQQjlePDBR
|
||||
XG4LbZTH8lXKIrLKDCEW
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEwjCCAqqgAwIBAgICEBIwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDgxMzE5NDUwMVoX
|
||||
DTI4MDgxMDE5NDUwMVowfjELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRcwFQYDVQQDDA5kb3R6ZWV0LXNlcnZlcjCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTEbZRrpHotvp2Boy24L0p9
|
||||
iTWTuxxptk24eP1X2fRiarhOIshqEXpzYMhD9S3aAZGJRRq3q8TvXDkeKNojzYNS
|
||||
IZzqfeksTyBOaIIO6X1PcGnsJToVC4wcHTw2v3JgSMFfNHg1+l+4wLElrQsZ2ge0
|
||||
MEyTUczNCPeOekChKc6zh7/ZBFM3mrpQ/0+XhRkQFBBEtYdSXVafgMumc2xOJ9tP
|
||||
FXTRA1dW5utVUOUUm8wkU76CBNsQcLfGLQZbpc+GqH/1ptHUec83EKl3ja1OFt48
|
||||
Kc8nEhMqKeZwaGK1po4Oq/KGez1T0zA/gLARX8wnnK0xgjknRzVn/qeRdSi72YsC
|
||||
AwEAAaM8MDowCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIAYDVR0RBBkwF4IJbG9j
|
||||
YWxob3N0hwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBCwUAA4ICAQCD/bQOYXMhywqT
|
||||
UsWgLvNsff5R3xT2ddn/ECN0KJSGZKYnPrCimWAVIEz97gVgPQneLyYz2aAEbARR
|
||||
IFvnKt4saXb/jbTNThV43IU4kTlpU7B4VY0w6RjmMCwpCwokIeRLNIU2SmswApoW
|
||||
isVBIeZ4LTdByKy3a74rPk8Nbt8pOa27adWoLrO9bxjReZ/RqeWwSVVOgVyiVkTe
|
||||
UadIADo1HJoFouyvjJsNG8E9B2V5KZ9FgdbJzGKKlMkHd1DoauNHTcORwcLz8G2X
|
||||
rf9yEiFYQKlgYaHpR7YtblVR9DiWtT4Nd25JeCiTZ+1/npj2stt+ZnjaZcFkLh43
|
||||
1Lw+HlD4eR4MLPEvlcBvmpTJcTOCY0ZL1GLK+Ip1dL90cseIBmON07zIqCNKLqUF
|
||||
baovuK1MTG/Hs/y5N1KOBFcc18O4F2DpSW0hD7AEFjEArs4mUwGrlqroCNjGo4K/
|
||||
CAXVltyFQqxWcPBzNYG/HKgYe6uatAjPirQrV5p/8CXOzXP7nEFF5t1tppilseib
|
||||
Amb8ClAby+//S6bDsvcaRNTtYVUJpv04ScjiT9/s1nBleGx5RMsz062JUbL70S9j
|
||||
bjBYvseajIZzaMIUL0zc3wNFOxUVCTaDMxt5GxO24YI8JBrRjPbpzLesJ5iMmjZq
|
||||
3hgAjgNwSNau0M0jKoqYSoJgBGnZaA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,35 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGBjCCA+6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTESMBAGA1UEBwwJQ2hhcmxvdHRlMRMw
|
||||
EQYDVQQKDApOZXRGb3VuZHJ5MSkwJwYDVQQLDCBOZXRGb3VuZHJ5IENlcnRpZmlj
|
||||
YXRlIEF1dGhvcml0eTEbMBkGA1UEAwwSTmV0Rm91bmRyeSBSb290IENBMB4XDTE4
|
||||
MDUxODE2NTcyM1oXDTI4MDUxNTE2NTcyM1owgYsxCzAJBgNVBAYTAlVTMRcwFQYD
|
||||
VQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEpMCcGA1UE
|
||||
CwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNVBAMMGk5l
|
||||
dEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
|
||||
MIICCgKCAgEAsb1EPhMUweS9WpjT7L54xAOmZqugJ6fhSrFfLUwNUy172q+ASvZT
|
||||
pT1zKIPcZpGmPB3TX2bHaAR67BbRkUR11JgWE3U8+FsGrYmPZtaKM6fg8Mh0WZ41
|
||||
oMYQNJyQixOktrgqfybyJoT5PeT5AA7QQmd8mku2X9nkAu6gWPf2nHNc7SeQdijm
|
||||
yQQaVK3oqyaxOzWzsU/XbfMEz/ObkefUxgt5Z6jlK0xcW0Q+QgtawMKLUiuo6obW
|
||||
RPcl7Hm9Sze8XJS5pbvS5JkUszxoRZuDVHZylrlHIpA/IL+BnvS+M7SP28UWe9sk
|
||||
rv/s6ACpJtuPJ1EYf5fakugOpY7i+hq7YNi//csbc49Qjn2OtttrR7JcTaHUEU1I
|
||||
/tQbQGAtNkI4pJjRVUdDawQFQlWHZD1COixNLErs2HzAI00DhLrY6SKITI/kjN0X
|
||||
x010XdMcdfay0PLWm6RwxiRmMQFL4GNIC895NF1q6xV4W4rWgqUNlcvKpy+i1chW
|
||||
pRbUHe16ul0qh10fcESrRvAbXn5YrQJLrwbSr+85ubN8lYdNLE0qg2cIXZlUilar
|
||||
ZZzWghtCe+KkUpjfRuAi/CqfSwNK3QXEfeVEK6S49mHeSekOizFIw7fmDhCz9vXw
|
||||
MOnbryRSLEJks0gIRcSDVChXheAqC98y4kcQdniNWFnqJXoqA+rrSokCAwEAAaNm
|
||||
MGQwHQYDVR0OBBYEFK8UXC/sq6dGVFAqEXHsQDzqzwuUMB8GA1UdIwQYMBaAFEHz
|
||||
6RRuOuXj2mwAzOeUinfWeivpMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
|
||||
BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBDAAaOE2Nbb49eOjyTNxIeOB+ZKQjJ
|
||||
1hUEgRrootAA8NYbtKW/vyxTWnNi5XOGXd4DFS9OKZ0mL/7NyLc0mbTwPH2ZT8KT
|
||||
PUTSCpo6yktZ/7TMjyAtWZiOMg2EH+6m/nlNSXk/v5fb8+JQLdZfpxoA017dHh3t
|
||||
c8l7KOskCZNwQHgF/YMXrPXUNbsGkXRuJLtpjPw5O9GvPys7p+a1aJH1WCTly9zf
|
||||
B6j+rMF+UGCPDT30sxitVlohik83j6pKLgEAP/gi8nJbILlTP7ce+gJeHR2tfDvm
|
||||
K91X6QgCF2STUFBU7/9H1/pPRRykOxQpAd8xqSgqGEyp9Ie4tysZjwoUEnG8IVJ5
|
||||
ykrIFximvnb4B+LABV9WEo08n8m1R8wEryrISi8fBPn3Pr5nuayOfFLa15CLTkZF
|
||||
40FN8ika1qNZy8bWRDwTZJQUUb7VCheRWcMwdZdNmhl3J+VZLpQ+ruW7b2ajwacH
|
||||
z5NwBHKNcmxXb/4vHq/BnlcayHnSqT6036+OZQ+owDegcYmWV6LaM7xLErjHz2EE
|
||||
38M2YSiW5SU1zluDe+iHb6l3Gd3Fj/X1gkMWFgYh0XPMSUSyimLNYzy4THKzmWlc
|
||||
QNFoLLiIDbLrMt+vk+vBkIsNTTPXRJOFPBhmIF6uIUj+2YhzNotX/pQtqMKms3pP
|
||||
lmHqdH6biwygEQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEuzCCAqOgAwIBAgICEAYwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDYxOTE5MjQ0OFoX
|
||||
DTI4MDYxNjE5MjQ0OFowdzELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRAwDgYDVQQDDAdtZ210LWd3MIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtJU/MT5Om7hLHOj+u8f+rBlzdx6xcQc3
|
||||
99Fd6kLywH5m+jPc6VWrM0r6B+rrTMvxud1XvrwFQ5RZrYXvGkMqWTWX5ZVQeXOe
|
||||
+UcBVhFKRx7F7V2mRLQiwgCswzWBsN00pq6Wee104GX54mj9nrovb/V4kX1q1NJr
|
||||
R0rbEwIG8gceJGT5xt1bHsMpd2QXDqZG6s4oX4ib0QItxs2wNY+7YUuA996Je+6u
|
||||
ihD/es2m4wkpjKb/snMEE1gResXAzGfLjBAxoCO7UlSC6wlrxnRsvTMYLWV9LuLL
|
||||
c5PmzF9crMIU5LSKYIu6uNeWeuetco7QfZmyxsq74UNBlr5Z5tRRGQIDAQABozww
|
||||
OjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhvc3SH
|
||||
BH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAJTgeIOI7gCNOerPRCbTgHax
|
||||
vajpPc12QIboMnbDEpo2WgLCju/P9DOTnIusARb1SuUG4FkI7x0AaSM23QSCWIw8
|
||||
hHvJg97pXyHbdSBr+9oR2eQ3/kzb0hMQTnsOub3O6Zqju+ZDyzx9OCygfXuacG42
|
||||
wj9GhdS1+NgXnImYqkdPl+OtWdrjNRL9VgGnrQSEVsJIRJaKG3AoQxBj7dO0Lwlz
|
||||
gKkg6+o2iZETT/iEjdszYsHUjnUB5H/T553ruwRH27VV/4TppSGpy6GoOdr54oa3
|
||||
H8RDQfEzb2No6zGZ1voKmPp1csUqI0P8CH5T6sPGpmcokLCH53AjDsAAK8K2msa5
|
||||
ZQLoh0PunE4LbHdTVmcrHLl009uEoYzH4QCsSo0yA1qImtZah6Pu/NEAFZ2g8BTe
|
||||
T2kZNm2laYL0kZXQs3uUf+T87uAFEBQ++dnCPVF6v0vAJy6eN4U8m87fncYK9XNq
|
||||
/QCcqJCOZnEBJyBPaJEx7UuFqxPyXbU/rqk+VOlsaazhvinmgGQOQWFwej6ASf/Q
|
||||
UTevZTrqVBCV+4YkMSGDCqczhYamsg5UpDqYzD1uHrmYDuHJ+MFGM3TuOMxtxtdr
|
||||
E6KhXsMrfc0Gwg48x6l2KomhIWK/p0KZ49xlbUWXHurKZcBsZnxOelG4Q0LN4Pea
|
||||
QXRit0jZCBdZCEReq1hu
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1 @@
|
||||
1000
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDAzCCAesCAQAwczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDEwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDbqcpLyr/yZFw2YxOy1RKhO/jw4ra8Z15KdEHNbz5h
|
||||
cNlT6dmVFQj4sBW9AsB06ynqzrO5cKjnWF/LZXzTRGlDUmxmKZOZCcb4NVy/4fwW
|
||||
NN8IBuJQBrrz1qTMBJaG4DRbZ+zTICrb2EJGJyNFZbNKvlRQzn4xMjMm57Upv2en
|
||||
Imy8BHUWahjkcCG/uXPTJzjupTweRI34DPxTU2q3hH7zwocdFMe/mkzShMb1qwj3
|
||||
3BByHWzSK60NawE140li24v3ELLhre/C6cZSV1Nyk4U9jreSeaQ/uj5cmk08dPnC
|
||||
eBcTqMIwhAOihMYM3vqhOZbNfssr7gXd0/8bv/7P6JGpAgMBAAGgSzBJBgkqhkiG
|
||||
9w0BCQ4xPDA6MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxv
|
||||
Y2FsaG9zdIcEfwAAAYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAQEAqNqHubzNgIzw
|
||||
qCMV/Njoprd9Ia6JK8N1O9RnvhYJCIc1SETJCaNF4O83AmVCZ7HgDIOYeHcYbzyh
|
||||
IVhfTlMdL1mkCq5h9f5TGokEBe+abMD2G9ff5l3MKMDi8SDMM7e+OyUignuCybo4
|
||||
rlKINukDR8Qn/UM4clBDYWp6VfWcnQNot1+1IJrMLigTmsn6Ggn+irNmFaLg5EFM
|
||||
O6S6mObGR0CzEkPD/VJ+xKHho2n+yCrC4TWUWUQuvgd6Ms5hx9AAEBGEMyr7KJK7
|
||||
KJuWeJ++mThBksKU5pwTRF9k7CfDShoc2auTTMNyz5KcN35rQ0AiG+4S07Ee6elv
|
||||
sCSWVD8saw==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDCjCCAfICAQAwejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDEtc2VydmVyMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA26nKS8q/8mRcNmMTstUSoTv48OK2vGde
|
||||
SnRBzW8+YXDZU+nZlRUI+LAVvQLAdOsp6s6zuXCo51hfy2V800RpQ1JsZimTmQnG
|
||||
+DVcv+H8FjTfCAbiUAa689akzASWhuA0W2fs0yAq29hCRicjRWWzSr5UUM5+MTIz
|
||||
Jue1Kb9npyJsvAR1FmoY5HAhv7lz0yc47qU8HkSN+Az8U1Nqt4R+88KHHRTHv5pM
|
||||
0oTG9asI99wQch1s0iutDWsBNeNJYtuL9xCy4a3vwunGUldTcpOFPY63knmkP7o+
|
||||
XJpNPHT5wngXE6jCMIQDooTGDN76oTmWzX7LK+4F3dP/G7/+z+iRqQIDAQABoEsw
|
||||
SQYJKoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREE
|
||||
GTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBACsD
|
||||
3UPwGHbffGyakLcmlI/kYR4la5w6fUBaGVFmhnvQ1GtWBYm1xZEBBEsRMcwcnV4H
|
||||
f+uWLhPbrN5n3Af+o5e+5BIcxvgz820cV67c08/1uwMCaWUOdY5mYFU1UFkSXydQ
|
||||
/97gL9rQkK8zuqT6dEWcWYJ0AER+ZBPeSlbNP2HNdfXHKniaZjU8Tswvyxmb/2gG
|
||||
gb4Tmq7JA7gqvz1A5cXAMHBLfZlaDvA9TuXaqv7gHdPDlIuqioGy43ARp57wFNB1
|
||||
Z2lNdDjkwQr9baagX9jDlnoTPzo5ACQtOfORIYPm8GTHe62Vm7etQeergoTvjxe2
|
||||
495uzvPv7ssDuup8JxE=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDAzCCAesCAQAwczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDIwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQDGfv6XkzO866Bi+rVZNGHtOjxXZE0HW5rwaxVQ3zMt
|
||||
k/8Elrlyr6ZuguObyUfLJdnScvirjaGbUqm6XTL7H9yRUKBshQZDtaci6XRm4gq2
|
||||
1X7pQ0f1oUmsW5q+dDqbJ8JJ+HbEhbPH7MmZfsTLIASWMKK/pEzTf9t98fyN4LJO
|
||||
/Yr++PmE7ZEz+YRwGphSupWEatLlfRh7XviihxKcXTiH8Z/qD8A6W8lngu2dHFU7
|
||||
VXiBITPwvx/GeanahwduqpnZJNWaCAA7h0MCCatJ01ITGGPgsBCfJWyezBw8CAyL
|
||||
WYL/dlauaq1q5Xg/Bp8V6HddEy20QypRxdY/kPobAcVPAgMBAAGgSzBJBgkqhkiG
|
||||
9w0BCQ4xPDA6MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxv
|
||||
Y2FsaG9zdIcEfwAAAYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAQEAOeXMaHBB2Wlz
|
||||
IWW8vd0BxWKtsE8rrd7mL32rivU+mv/ARruGusF8n3kINzE6w3nLCvk0QRAelhK2
|
||||
Jp7Ml5ugmS2y/O/y8+vr9iJc2vcd04i1gCzWcjFXZTVNVVIB79Pvycvi6rVWyz5k
|
||||
X6HlvRrRyf3Sq/52heaHkh8xEWkyDvphUHnorClMaezwCRxfvXgln2riBPdSjNG8
|
||||
+Viz5L2N3Rkiim0AkiAb5NMhYzNFtDajdi36qFT3T8ZpwkbDn1eYb0TkoaPr/ITX
|
||||
EFdsXCsG82QexxLYrA0IC9rygxkHGKErQaLvCQ8X6EgNz3Rsw1F7w0kkiCMfQ36c
|
||||
k8nxba2a8w==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDCjCCAfICAQAwejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDItc2VydmVyMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxn7+l5MzvOugYvq1WTRh7To8V2RNB1ua
|
||||
8GsVUN8zLZP/BJa5cq+mboLjm8lHyyXZ0nL4q42hm1Kpul0y+x/ckVCgbIUGQ7Wn
|
||||
Iul0ZuIKttV+6UNH9aFJrFuavnQ6myfCSfh2xIWzx+zJmX7EyyAEljCiv6RM03/b
|
||||
ffH8jeCyTv2K/vj5hO2RM/mEcBqYUrqVhGrS5X0Ye174oocSnF04h/Gf6g/AOlvJ
|
||||
Z4LtnRxVO1V4gSEz8L8fxnmp2ocHbqqZ2STVmggAO4dDAgmrSdNSExhj4LAQnyVs
|
||||
nswcPAgMi1mC/3ZWrmqtauV4PwafFeh3XRMttEMqUcXWP5D6GwHFTwIDAQABoEsw
|
||||
SQYJKoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREE
|
||||
GTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAGVv
|
||||
VIaN7FH3nBxexB9iz9blTw9uvz2PH9g525ebcbw4E7tMWpuJzux+DkIpxKPHsAjz
|
||||
UkUH/6j9W/C5JjNnGMFwFrdCQIga8FhrOgG+EGuRGIWDk2Mlh1nolOaKSdIguH6a
|
||||
Ejjc8EFc/VICOn670dJ/LT6PT1CTYFRge9s9F0GxMa07QcBy0aw2RedXOQFSMxd5
|
||||
ynCqxn8hhlkRU8SPqz/KH2jZmxFDYjDltMsVz55duVOslyF3RNA8oca0M9y5tgpl
|
||||
4w3YgF+sjGCQ4fGTcNl6hq9XWF0w9lX2lDrObSR5UWxvHlqskRmkh6tF4N5eZNpG
|
||||
MCyQNrB3uJw28KPvyLk=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDAzCCAesCAQAwczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDMwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCcg8MIdQyQgc/av7DR8Ulx8ysYWGrT8wIoV515O2Vn
|
||||
5V3PGNJqosNzOyVmPRhRxN1Bmutj39CA53Jnjb1BgH4e5WEdqWoW2pfuf2fkkx0z
|
||||
goxRbiOFT1+SmcUKQo9m6PfsAGuLUuW2cvPLNk6SPHuGbcvPkP8jUqjsP9utewVG
|
||||
TiJto18SbOANg7PuVA76feeYPOitaDaX8kAGTsaNMEz/lriPCwzqrwpCfw+I5QW9
|
||||
1u/T52o/O4REKCno1/I3FJpk3LbEAYiGUtXOVlv7/HBj4BfCCpdcIA9P7TYkv1dt
|
||||
adylT4G1lnXz+OoOUFvvIoFBaNB/x4zDVvIpncpuz/CJAgMBAAGgSzBJBgkqhkiG
|
||||
9w0BCQ4xPDA6MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxv
|
||||
Y2FsaG9zdIcEfwAAAYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAQEAKJoDBGGyGUSN
|
||||
uQbM0r+TGWV92wIH6AcgU5FsRoMhpNAScha+lhn1+2qUJlgpUAywye0tUzE3PXlX
|
||||
bjNE/1FNLoIN3X5BfXeDdxtkyQMFYAzctDVSixRHOLU2GMQaYtiecSD/cb3iLgvk
|
||||
P7QwbXtNNim3eoqYjvyMvP/wVivfjvtgAIquxbtzSuMDrOSwkS57CyZZ+Yvasjx3
|
||||
y2PgWCSYaB/pV99s768b9nf3aNQqmYUaEkwYQFBjWQOWpjS9YYFLwRZLGa2tjFSQ
|
||||
l0hATmzhxfWj/skLQad41HgG/foTXXBI1ZayDqFVYLMI0cy4hOFnCVwHBzVcAjaT
|
||||
EsxBl5IlJQ==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDCjCCAfICAQAwejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDMtc2VydmVyMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIPDCHUMkIHP2r+w0fFJcfMrGFhq0/MC
|
||||
KFedeTtlZ+VdzxjSaqLDczslZj0YUcTdQZrrY9/QgOdyZ429QYB+HuVhHalqFtqX
|
||||
7n9n5JMdM4KMUW4jhU9fkpnFCkKPZuj37ABri1LltnLzyzZOkjx7hm3Lz5D/I1Ko
|
||||
7D/brXsFRk4ibaNfEmzgDYOz7lQO+n3nmDzorWg2l/JABk7GjTBM/5a4jwsM6q8K
|
||||
Qn8PiOUFvdbv0+dqPzuERCgp6NfyNxSaZNy2xAGIhlLVzlZb+/xwY+AXwgqXXCAP
|
||||
T+02JL9XbWncpU+BtZZ18/jqDlBb7yKBQWjQf8eMw1byKZ3Kbs/wiQIDAQABoEsw
|
||||
SQYJKoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREE
|
||||
GTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAIhu
|
||||
MLS2WGErqzN+15zKdYOoeXZaAGIPk3UZW7G7Fe/yNw5ukNF0nCQBsu97WBYQkXV5
|
||||
JY7Ur0Tx/4aplvcUAKbGIQ5FBTzlqQYkuQVgqtDbvWy7NzT7GoLdVsxZm5fFkHqq
|
||||
ny1l60xRHWnpSyUsAsKvYWPbTMqvpnm2/6JHWs+p3vpaDRvyN66bOi268ozvrVa0
|
||||
SlzrkGfm4TIeuxSB5uKIEGDvbAoMK8UEINtuQR+nMa7eOMeDc2cfJXe608dkBZzi
|
||||
z+cmijYe15OMBuocPNhpJI3Ij5/20HY4VV4QyWwnLp2aATq2QrdijIeIgfRLfe6u
|
||||
ztzBGpuDSxP5zxgyWbo=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDAzCCAesCAQAwczELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMQwwCgYDVQQDDAMwMDQwggEiMA0GCSqGSIb3DQEB
|
||||
AQUAA4IBDwAwggEKAoIBAQCqBDdOcSnf0fCctQwn+yyjygU3qqx74bQEpNh0YEst
|
||||
PxbqOrGzkUUV6vIqMAfyQDcEAaXbxh35/W4ms73waN/+swYDkQVbUn31qB7npsm/
|
||||
wqTz6NVUJ0r20KFJMVoGtfqO991gl1r/xFT6gc7+v+hGj+6iAuMED7v3xFA7qNRD
|
||||
8N+iNzq2ArdUX4OfMN0d2y1Zq5sBqicA3vMV91+KDvKfmQRfGFkvyW6Y1S30WDEW
|
||||
HVCgvmnnw9l8+A8kdEe5/YQbBe5bwdaLYCtv8h6Jz16Ok7jBbrrasYbpcsD8wOI5
|
||||
CnyuV7wKcSFO/vcEO/P3YYqL65puKGKVMteyige4/rpvAgMBAAGgSzBJBgkqhkiG
|
||||
9w0BCQ4xPDA6MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMCAGA1UdEQQZMBeCCWxv
|
||||
Y2FsaG9zdIcEfwAAAYcEAAAAADANBgkqhkiG9w0BAQsFAAOCAQEAMTokHy9zmf6A
|
||||
q48lxaGS+RC0NZlpzwf/NybVkCiAg16MjX1ipLa2hUw0m7CiqGuqZBi5guQISn2c
|
||||
KPGYp/cEAk3YQh2y5jb8mOvc6t6TW827dJUMkjuEYExhoEZJRPFOSoI/tCMjCjiM
|
||||
l3hXt4HlErNvMTA3uDACZwiNTQ6uGzv0VCH8+dpTtUkhinYJc1oUy8YAKQr6xvgR
|
||||
dEt7iRn6FuH0Z9cY35MAR1aFzNIoGcS+UTn/r2BefZNwiyTDTlnXquPL8aVgRkcp
|
||||
2MkfjH3wia/M/2rtl/vn5dkEZ2jnPqQCMilsV8DUgGe9E6d8Dk7Jeu4H2vo1XTO/
|
||||
OIUhslqO4A==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDCjCCAfICAQAwejELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRMwEQYDVQQDDAowMDQtc2VydmVyMIIBIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqgQ3TnEp39HwnLUMJ/sso8oFN6qse+G0
|
||||
BKTYdGBLLT8W6jqxs5FFFeryKjAH8kA3BAGl28Yd+f1uJrO98Gjf/rMGA5EFW1J9
|
||||
9age56bJv8Kk8+jVVCdK9tChSTFaBrX6jvfdYJda/8RU+oHO/r/oRo/uogLjBA+7
|
||||
98RQO6jUQ/Dfojc6tgK3VF+DnzDdHdstWaubAaonAN7zFfdfig7yn5kEXxhZL8lu
|
||||
mNUt9FgxFh1QoL5p58PZfPgPJHRHuf2EGwXuW8HWi2Arb/Ieic9ejpO4wW662rGG
|
||||
6XLA/MDiOQp8rle8CnEhTv73BDvz92GKi+uabihilTLXsooHuP66bwIDAQABoEsw
|
||||
SQYJKoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREE
|
||||
GTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBACr4
|
||||
joLa7wXzoT+w4SNDZG3SW8++iKEe+niP3rG1q47lWgSIn4Y3xfVUgLu/RlHAfPCY
|
||||
PSMJx6INsalcqj5I4AWr7t8CVgcXMKbfz98IJJqmQ+DFuE9eJHortDOgELGKzkpc
|
||||
i9cg6uUUjLXJ0+OLS2tIVHy1lS8UMwI8gV/7J4x05bofDrTWyZgNTH75z7G6QWkx
|
||||
wC3BnfXHLagCgJFgNI/LPE1AFfhbScx98M+r3kiRJwdJF40NMJzL68ng4XyFScCA
|
||||
V9W5sOTf0Htu9PqOYQxpKjkHGB9WPpIyQ6NX4kcp7OtRqGg1SFQJZLyHy6TkfEID
|
||||
EcU1OYQEAwzIanV2a8s=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDCzCCAfMCAQAwezELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRQwEgYDVQQDDAtjdHJsX2NsaWVudDCCASIwDQYJ
|
||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALGXmeb1l8EjH6EbDgY8UU66MFB42THj
|
||||
A6DwHRaU8TVaGUqM0HUwA6o1oOuDDaq0WGExVTW80UnQC9PoGKO630JXAIh1ouLI
|
||||
GLCTRwzuHeDdFqh94w/U8bpt8UmdCwM4B9SAbZNWJtzQlR1bH/7NdujyQHhr064h
|
||||
ESpQeXERt5JD9kEnTaDTBmRBS2Va/piq+O7os8Xdxwm//5CgFJ4mY+Jx2M97brH5
|
||||
vo9gWI2lWHo3MrZS2CryNnYv3KETwpsz7FnSab67sch1yg0Y1ewpjXpytNNvPjDN
|
||||
9FmP2DPcV2pecZur13y5urhv73sOYrFIZeO0c2ZwpPYQ5H11jpEYv0sCAwEAAaBL
|
||||
MEkGCSqGSIb3DQEJDjE8MDowCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIAYDVR0R
|
||||
BBkwF4IJbG9jYWxob3N0hwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQBb
|
||||
+MaqsY2rcoHg107Qc+WyxoKE+jCzZIyPTxTYBx7g6NtRQFhPVoZYKdfMRpKRe9Wa
|
||||
eMsGKbLTBW9WsUsYNNJhQmDDfgWkWP1mmL5Q8ZkC22CPnsarx/8XjERe1fSbK8/g
|
||||
BvowJgoacymwr2XkfT8a8q/ZVP4htXpAmbJ4tMKxR/YbsbwttOkKlW9hPrGOyU5Q
|
||||
S6y5eN3PWM+B6VGNLWZC+yowQWyQOtXCWWjbuwHD5sPO6PItZ423E+8h4hyc7BOk
|
||||
kIJbkJF9uHBsBHpm4qWnRaiB0CDhvn71Nm/I5zul+cpEi9Ean6X1nmp+A96dnqU/
|
||||
DjNmWl4GQUmK+0vFi47w
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDBDCCAewCAQAwdDELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMQ0wCwYDVQQDDARjdHJsMIIBIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAQ8AMIIBCgKCAQEAsZeZ5vWXwSMfoRsOBjxRTrowUHjZMeMDoPAdFpTx
|
||||
NVoZSozQdTADqjWg64MNqrRYYTFVNbzRSdAL0+gYo7rfQlcAiHWi4sgYsJNHDO4d
|
||||
4N0WqH3jD9Txum3xSZ0LAzgH1IBtk1Ym3NCVHVsf/s126PJAeGvTriERKlB5cRG3
|
||||
kkP2QSdNoNMGZEFLZVr+mKr47uizxd3HCb//kKAUniZj4nHYz3tusfm+j2BYjaVY
|
||||
ejcytlLYKvI2di/coRPCmzPsWdJpvruxyHXKDRjV7CmNenK0028+MM30WY/YM9xX
|
||||
al5xm6vXfLm6uG/vew5isUhl47RzZnCk9hDkfXWOkRi/SwIDAQABoEswSQYJKoZI
|
||||
hvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXggls
|
||||
b2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAK2KV6DHNg3X
|
||||
6/5BVvwrw/xShn6JsegGzmryhI5KulPUtZxT1ug8zlOHlX8tocv3A6rnD9U/qb/H
|
||||
X3zF9InHoMqMNZzM5HAYW6soDNGVdDzMAdUgOHzxhKpIjWP1+nrHzhLuSYZT9cAl
|
||||
eGgo/75rjF8KP4F7X5ApjQ3lTG+prov+qQBGQKWMwtlcpFvSngI+nt+P5HB1MZhK
|
||||
uG2h183j5fGOShHabePH/fU6i2XvoQ7MyQSSD2kmarYcyPvVlV1q3+aV+LUYGFhN
|
||||
FBhcnx3zwJmgGUBRKO2wEGmiwl2NGrsgWFP7OpvGj75Mrf8olrC68nCQMbiXJlAF
|
||||
iF9lnavVuAU=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDBzCCAe8CAQAwdzELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRAwDgYDVQQDDAdkb3R6ZWV0MIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtMRtlGukei2+nYGjLbgvSn2JNZO7HGm2Tbh4
|
||||
/VfZ9GJquE4iyGoRenNgyEP1LdoBkYlFGrerxO9cOR4o2iPNg1IhnOp96SxPIE5o
|
||||
gg7pfU9waewlOhULjBwdPDa/cmBIwV80eDX6X7jAsSWtCxnaB7QwTJNRzM0I9456
|
||||
QKEpzrOHv9kEUzeaulD/T5eFGRAUEES1h1JdVp+Ay6ZzbE4n208VdNEDV1bm61VQ
|
||||
5RSbzCRTvoIE2xBwt8YtBlulz4aof/Wm0dR5zzcQqXeNrU4W3jwpzycSEyop5nBo
|
||||
YrWmjg6r8oZ7PVPTMD+AsBFfzCecrTGCOSdHNWf+p5F1KLvZiwIDAQABoEswSQYJ
|
||||
KoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAX
|
||||
gglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAItwmLYp
|
||||
5IVaWIKVm7KiNziSAUlETSm3pFN+GSo0k029XIn2jxMJ1nflr5rSTIa1PuB7xHI9
|
||||
T8rMSWreJsfRZoNyi+VPom+ZMCy8g7VWBYW6FS6wqg8U+bErLIvd4MyV/Ke6MiRA
|
||||
9/sqJMHuN+2MC3oWR38O8cgclWur7najVbIX+3P+Ucq93qtrWaVarVzfO1STtNmL
|
||||
zocAH5BbaOTQojdDzTTMlyrRM2ZVqAfDR9tGprEWxxW1tF4xFk3oh3sEWDhGiH3x
|
||||
vwXgSS2MoY7U6j+gXqXTODvhTZPD75BCepIItCOOLxUbCVlIzyPGf9YqtTpNIAG0
|
||||
xnYiEbwg6noBKR4=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDDjCCAfYCAQAwfjELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRcwFQYDVQQDDA5kb3R6ZWV0LXNlcnZlcjCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTEbZRrpHotvp2Boy24L0p9iTWT
|
||||
uxxptk24eP1X2fRiarhOIshqEXpzYMhD9S3aAZGJRRq3q8TvXDkeKNojzYNSIZzq
|
||||
feksTyBOaIIO6X1PcGnsJToVC4wcHTw2v3JgSMFfNHg1+l+4wLElrQsZ2ge0MEyT
|
||||
UczNCPeOekChKc6zh7/ZBFM3mrpQ/0+XhRkQFBBEtYdSXVafgMumc2xOJ9tPFXTR
|
||||
A1dW5utVUOUUm8wkU76CBNsQcLfGLQZbpc+GqH/1ptHUec83EKl3ja1OFt48Kc8n
|
||||
EhMqKeZwaGK1po4Oq/KGez1T0zA/gLARX8wnnK0xgjknRzVn/qeRdSi72YsCAwEA
|
||||
AaBLMEkGCSqGSIb3DQEJDjE8MDowCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIAYD
|
||||
VR0RBBkwF4IJbG9jYWxob3N0hwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQCwsVa3ljYFd8KchIahQacOvnj1MpxqiZS2NdlkA+JfMlfmArPkuBYphb1p2vWY
|
||||
sfnvoyQ7VtqGsb3zesQKlq4eN6RdmwPA1FjntnurqaNucfTpX9HwiNlmDefHFlTI
|
||||
0L8MF25EJ7IDcuApThG5qGb1NVYxtaR8SZOfGahkr3xXKI1uHosyVPIET/pDQ85f
|
||||
bCmBcPt2327S2VW596czfdmO9Aw8AuI9L1BLcKlY/m3xAq2U8g3QG3aB54PvApFl
|
||||
86BMXfqvpcJL+LGGbNE4eYM3TlH+4JRQlAgYJ//Tep0/QynkJro9te121DYYLvmy
|
||||
yEj1Cz/atugjFmC1wCcWC5qY
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIFMDCCAxgCAQAwgZ8xCzAJBgNVBAYTAlVTMRcwFQYDVQQIDA5Ob3J0aCBDYXJv
|
||||
bGluYTESMBAGA1UEBwwJQ2hhcmxvdHRlMRMwEQYDVQQKDApOZXRGb3VuZHJ5MSkw
|
||||
JwYDVQQLDCBOZXRGb3VuZHJ5IENlcnRpZmljYXRlIEF1dGhvcml0eTEjMCEGA1UE
|
||||
AwwaTmV0Rm91bmRyeSBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQCxvUQ+ExTB5L1amNPsvnjEA6Zmq6Anp+FKsV8tTA1TLXva
|
||||
r4BK9lOlPXMog9xmkaY8HdNfZsdoBHrsFtGRRHXUmBYTdTz4WwatiY9m1oozp+Dw
|
||||
yHRZnjWgxhA0nJCLE6S2uCp/JvImhPk95PkADtBCZ3yaS7Zf2eQC7qBY9/acc1zt
|
||||
J5B2KObJBBpUreirJrE7NbOxT9dt8wTP85uR59TGC3lnqOUrTFxbRD5CC1rAwotS
|
||||
K6jqhtZE9yXseb1LN7xclLmlu9LkmRSzPGhFm4NUdnKWuUcikD8gv4Ge9L4ztI/b
|
||||
xRZ72ySu/+zoAKkm248nURh/l9qS6A6ljuL6Grtg2L/9yxtzj1COfY6222tHslxN
|
||||
odQRTUj+1BtAYC02QjikmNFVR0NrBAVCVYdkPUI6LE0sSuzYfMAjTQOEutjpIohM
|
||||
j+SM3RfHTXRd0xx19rLQ8tabpHDGJGYxAUvgY0gLz3k0XWrrFXhbitaCpQ2Vy8qn
|
||||
L6LVyFalFtQd7Xq6XSqHXR9wRKtG8BteflitAkuvBtKv7zm5s3yVh00sTSqDZwhd
|
||||
mVSKVqtlnNaCG0J74qRSmN9G4CL8Kp9LA0rdBcR95UQrpLj2Yd5J6Q6LMUjDt+YO
|
||||
ELP29fAw6duvJFIsQmSzSAhFxINUKFeF4CoL3zLiRxB2eI1YWeoleioD6utKiQID
|
||||
AQABoEswSQYJKoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAg
|
||||
BgNVHREEGTAXgglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQAD
|
||||
ggIBAADmvwgKE//IQfLADi9rlDUBHS+poNT3na2WKaMwRswdSp0FOqWjoIKZmfg8
|
||||
zSMXnszQ7Q4kj+QpzzaHQVBj9tQFLN44NntWMfmU9Eh7gNFZG+0ShfSnO5WnC28u
|
||||
5c2yxls1G1CwHtivRHdRr7kut7w9IbnPe68Wm0/P1LiOQqQJvKFCVIlmFQCkDJ+A
|
||||
EWppvfEd51YeHMl69UuUAiPZFPAw+HBxbyQiTtB8hzJqkwyqJEhY7+UbFryyk4KM
|
||||
E5nUqyMJI3BnPZ943nR9fx8yH7R28n0m7lGQGdTLhxxVB2aZG1ko/AgteODQhSUy
|
||||
cPrN7jWoE7sSOWOZIGgeGVrkm6TxCytjZZGGjnA2uSLGxHgpuUIqP45YDUIu9vvx
|
||||
mZXVILbANzZ4kk8evoCyVrXBpX+ODj4HK/ApSb91ZJOXAvczKTP+g7bSbnXWaqkn
|
||||
kFc//MzVuVC455eym+4X6MulNYAe/SIhQitzLc0l1rHx2QvvDRAnMkeGVmGEVA2D
|
||||
sJVmPS1pnNy9X/S1O1kgRxVeJ59ymnMidYDOgNcW3pPN9ScJs3lTBN9eYJyTQNic
|
||||
OClNyP3UOr0bDi3ACIWoPjBzL2JrC94pH5xxfwfm2FMjqOLYudnqQqkYYvWs6I3O
|
||||
TIyUkMfuZWSlkGrYhMABX9yHaJCJLEFwSP6ELQEfGa0L/ww6
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIDBzCCAe8CAQAwdzELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
|
||||
aW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkxFDAS
|
||||
BgNVBAsMC1ppdGkgRmFicmljMRAwDgYDVQQDDAdtZ210LWd3MIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtJU/MT5Om7hLHOj+u8f+rBlzdx6xcQc399Fd
|
||||
6kLywH5m+jPc6VWrM0r6B+rrTMvxud1XvrwFQ5RZrYXvGkMqWTWX5ZVQeXOe+UcB
|
||||
VhFKRx7F7V2mRLQiwgCswzWBsN00pq6Wee104GX54mj9nrovb/V4kX1q1NJrR0rb
|
||||
EwIG8gceJGT5xt1bHsMpd2QXDqZG6s4oX4ib0QItxs2wNY+7YUuA996Je+6uihD/
|
||||
es2m4wkpjKb/snMEE1gResXAzGfLjBAxoCO7UlSC6wlrxnRsvTMYLWV9LuLLc5Pm
|
||||
zF9crMIU5LSKYIu6uNeWeuetco7QfZmyxsq74UNBlr5Z5tRRGQIDAQABoEswSQYJ
|
||||
KoZIhvcNAQkOMTwwOjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAX
|
||||
gglsb2NhbGhvc3SHBH8AAAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggEBAGP3liiH
|
||||
ezmKbo4Jy02TBJVhHtJrv2X8QYQ//oYUs8aJOuhMTGP6yD7eUJ9eUR+JEvZQA44O
|
||||
llSNrCqgt55LctIpGv60SZfpylaQ7gvKBk+zWJXao7+ZYvmrEebQlUY7opgU2SDm
|
||||
bmsXAEhQth70+dV02XseHeKw4SVFrjisDOrOgjz/JJtYHFyDnf5ec5m+cLSZH24V
|
||||
uE1Lny8sdb3+6pgxEwTJJCI+zzQDCBRPX9LvQhJBISAEeIn4rAj8yXwF6q7jHGle
|
||||
ePoVQt9tb9Zy1hIcHAYOofA4PioNIxK2/UhMRsy1XdDV4bidlzAY8Gxctz4E8nGK
|
||||
xzB604/xUwPyLwE=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,19 @@
|
||||
V 280515170150Z 1000 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=ctrl
|
||||
V 280515170307Z 1001 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=ctrl_client
|
||||
V 280515170427Z 1002 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r1
|
||||
V 280515170459Z 1003 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r1_client
|
||||
V 280515170610Z 1004 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r2
|
||||
V 280515170623Z 1005 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r2_client
|
||||
V 280616192448Z 1006 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=mgmt-gw
|
||||
V 280806180805Z 1007 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r3
|
||||
V 280806180939Z 1008 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r3_client
|
||||
V 280810192725Z 1009 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=001-server
|
||||
V 280810192736Z 100A unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=002-server
|
||||
V 280810192749Z 100B unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=003-server
|
||||
V 280810192804Z 100C unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=004-server
|
||||
V 280810192840Z 100D unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=001
|
||||
V 280810192903Z 100E unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=002
|
||||
V 280810192913Z 100F unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=003
|
||||
V 280810192924Z 1010 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=004
|
||||
V 280810194440Z 1011 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=dotzeet
|
||||
V 280810194501Z 1012 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=dotzeet-server
|
||||
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
@@ -0,0 +1 @@
|
||||
unique_subject = yes
|
||||
@@ -0,0 +1,18 @@
|
||||
V 280515170150Z 1000 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=ctrl
|
||||
V 280515170307Z 1001 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=ctrl_client
|
||||
V 280515170427Z 1002 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r1
|
||||
V 280515170459Z 1003 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r1_client
|
||||
V 280515170610Z 1004 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r2
|
||||
V 280515170623Z 1005 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r2_client
|
||||
V 280616192448Z 1006 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=mgmt-gw
|
||||
V 280806180805Z 1007 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r3
|
||||
V 280806180939Z 1008 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=r3_client
|
||||
V 280810192725Z 1009 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=001-server
|
||||
V 280810192736Z 100A unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=002-server
|
||||
V 280810192749Z 100B unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=003-server
|
||||
V 280810192804Z 100C unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=004-server
|
||||
V 280810192840Z 100D unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=001
|
||||
V 280810192903Z 100E unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=002
|
||||
V 280810192913Z 100F unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=003
|
||||
V 280810192924Z 1010 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=004
|
||||
V 280810194440Z 1011 unknown /C=US/ST=North Carolina/L=Charlotte/O=NetFoundry/OU=Ziti Fabric/CN=dotzeet
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEuDCCAqCgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDUxODE3MDE1MFoX
|
||||
DTI4MDUxNTE3MDE1MFowdDELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQ0wCwYDVQQDDARjdHJsMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsZeZ5vWXwSMfoRsOBjxRTrowUHjZMeMDoPAd
|
||||
FpTxNVoZSozQdTADqjWg64MNqrRYYTFVNbzRSdAL0+gYo7rfQlcAiHWi4sgYsJNH
|
||||
DO4d4N0WqH3jD9Txum3xSZ0LAzgH1IBtk1Ym3NCVHVsf/s126PJAeGvTriERKlB5
|
||||
cRG3kkP2QSdNoNMGZEFLZVr+mKr47uizxd3HCb//kKAUniZj4nHYz3tusfm+j2BY
|
||||
jaVYejcytlLYKvI2di/coRPCmzPsWdJpvruxyHXKDRjV7CmNenK0028+MM30WY/Y
|
||||
M9xXal5xm6vXfLm6uG/vew5isUhl47RzZnCk9hDkfXWOkRi/SwIDAQABozwwOjAJ
|
||||
BgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAgBgNVHREEGTAXgglsb2NhbGhvc3SHBH8A
|
||||
AAGHBAAAAAAwDQYJKoZIhvcNAQELBQADggIBAGH1o/uGn8QdwnM9LyoGfaDKCLYZ
|
||||
p2w+9Bhpbm1RcOgg8Srw6yJHQHrDJgVAH6YYDaueS1TTiUNOUDmHLBuX4AGPga6h
|
||||
8sxVsB0faYqM82yDXO/wQdw5FmcvBNFpchK5R72L7NSRshdq/VUL+FsWdQw58uLn
|
||||
s6QDfMme3fU0WRQ5vAkSEm057BKeBXviRT9xNcnYMTlqZaQE2pEdzPG8xicBJNvL
|
||||
V5zP4HOi63/it2Tv1M2YXVcriBXJkx023CHKZ4tm2enqVofZLyjvzqLTeNuJc0jV
|
||||
zwjBpp4hG/dNc4p9kl1fQOcd7N6EfBggQy3f89J2W5X4AXBgCjxcubj3pg2q2qV6
|
||||
83d45xD4K1HJFRlgpxg26Z/e09GL4yUdST77elv+SKaYNSOuyzOu+IoBv8GHEnH4
|
||||
QqbW8/56taQ9bUSGw+r8yvv7uw69bPig1OnAc9hZ4cc4yOVnzW7L98OeKae/XR5I
|
||||
Ewv1kvrv7ISsYKjSOIGtcQLZ2/xoHsf3xJrZ14viG2OCoRj93P18xod2yi2Vgr2Y
|
||||
uBdknNjcV3SVv4dsbU8bMSHTThlQM5qrPZHlnbQjncWwXesLCUqeL0O7Tzz6lGT6
|
||||
rpD1hgO9R3c9Vmqa5g+Anqbv50YTt+57M5NcLtHTAdfWIOa92LZF8FOpqTE405A/
|
||||
xLJv+nDUo0iraA3w
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvzCCAqegAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDUxODE3MDMwN1oX
|
||||
DTI4MDUxNTE3MDMwN1owezELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMRQwEgYDVQQDDAtjdHJsX2NsaWVudDCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGXmeb1l8EjH6EbDgY8UU66MFB4
|
||||
2THjA6DwHRaU8TVaGUqM0HUwA6o1oOuDDaq0WGExVTW80UnQC9PoGKO630JXAIh1
|
||||
ouLIGLCTRwzuHeDdFqh94w/U8bpt8UmdCwM4B9SAbZNWJtzQlR1bH/7NdujyQHhr
|
||||
064hESpQeXERt5JD9kEnTaDTBmRBS2Va/piq+O7os8Xdxwm//5CgFJ4mY+Jx2M97
|
||||
brH5vo9gWI2lWHo3MrZS2CryNnYv3KETwpsz7FnSab67sch1yg0Y1ewpjXpytNNv
|
||||
PjDN9FmP2DPcV2pecZur13y5urhv73sOYrFIZeO0c2ZwpPYQ5H11jpEYv0sCAwEA
|
||||
AaM8MDowCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwIAYDVR0RBBkwF4IJbG9jYWxo
|
||||
b3N0hwR/AAABhwQAAAAAMA0GCSqGSIb3DQEBCwUAA4ICAQCOuukYQ6cgstNbbYVe
|
||||
xJsKRRdLqIdkHthH4dCtOaB5MxIH+n8CpAWwZcepbf6/RsPnsE54kVw1rJwgbWxY
|
||||
Leyl5iVyuSzQ2NtiJOJAqHiKWLi965bs8e7rHEK/k6AnRpCaqXWZKUMSgFJ1wyLn
|
||||
B602AE9OHkXgXumNyjE1IVP30BKd4DYOtB33Z3J77F3UIcaDcaU6IJThVO4VmLle
|
||||
Fv4Vnw8iMvMfAy0FuwAahHEshFW53HW5ZSoi4a8BcwRNy17xQpGKjAOw4naOWe+H
|
||||
A1T2ayKAGMA9jFcXKn7+lfTSgYdwmhKUGMQTlsqdpHktvBjQUFyPcvMt99AI5Amy
|
||||
0MNaTQ/tXr6lb3ws40YFOqjD7VKhJcoqcwHqX0xXfI7X0zYNY3DGVTkvUnWTDcle
|
||||
pF3O6ZKllbL6LKFkJXJRVhqOuomsAuho+vi2A3la/PBcF48z4M0aH8j6HGftzgNe
|
||||
AS0Ys5iOqJhr1qdBils6hSL84cCsNYyHG+V95jdwNepSOOBqc5+OydFoUjFQScK3
|
||||
Q3bjV7T59N11yCMOJzukrJorGtUr/nRdQPcEsCQlvGj60+kx3FEygBIpeiZy5AAS
|
||||
h7KoWY1Sh2l4YW0Oh4AmeLDY0ryBXDafgAuwGFh7zENLBjDitdpFSuo+d/YksOnG
|
||||
CR1KiiHDLLh/aqOiR7T0/HKFqg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,28 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEtjCCAp6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVT
|
||||
MRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTETMBEGA1UECgwKTmV0Rm91bmRyeTEp
|
||||
MCcGA1UECwwgTmV0Rm91bmRyeSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIzAhBgNV
|
||||
BAMMGk5ldEZvdW5kcnkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDUxODE3MDQyN1oX
|
||||
DTI4MDUxNTE3MDQyN1owcjELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENh
|
||||
cm9saW5hMRIwEAYDVQQHDAlDaGFybG90dGUxEzARBgNVBAoMCk5ldEZvdW5kcnkx
|
||||
FDASBgNVBAsMC1ppdGkgRmFicmljMQswCQYDVQQDDAJyMTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAMqCBmQ1w36rpLpVXO+qhcbYvGWh7TiVYC2eD1XB
|
||||
jSuW1BTeTRV129Obhus4IW81YIGC6dZchH828eQbp8VrgCWPIVbdHvXEFcbppE/V
|
||||
7BSfG3DFMRICWTyTMHb3bDGhvQl+fiCf4Z3YHGa/JE3emBiTFJK5ohBu1BIIy7gb
|
||||
25rPaiWcrrrWyCq793UQOFv7pQ5C602xHS4G1EAfn/pwXv/jGQoAn7nQY2pzNHOa
|
||||
/psMp/TRuqSKoeh8phkYxRzz9GrhMl3DnhiYC8M62mmWUWTxHyimMtXsOiJptM2m
|
||||
S9Jg8FNb2esdRqJBO7Ms+X/P0wgs90SCYKntXxjttd0PmxsCAwEAAaM8MDowCQYD
|
||||
VR0TBAIwADALBgNVHQ8EBAMCBeAwIAYDVR0RBBkwF4IJbG9jYWxob3N0hwR/AAAB
|
||||
hwQAAAAAMA0GCSqGSIb3DQEBCwUAA4ICAQB9KgzI2wIcX/+u1w1T7teTIoyvnDLD
|
||||
x2X2+ajFUrKsHIQJYz2Gu3ds5VBfWST9vOIDQzv7LWi3uIl/15WkvPUSgdhCzy7W
|
||||
n0YH7rybxF3cvMrytctg4z4/xflIjZq/7IYsncqNZKSIbZNP46RNzfJfIPHA58rO
|
||||
Tb/Sq8k57jPOGePOlPXuyUKwaGuKkmGdvz566PY7A2O7y5JmuJx2o9xkSJM9LVRT
|
||||
X9Ff5ii9PjBALNOtraI7FtNAzMZ/oPiAw4B3MxyoH6WXQyfnd9mLLU3Rrkhl5rA+
|
||||
/inQ/HZpv93evu7E4nniwq1bCZTNF4kgIGENdPewWdr+yhcCfm2qYsUC4gStZHCW
|
||||
FTeV9e7CdfOA5Oj5EsCRWMYUnlNEXwzugBPB9tX7iYFIHL85PWCyuGKx9rtlQ/EP
|
||||
7DRIoZibdKZGYAq1XtjSHeYzG3OXxq40o4D0f+HkQnsGl5wVF2IIM5ll8tuxKrRd
|
||||
WiWbEmLFNEJ2wvv63oCaZCKRJxXxpnHif9E+ufOSMTySSyqHMPuSjRuIVwmundD+
|
||||
IwGHndcHWSb1hzKPvDUd+OBvM9PZ2A6IOL7XZaRaV0x5O58Fpkn+QU8CXnbbOxRE
|
||||
D2tysrka4vnHmLDgdM0IKJd05gp8QWpW36Kg0JYckMj0fWWJ1EFPBOJch4HWIYd9
|
||||
7aTY4K+wdj1KOg==
|
||||
-----END CERTIFICATE-----
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user