Skip to content

Commit

Permalink
deployment: use service prefix for simplified path routing
Browse files Browse the repository at this point in the history
This commit adds a service prefix to api paths. Prior to this commit
adding a new end point to ClairV4 would require operations to
reconfigure their infrastructure.

Signed-off-by: ldelossa <ldelossa@redhat.com>
  • Loading branch information
ldelossa authored and ldelossa committed Sep 22, 2020
1 parent f00698b commit bc4c324
Show file tree
Hide file tree
Showing 15 changed files with 102 additions and 127 deletions.
8 changes: 4 additions & 4 deletions Documentation/concepts/notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type VulnSummary struct {
When you configure notifier for webhook delivery you provide the service with the following pieces of information:
* A target URL where the webhook will fire
* The callback URL where the notifier may be reached including its API path
* e.g. "http://clair-notifier/api/v1/notifications"
* e.g. "http://clair-notifier/notifier/api/v1/notifications"

When the notifier has determined an updated security database has changed the affected status of an indexed manifest, it will deliver the following JSON body to the configured target:
```json
Expand All @@ -72,7 +72,7 @@ The URL returned in the callback field brings the client to a paginated result.
The callback endpoint specification follows:

```go
GET /api/v1/notification/{id}?[page_size=N][next=N]
GET /notifier/api/v1/notification/{id}?[page_size=N][next=N]
{
page: {
size: int, // maximum number of notifications in the response
Expand All @@ -99,10 +99,10 @@ When the final page is served to the client the returned "page" data structure w
Therefore the following loop is valid for obtaining all notifications for a notification id in pages of a specified size.

```
{ page, notifications } = http.Get("http://clairv4/api/v1/notifications/{id}?page_size=1000")
{ page, notifications } = http.Get("http://clairv4/notifier/api/v1/notifications/{id}?page_size=1000")
while (page.Next != None) {
{ page, notifications } = http.Get("http://clairv4/api/v1/notifications/{id}?next={page.Next},page_size=1000")
{ page, notifications } = http.Get("http://clairv4/notifier/api/v1/notifications/{id}?next={page.Next},page_size=1000")
}
```

Expand Down
12 changes: 6 additions & 6 deletions Documentation/howto/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ When the load balancer encounters a particular path prefix it must send those re

For example, this is how we configure Traefik in our local development environment:
```
"traefik.enable=true"
"traefik.http.routers.notifications.entrypoints=clair"
"traefik.http.routers.notifications.rule=PathPrefix(`/api/v1/notification`)"
"traefik.http.routers.notifications.service=notifications"
"traefik.http.services.notifications.loadbalancer.server.port=6000"
- "traefik.enable=true"
- "traefik.http.routers.notifier.entrypoints=clair"
- "traefik.http.routers.notifier.rule=PathPrefix(`/notifier`)"
- "traefik.http.routers.notifier.service=notifier"
- "traefik.http.services.notifier.loadbalancer.server.port=6000"
```

This configuration is saying "take any paths prefixes of /api/v1/notification and send them to the notifier services on port 6060"
This configuration is saying "take any paths prefixes of /notifier/ and send them to the notifier services on port 6000"

Every load balancer will have their own way to perform path routing. Check the documentation for your infrastructure of choice.
2 changes: 2 additions & 0 deletions Documentation/howto/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,5 @@ will rip the entire environment down.
The most common issue encountered when standing up the dev environment is port conflicts. Make sure that you do not have any other processes listening on any of the ports outlined above.

The second issue you may face is your Docker resource settings maybe too constrained to support the local dev stack. This is typically seen on Docker4Mac since a VM is used with a specific set of resources configured. See [Docker For Mac Manual](https://docs.docker.com/docker-for-mac/) for instructions on how to change these resources.

Lastly, you can view traefik's ui at `localhost:7000`. If traefik is reporting no routers or services its likely SELinux has blocked its access to `/var/run/docker.socket`. Place SELinuse in permissive mode and restart the local development environment.
50 changes: 25 additions & 25 deletions Documentation/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.delete('/api/v1/notification/{notification_id}', headers = headers)
r = requests.delete('/notifier/api/v1/notification/{notification_id}', headers = headers)

print(r.json())

Expand All @@ -63,7 +63,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("DELETE", "/api/v1/notification/{notification_id}", data)
req, err := http.NewRequest("DELETE", "/notifier/api/v1/notification/{notification_id}", data)
req.Header = headers

client := &http.Client{}
Expand All @@ -79,7 +79,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/notification/{notification_id}',
fetch('/notifier/api/v1/notification/{notification_id}',
{
method: 'DELETE',

Expand All @@ -93,7 +93,7 @@ fetch('/api/v1/notification/{notification_id}',

```

`DELETE /api/v1/notification/{notification_id}`
`DELETE notifier/api/v1/notification/{notification_id}`

Issues a delete of the provided notification id and all associated notifications.
After this delete clients will no longer be able to retrieve notifications.
Expand Down Expand Up @@ -139,7 +139,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.get('/api/v1/notification/{notification_id}', headers = headers)
r = requests.get('/notifier/api/v1/notification/{notification_id}', headers = headers)

print(r.json())

Expand All @@ -160,7 +160,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/api/v1/notification/{notification_id}", data)
req, err := http.NewRequest("GET", "/notifier/api/v1/notification/{notification_id}", data)
req.Header = headers

client := &http.Client{}
Expand All @@ -176,7 +176,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/notification/{notification_id}',
fetch('/notifier/api/v1/notification/{notification_id}',
{
method: 'GET',

Expand All @@ -190,7 +190,7 @@ fetch('/api/v1/notification/{notification_id}',

```

`GET /api/v1/notification/{notification_id}`
`GET notifier/api/v1/notification/{notification_id}`

By performing a GET with a notification_id as a path parameter the client
will retrieve a paginated response of notifcation objects
Expand Down Expand Up @@ -299,7 +299,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.post('/api/v1/index_report', headers = headers)
r = requests.post('/indexer/api/v1/index_report', headers = headers)

print(r.json())

Expand All @@ -321,7 +321,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("POST", "/api/v1/index_report", data)
req, err := http.NewRequest("POST", "/indexer/api/v1/index_report", data)
req.Header = headers

client := &http.Client{}
Expand Down Expand Up @@ -354,7 +354,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/index_report',
fetch('/indexer/api/v1/index_report',
{
method: 'POST',
body: inputBody,
Expand All @@ -368,7 +368,7 @@ fetch('/api/v1/index_report',

```

`POST /api/v1/index_report`
`POST indexer/api/v1/index_report`

By submitting a Manifest object to this endpoint Clair will fetch the
layers, scan each layer's contents, and provide an index of discovered
Expand Down Expand Up @@ -481,7 +481,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.get('/api/v1/index_report/{manifest_hash}', headers = headers)
r = requests.get('/indexer/api/v1/index_report/{manifest_hash}', headers = headers)

print(r.json())

Expand All @@ -502,7 +502,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/api/v1/index_report/{manifest_hash}", data)
req, err := http.NewRequest("GET", "/indexer/api/v1/index_report/{manifest_hash}", data)
req.Header = headers

client := &http.Client{}
Expand All @@ -518,7 +518,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/index_report/{manifest_hash}',
fetch('/indexer/api/v1/index_report/{manifest_hash}',
{
method: 'GET',

Expand All @@ -532,7 +532,7 @@ fetch('/api/v1/index_report/{manifest_hash}',

```

`GET /api/v1/index_report/{manifest_hash}`
`GET indexer/api/v1/index_report/{manifest_hash}`

Given a Manifest's content addressable hash an IndexReport will
be retrieved if exists.
Expand Down Expand Up @@ -628,7 +628,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.get('/api/v1/index_state', headers = headers)
r = requests.get('/indexer/api/v1/index_state', headers = headers)

print(r.json())

Expand All @@ -649,7 +649,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/api/v1/index_state", data)
req, err := http.NewRequest("GET", "/indexer/api/v1/index_state", data)
req.Header = headers

client := &http.Client{}
Expand All @@ -665,7 +665,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/index_state',
fetch('/indexer/api/v1/index_state',
{
method: 'GET',

Expand All @@ -679,7 +679,7 @@ fetch('/api/v1/index_state',

```

`GET /api/v1/index_state`
`GET indexer/api/v1/index_state`

The index state endpoint returns a json structure indicating the
indexer's internal configuration state.
Expand Down Expand Up @@ -729,7 +729,7 @@ headers = {
'Accept': 'application/json'
}

r = requests.get('/api/v1/vulnerability_report/{manifest_hash}', headers = headers)
r = requests.get('/matcher/api/v1/vulnerability_report/{manifest_hash}', headers = headers)

print(r.json())

Expand All @@ -750,7 +750,7 @@ func main() {
}

data := bytes.NewBuffer([]byte{jsonReq})
req, err := http.NewRequest("GET", "/api/v1/vulnerability_report/{manifest_hash}", data)
req, err := http.NewRequest("GET", "/matcher/api/v1/vulnerability_report/{manifest_hash}", data)
req.Header = headers

client := &http.Client{}
Expand All @@ -766,7 +766,7 @@ const headers = {
'Accept':'application/json'
};

fetch('/api/v1/vulnerability_report/{manifest_hash}',
fetch('/matcher/api/v1/vulnerability_report/{manifest_hash}',
{
method: 'GET',

Expand All @@ -780,7 +780,7 @@ fetch('/api/v1/vulnerability_report/{manifest_hash}',

```

`GET /api/v1/vulnerability_report/{manifest_hash}`
`GET matcher/api/v1/vulnerability_report/{manifest_hash}`

Given a Manifest's content addressable hash a VulnerabilityReport
will be created. The Manifest **must** have been Indexed first
Expand Down Expand Up @@ -1021,7 +1021,7 @@ PagedNotifications
```json
{
"notification_id": "269886f3-0146-4f08-9bf7-cb1138d48643",
"callback": "http://clair-notifier/api/v1/notifications/269886f3-0146-4f08-9bf7-cb1138d48643"
"callback": "http://clair-notifier/notifier/api/v1/notifications/269886f3-0146-4f08-9bf7-cb1138d48643"
}

```
Expand Down
6 changes: 3 additions & 3 deletions config.yaml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ notifier:
# webhook, amqp, stomp
webhook:
target: "http://webhook/"
callback: "http://clair-notifier/api/v1/notifications"
callback: "http://clair-notifier/notifier/api/v1/notifications"
amqp:
exchange:
name: ""
Expand All @@ -58,15 +58,15 @@ notifier:
uris: ["amqp://user:pass@host:10000/vhost"]
direct: false
routing_key: "notifications"
callback: "http://clair-notifier/api/v1/notifications"
callback: "http://clair-notifier/notifier/api/v1/notifications"
tls:
root_ca: "optional/path/to/rootca"
cert: "madatory/path/to/cert"
key: "madatory/path/to/key"
stomp:
desitnation: "notifications"
direct: false
callback: "http://clair-notifier/api/v1/notifications"
callback: "http://clair-notifier/notifier/api/v1/notifications"
login:
login: "username"
passcode: "passcode"
Expand Down
26 changes: 13 additions & 13 deletions contrib/openshift/manifests/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,19 @@ objects:
service: matcher
app: clair
#
# index_report route
# indexer
#
- kind: Route
apiVersion: route.openshift.io/v1
metadata:
name: clair-index-report
name: clair-indexer
namespace: clair
labels:
app: clair
component: indexer
spec:
host: clair.stage.quay.io
path: /api/v1/index_report
path: /indexer
to:
kind: Service
name: clair-indexer
Expand All @@ -210,43 +210,43 @@ objects:
targetPort: ${{INTROSPECTION_PORT}}
wildcardPolicy: None
#
# index_state route
# matcher route
#
- kind: Route
apiVersion: route.openshift.io/v1
metadata:
name: clair-index-state
name: clair-matcher
namespace: clair
labels:
app: clair
component: indexer
component: matcher
spec:
host: clair.stage.quay.io
path: /api/v1/index_state
path: /matcher
to:
kind: Service
name: clair-indexer
name: clair-matcher
weight: 100
port:
targetPort: ${{INTROSPECTION_PORT}}
wildcardPolicy: None
#
# vulnerability_report route
# notifier route
#
- kind: Route
apiVersion: route.openshift.io/v1
metadata:
name: clair-vulnerability-report
name: notifier
namespace: clair
labels:
app: clair
component: matcher
component: notifier
spec:
host: clair.stage.quay.io
path: /api/v1/vulnerability_report
path: /notifier
to:
kind: Service
name: clair-matcher
name: clair-notifier
weight: 100
port:
targetPort: ${{INTROSPECTION_PORT}}
Expand Down
Loading

0 comments on commit bc4c324

Please sign in to comment.