Skip to content

Commit d78c229

Browse files
committed
improve output
1 parent eeab2b4 commit d78c229

8 files changed

+215
-275
lines changed

README.md

+14-80
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ Resources of all supported types in all or some of the projects in the GCP organ
1717
## Note: Organization focus
1818

1919
Note that Iris is designed to serve the organization.
20-
* It is not designed around serving a single project (though you can configure that).
21-
* Only one instance of Iris runs at any one time in an organization.
22-
* The organization focus was chosen because labels are used for billing analysis which is typically done on the organization level (even though projects can be associated arbitrarily with billing accounts).
20+
* It is designed to label all projects in the organization (though you can configure that).
21+
* The organization focus was chosen because labels are used for billing analysis which is typically done on the organization level (even though projects can in fact be associated arbitrarily with billing accounts).
2322

2423
## Iris doesn't add new information
2524

@@ -90,7 +89,7 @@ names start `_gcp_`. The part of the function name after `_gcp_` is used for the
9089
[new project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
9190

9291
### Needed roles for deployment
93-
#### Organization-leve roles
92+
#### Organization-level roles
9493

9594
* Here are the required organization-level roles for you, the deployer, to allow the deploy script to set up roles and log sink. (Note that *Organization Owner* is not enough).
9695
* *Organization Role Administrator* so the deployment script can create a custom IAM role for Iris that allows it to get and set labels.
@@ -122,17 +121,14 @@ names start `_gcp_`. The part of the function name after `_gcp_` is used for the
122121
* Optionally configure by editing the config file. ([See more documentation below](#configuration).)
123122

124123
* Now, run `./deploy.sh <PROJECT_ID> `.
125-
* For options, run `deploy.sh -h` for documentation on usage of command-line options.
124+
* For documentation on usage of command-line options, run `deploy.sh -h`
126125

127-
* When the labeling occurs
126+
* Choosing when the labeling occurs
128127
* By default, labeling occurs on resource-creation, and also using Cloud Scheduler ("cron"). Each of these types works on certain resource types and not others (see [Supported Google Cloud Labels](#Supported Google Cloud Labels) above), depending on configuration (`config.yaml`).
129128
* Use `-c` switch on `deploy.sh` to label using Cloud Scheduler only.
130129
* Use `-e` switch on `deploy.sh` to label on-event only.
131130
* If you use **both** `-c` and `-e` or **neither**, both types of labeling occur.
132-
* If you change from having Cloud Scheduler labeling to not having it, or vice versa, be sure to deploy both org-level and project-level elements , not just project elements, since this involves the org-level sink.
133-
* Organization-level and project-level elements
134-
* First, note that Iris is an organization-level application. A single instance of Iris labels all projects in an org (unless you limit it by configuration). Iris has architecture elements which are deployed to both the org and the project.
135-
* If you want a person with all permissions to deploy the org-level elements and a person without org-level permissions to redeploy only the project-level elements (e.g. when you change configuration), you can do this with flags on the script. Run `deploy.sh -h`.
131+
136132

137133

138134
# Configuration
@@ -156,6 +152,11 @@ names start `_gcp_`. The part of the function name after `_gcp_` is used for the
156152
# Architecture
157153

158154
* Iris runs in Google App Engine Standard Environment (Python 3).
155+
* Organization-level and project-level elements
156+
* First, note that Iris is an organization-level application.
157+
* A single instance of Iris in one project labels all projects in an org (unless you limit it by configuration).
158+
* Iris has architecture elements which are deployed to both the org and the project.
159+
* If you want a person with all permissions to deploy the org-level elements and a person without org-level permissions to redeploy only the project-level elements (e.g. when you change configuration), you can do this with flags on the script. Run `deploy.sh -h`.
159160
* The Cloud Scheduler "cron" job triggers Iris at configured intervals. See `cron_full.yaml` for config. The GCP Console view for this is in a separate App Engine tab in the Cloud Scheduler view.
160161
* For newly created resources, a Log Sink on the organization level sends all logs for resource creation to a PubSub topic.
161162
* The Log Sink is filtered to include only supported resource types
@@ -169,74 +170,7 @@ names start `_gcp_`. The part of the function name after `_gcp_` is used for the
169170
* For security, these two PubSub subscriptions [use JWT auth](https://cloud.google.com/pubsub/docs/authenticate-push-subscriptions), where the JWT token is verified in the Iris webapp.
170171
* A dead-letter subscription. This is a pull subscription. By default, it just accumulates the messages. You can use it to see statistics, or you can pull messages from it.
171172

172-
# Local Development
173-
174-
## Development tools
175-
176-
* Prerequisites for developing and building.
177-
* See [Installation](#installation)
178-
* Also, for development, set up a virtual env and run `pip3 install -r requirements.txt`
179-
* Run the server locally
180-
* Run `main.py` as an ordinary Flask application as follows:
181-
* To use the command-line,
182-
use `export FLASK_ENV=development;export FLASK_RUN_PORT=8000;export FLASK_DEBUG=1;FLASK_APP=main.py python -m flask run`
183-
* In an interactive development environment, run `main.py`, first setting these environment variables.
184-
* For hands-on debugging
185-
* Use `test_do_label` and `test_label_one` and `test_schedule` to trigger against your localhost dev-server; this should label actual Cloud resources that you have pre-deployed.
186-
* See the `test_...` files for instructions.
187-
188-
## Adding new kinds of labels
189-
190-
Iris adds about twenty kinds of labels. More can be added, but don't add too many: Billing analytics work best when not swamped by excess labels. This is why Iris does not implement all possible labeling, say by automatically copying all fields from each resource into labels.
191-
192-
### Developing new labels for an existing resource type
193-
194-
To add a new label key to an existing resource type, add `_gcp_<LABEL_NAME>` methods (like `_gcp_zone()`) in the relevant file in `/plugins`, following the example of the existing ones. Labels will be added with a key from the function name (`zone` in that example), and a value returned by the function (in our example, the zone identifier).
195-
196-
For example, you might want to add a label identifying the creator of a resource, or add the name of the topic to its subscriptions.
197-
198-
### Supporting new resource types
199-
200-
Iris is easily extensible with plugins, to support labeling of other GCP resources. Use existing files in `/plugins` as
201-
examples.
202-
203-
1. Create a Python file in the `/plugins` directory, holding a subclass of `Plugin`.
204-
205-
a. The filename and class name take the form: `cloudsql.py` and `Cloudsql`. That's lowercase and Titlecase. (Only the
206-
first character is capitalized, even in multiword names.) The two names should be the same except for case.
207-
208-
b. Implement abstract methods from the `Plugin` class.
209-
210-
c. Add `_gcp_<LABEL_NAME>` methods (like `_gcp_zone()`). Labels will be added with a key from the function
211-
name (`zone` in that example), and a value returned by the function
212-
(in our example, the zone identifier).
213-
214-
d. For resources that cannot be labeled on creation (like CloudSQL, which takes too long to initialize), you should
215-
override `is_labeled_on_creation()` and return `False` (though if you don't, the only bad-side effect will be errors
216-
in the logs).
217-
218-
e. For resources with mutable labels (like Disks, for which attachment state may have changed), override `relabel_on_cron()` and return `True`. This will allow Cloud Scheduler to relabel them. (This is because after a resource is created and possibly labeled, so Cloud Scheduler is the way to relabel mutated state.)
219-
220-
2. Add your API to the `required_svcs` in `deploy.sh`.
221-
222-
3. Add your Google Cloud API "methods" to `log_filter` in `deploy.sh`.
223-
* `methodName` is part of the logs generated on creation.
224-
* See examples of such logs in `sample_data` directory.
225-
* E.g., you can see a log sample for bucket creation, in
226-
file `sample_data/storage.buckets.create.log_message.json`. (Or create a bucket and look at the log.)
227-
* In that file you see `"methodName": "storage.buckets.create"`.
228-
229-
4. Add permissions in `iris-custom-role.yaml` to be granted to the Iris custom role.
230-
* This role allows Iris, for each resource type, to list, get, and update.
231-
* ("Update" requires permission `setLabels` where available or permission `update` otherwise.)
232-
* The name of this custom role is `iris3`by default, but may be set by passing env variable `IRIS_CUSTOM_ROLE` in calling `deploy.sh` or `uninstall.sh`
233-
234-
# Testing
235-
236-
## Integration test
237-
238-
`./test_scripts/integration_test.py` creates a Google App Engine app and cloud resources, and tests against them. Run it without parameters for usage instructions.
239-
240-
# Next steps
173+
# Development and Testing
241174

242-
See `TODO.md` and GitHub issues for potential future improvements.
175+
Please see [docs_for_dev_and_testing](./docs_for_dev_and_testing)
176+

deploy.sh

+4-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ deploy_org=
3434
export LABEL_ON_CRON=
3535
export LABEL_ON_CREATION_EVENT=
3636

37-
3837
while getopts 'cepoh' opt; do
3938
case $opt in
4039
c)
@@ -91,7 +90,7 @@ fi
9190

9291
export PROJECT_ID=$1
9392

94-
pip3 install -r requirements.txt >/dev/null
93+
pip3 install -r requirements.txt > /dev/null
9594

9695
# If both -c and -e are not given, then actually act as if both are there.
9796
if [[ "$LABEL_ON_CRON" != "true" ]] && [[ "$LABEL_ON_CREATION_EVENT" != "true" ]]; then
@@ -106,14 +105,13 @@ if [[ "$deploy_org" != "true" ]] && [[ "$deploy_proj" != "true" ]]; then
106105
deploy_proj=true
107106
fi
108107

109-
110-
gcloud projects describe "$PROJECT_ID" >/dev/null|| {
108+
gcloud projects describe "$PROJECT_ID" >/dev/null || {
111109
echo "Project $PROJECT_ID not found"
112110
exit 1
113111
}
114112

115-
#echo "Project ID $PROJECT_ID"
116-
gcloud config set project "$PROJECT_ID"
113+
gcloud auth application-default set-quota-project $PROJECT_ID > /dev/null 2>&1
114+
gcloud config set project "$PROJECT_ID" > /dev/null 2>&1
117115

118116

119117
if [[ "$deploy_org" == "true" ]]; then

docs_for_dev_and_testing.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Iris: Dev and Testing
2+
3+
4+
## Development tools
5+
6+
* Prerequisites for developing and building.
7+
* See [Installation](#installation)
8+
* Also, for development, set up a virtual env and run `pip3 install -r requirements.txt`
9+
* Run the server locally
10+
* Run `main.py` as an ordinary Flask application as follows:
11+
* To use the command-line,
12+
use `export FLASK_ENV=development;export FLASK_RUN_PORT=8000;export FLASK_DEBUG=1;FLASK_APP=main.py python -m flask run`
13+
* In an interactive development environment, run `main.py`, first setting these environment variables.
14+
* For hands-on debugging
15+
* Use `test_do_label` and `test_label_one` and `test_schedule` to trigger against your localhost dev-server; this should label actual Cloud resources that you have pre-deployed.
16+
* See the `test_...` files for instructions.
17+
18+
## Adding new kinds of labels
19+
20+
Iris adds about twenty kinds of labels. More can be added, but don't add too many: Billing analytics work best when not swamped by excess labels. This is why Iris does not implement all possible labeling, say by automatically copying all fields from each resource into labels.
21+
22+
## Developing new labels for an existing resource type
23+
24+
To add a new label key to an existing resource type, add `_gcp_<LABEL_NAME>` methods (like `_gcp_zone()`) in the relevant file in `/plugins`, following the example of the existing ones. Labels will be added with a key from the function name (`zone` in that example), and a value returned by the function (in our example, the zone identifier).
25+
26+
For example, you might want to add a label identifying the creator of a resource, or add the name of the topic to its subscriptions.
27+
28+
## Supporting new resource types
29+
30+
Iris is easily extensible with plugins, to support labeling of other GCP resources. Use existing files in `/plugins` as examples.
31+
32+
1. Create a Python file in the `/plugins` directory, holding a subclass of `Plugin`.
33+
34+
a. The filename and class name take the form: `cloudsql.py` and `Cloudsql`. That's lowercase and Titlecase. (Only the
35+
first character is capitalized, even in multiword names.) The two names should be the same except for case.
36+
37+
b. Implement abstract methods from the `Plugin` class.
38+
39+
c. Add `_gcp_<LABEL_NAME>` methods (like `_gcp_zone()`). Labels will be added with a key from the function
40+
name (`zone` in that example), and a value returned by the function
41+
(in our example, the zone identifier).
42+
43+
d. For resources that cannot be labeled on creation (like CloudSQL, which takes too long to initialize), you should
44+
override `is_labeled_on_creation()` and return `False` (though if you don't, the only bad-side effect will be errors
45+
in the logs).
46+
47+
e. For resources with mutable labels (like Disks, for which attachment state may have changed), override `relabel_on_cron()` and return `True`. This will allow Cloud Scheduler to relabel them. (This is because after a resource is created and possibly labeled, so Cloud Scheduler is the way to relabel mutated state.)
48+
49+
2. Add the relevant Google Cloud API to the `required_svcs` in `deploy.sh`.
50+
51+
3. Add your Google Cloud API "methods" to `log_filter` in `deploy.sh`.
52+
* `methodName` is part of the logs generated on creation.
53+
* See examples of such logs in `sample_data` directory.
54+
* E.g., you can see a log sample for bucket creation, in
55+
file `sample_data/storage.buckets.create.log_message.json`. (Or create a bucket and look at the log.)
56+
* In that file you see `"methodName": "storage.buckets.create"`.
57+
58+
4. Add permissions in `iris-custom-role.yaml` to be granted to the Iris custom role.
59+
* This role allows Iris, for each resource type, to list, get, and update.
60+
* ("Update" requires permission `setLabels` where available or permission `update` otherwise.)
61+
* The name of this custom role is `iris3`by default, but may be set by passing env variable `IRIS_CUSTOM_ROLE` in calling `deploy.sh` or `uninstall.sh`
62+
63+
# Testing
64+
65+
## Integration test
66+
67+
`./test_scripts/integration_test.py` creates a Google App Engine app and cloud resources, and tests against them. Run it without parameters for usage instructions.
68+
69+
# Next steps
70+
71+
See `TODO.md` and GitHub issues for potential future improvements.

scripts/_deploy-org.sh

+10-18
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
#set -x
88
# The following lines must come before set -u
99
if [[ -z "$IRIS_CUSTOM_ROLE" ]]; then IRIS_CUSTOM_ROLE=iris3; fi
10-
if [[ -z "$SKIP_ADDING_IAM_BINDINGS" ]] ; then SKIP_ADDING_IAM_BINDINGS=""; fi
10+
if [[ -z "$SKIP_ADDING_IAM_BINDINGS" ]]; then SKIP_ADDING_IAM_BINDINGS=""; fi
1111
set -u
1212
set -e
1313

1414
LOG_SINK=iris_log
1515

1616
# Get organization id for this project
17-
ORGID=$(gcloud projects get-ancestors $PROJECT_ID --format='value(TYPE,ID)' | awk '/org/ {print $2}')
17+
ORGID=$(gcloud projects get-ancestors "$PROJECT_ID" --format='value(TYPE,ID)' | awk '/org/ {print $2}')
1818

1919
set +e
2020
# Create custom role to run iris
@@ -25,19 +25,17 @@ existing_role=$(gcloud iam roles describe --organization "$ORGID" $IRIS_CUSTOM_R
2525
# 3. For non-existing role, empty-string
2626
if [ -n "$existing_role" ]; then
2727
if [[ "$existing_role" == *"True"* ]]; then # It's a soft-deleted role
28-
gcloud iam roles undelete -q "$IRIS_CUSTOM_ROLE" --organization "$ORGID" >/dev/null
28+
gcloud iam roles undelete -q "$IRIS_CUSTOM_ROLE" --organization "$ORGID" >/dev/null
2929
fi
3030

3131
gcloud iam roles update -q "$IRIS_CUSTOM_ROLE" --organization "$ORGID" --file iris-custom-role.yaml >/dev/null
3232
role_error=$?
33-
3433
else
35-
gcloud iam roles create -q "$IRIS_CUSTOM_ROLE" --organization "$ORGID" --file iris-custom-role.yaml >/dev/null
36-
role_error=$?
34+
gcloud iam roles create -q "$IRIS_CUSTOM_ROLE" --organization "$ORGID" --file iris-custom-role.yaml >/dev/null
35+
role_error=$?
3736
fi
3837

3938
set -e
40-
4139
if [[ "$role_error" != "0" ]]; then
4240
echo "Error in accessing organization.
4341
If you just want to redeploy to the same project,
@@ -52,8 +50,7 @@ fi
5250
gcloud organizations add-iam-policy-binding "$ORGID" \
5351
--member "serviceAccount:$PROJECT_ID@appspot.gserviceaccount.com" \
5452
--role "organizations/$ORGID/roles/$IRIS_CUSTOM_ROLE" \
55-
--condition=None >/dev/null
56-
53+
--condition=None >/dev/null 2>&1
5754

5855
if [[ "$LABEL_ON_CREATION_EVENT" != "true" ]]; then
5956
echo >&2 "Will not label on creation event."
@@ -95,30 +92,25 @@ else
9592

9693
# Create or update a sink at org level
9794
if ! gcloud logging sinks describe --organization="$ORGID" "$LOG_SINK" >&/dev/null; then
98-
#echo >&2 "Creating Log Sink/Router at Organization level."
9995
gcloud logging sinks create "$LOG_SINK" \
10096
pubsub.googleapis.com/projects/"$PROJECT_ID"/topics/"$LOGS_TOPIC" \
10197
--organization="$ORGID" --include-children \
102-
--log-filter="${log_filter[*]}" --quiet
98+
--log-filter="${log_filter[*]}" --quiet >/dev/null 2>&1
10399
else
104-
#echo >&2 "Updating Log Sink/Router at Organization level."
105100
gcloud logging sinks update "$LOG_SINK" \
106101
pubsub.googleapis.com/projects/"$PROJECT_ID"/topics/"$LOGS_TOPIC" \
107102
--organization="$ORGID" \
108-
--log-filter="${log_filter[*]}" --quiet
103+
--log-filter="${log_filter[*]}" --quiet >/dev/null 2>&1
109104
fi
110105

111106
# Extract service account from sink configuration.
112107
# This is the service account that publishes to PubSub.
113-
svcaccount=$(gcloud logging sinks describe --organization="$ORGID" "$LOG_SINK" |
108+
svcaccount=$(gcloud logging sinks describe --organization="$ORGID" "$LOG_SINK" |
114109
grep writerIdentity | awk '{print $2}')
115110

116111
if [[ "$SKIP_ADDING_IAM_BINDINGS" != "true" ]]; then
117-
echo >&2 "Adding IAM bindings in _deploy-org"
118112
# Assign a publisher role to the extracted service account.
119113
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
120-
--member="$svcaccount" --role=roles/pubsub.publisher --quiet > /dev/null
121-
else
122-
echo >&2 "Not adding IAM bindings in _deploy-org"fi
114+
--member="$svcaccount" --role=roles/pubsub.publisher --quiet >/dev/null 2>&1
123115
fi
124116
fi

0 commit comments

Comments
 (0)