Skip to content

Commit a364d0c

Browse files
committed
support folders
1 parent c4ddd7b commit a364d0c

22 files changed

+144
-80
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
12
# Iris
23

3-
In Greek mythology, Iris (/ˈaɪrɪs/; Greek: Ἶρις) is the personification of the rainbow and messenger of the gods. She
4-
was the handmaiden to Hera.
4+
In Greek mythology, Iris(Ἶρις) is the personification of the rainbow and messenger of the gods. She was the handmaiden to Hera.
55

66
# Blog post
77

@@ -26,9 +26,9 @@ Note that Iris is designed to serve the org. It is not designed around serving a
2626
Iris does not *add* information, only *copy* values that already exist. For example, it can label a VM instance with its zone, since this information is known; but it cannot add a "business unit" label because it does not know what business
2727
unit a resource should be attributed to. For that, you should label all resources when creating them, e.g., in your Terraform scripts.
2828

29-
## Iris doesn't by default label all existing resources.
29+
## Iris **doesn't** label all existing resources in the default setup.
3030

31-
To do it, see section [Labeling existing resources](#Labeling existing resources) below.
31+
To do this, see section "[Labeling existing resources](#labeling-existing-resources)" below.
3232

3333
# Open source
3434
Iris is open-source: Feel free to add functionality and add new types of labels. See the `TODO.md` file and Github issues for features and fixes you might do.
@@ -47,8 +47,8 @@ Or you can disable the schedule labeling.
4747

4848
## Labeling existing resources
4949

50-
* When you first use Iris, you may want to label all existing resources. This is not Iris' preferred flow for adding labels, but you can do it.
51-
* To do this, deploy it with `label_all_on_cron: True` and wait for the next scheduled run, or manually trigger a run.
50+
* When you first use Iris, you may want to label all existing resources. This is not Iris' default flow for adding labels, but you can do it.
51+
* To do this, deploy it with `label_all_on_cron: True` and wait for the next scheduled run, or manually trigger a run through Cloud Scheduler.
5252
* Thenּ, you may want to then redeploy Iris with `label_all_on_cron: False` to avoid the resource consumption of relabeling all resources with the same label every day forever.
5353

5454
# Supported Google Cloud resources
@@ -85,13 +85,13 @@ The part of the function name after `_gcp_` is used for the label key.
8585
* You can deploy Iris in any project within your Google Cloud organization, but we recommend using a
8686
[new project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
8787

88-
* You need to have certain permissions to run the deployment script to deploy Iris on the org level--the deploy script sets up roles and log sink. You will need to have these roles on the *organization* where Iris is deployed. You do not need to have these roles if you are doing further re-deployments of new versions of Iris on the project level (where you use the `-p` switch on `deploy.sh`.
88+
* Here are the required organization-level roles for you, the deployer, to allow the deploy script to set up roles and log sink. You do not need to have these roles if you are doing further re-deployments of new versions of Iris on the project level (where you use the `-p` switch on `deploy.sh`.
8989
* *Organization Role Administrator* so the deployment script can create a custom IAM role for Iris that allows to get and set labels.
9090
* (Note that *Organization Owner* is not enough).
9191
* *Security Admin* **or** *Organization Administrator* so the deployment script can allow the Iris app engine service account to have the needed permissions.
9292
* *Logs Configuration Writer* so the deployment script can create an organization log sink that sends logs to PubSub.
9393

94-
* You need to have certain permissions to run the deployment script to deploy Iris on the project level.
94+
* Here are the required project-level roles that you need on the Iris deployment project.
9595
* One option: You can have *Project Owner* on the project where Iris is deployed
9696
* Another option: You can have these roles.
9797
* *Project IAM Admin* to let the deployment script set up the bindings.

TODO.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# Improvements and fixes
22
## Note: see also Github Issues
33

4-
* Instead of just the -c switch on install.sh, create consistency by adding an -e (for "event-driven") switch to mean "event-driven labeling". Running install.sh with neither -c or -e means the equivalent of having both -c -e.
5-
In doing this, validate that any installation with only -c or only -e is NOT -p (project-only) or -o (org-only) and fail if so. (i.e., proceed with installation only if neither or both switches are used.)
4+
* P2 Redo the whole thing with Cloud Asset Inventory including feeds.
5+
Cloud Asset Inventory only recognizes assets for listing with a delay; and it is not clear whether the feeds are "real-time" or have a delay.
6+
* P2 Instead of just the -c switch on install.sh, create consistency by adding an -e (for "event-driven") switch to mean "event-driven labeling". Running install.sh with neither -c or -e should mean the same as having both -c -e.
7+
In doing this, validate that any installation with only -c or only -e is NOT -p (project-only) or -o (org-only) and fail if so. (i.e., proceed with installation if and only if neither or both switches are used.)
68

7-
* P2 Even an empty AppEngine app (not Iris, just a Hello World with 3 lines of code in total) crashes on out-of-memory for the smalled AppEngine instance. Google has confirmed this. See if there is a workaround. This will same money.
9+
* P2 Memory consumption: Even an empty AppEngine app (not Iris, just a Hello World with 3 lines of code in total) crashes on out-of-memory for the smalled AppEngine instance. Google has confirmed this. See if there is a workaround. This will same money.
810

911
* P2 PubSub push endpoint security:
1012
Note: The token by itself is not very secure, though
@@ -49,8 +51,6 @@
4951

5052
* P3 Rethink the need for title case in class names. This is clumsy for `Cloudsql`.
5153

52-
* P3 Concurrent execution
53-
* Init of multiple plugins is among the biggest slowdowns. They could be initialized concurrently.
5454

5555
* P4 Implement new labels, for example using ideas from
5656
the [GCP Auto Tag project](https://github.com/doitintl/gcp-auto-tag/)

deploy.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# See usage (deploy.sh -h).
44
# Deploys Iris to Google App Engine, setting up Roles, Sinks, Topics, and Subscriptions as needed.
55

6-
#set -x
6+
set -x
77
set -u
88
set -e
99

gce_base/gce_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import proto
55

66
from plugin import Plugin
7-
from util.gcp_utils import (
7+
from util.gcp.gcp_utils import (
88
cloudclient_pb_obj_to_dict,
99
cloudclient_pb_objects_to_list_of_dicts,
1010
)

gce_base/gce_zonal_base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from typing import Dict, Optional
77

88
from gce_base.gce_base import GceBase
9-
from util import gcp_utils
10-
from util.gcp_utils import add_loaded_lib
9+
from util.gcp import gcp_utils
10+
from util.gcp.gcp_utils import add_loaded_lib
1111
from util.utils import timing
1212

1313

main.py

+32-26
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22

33
import sys
44

5-
65
from flask import Response
76

87
print("Initializing ", file=sys.stderr)
98
import flask
10-
from util.gcp_utils import (
9+
from util.gcp.gcp_utils import (
1110
increment_invocation_count,
1211
count_invocations_by_path,
1312
)
14-
from util.detect_gae import detect_gae
13+
from util.gcp.detect_gae import detect_gae
1514

1615
app = flask.Flask(__name__)
1716
if detect_gae():
@@ -37,8 +36,9 @@
3736
import os
3837

3938
from plugin import Plugin, PluginHolder
40-
from util import pubsub_utils, gcp_utils, utils, config_utils
41-
from util.gcp_utils import (
39+
from util import pubsub_utils, utils, config_utils
40+
from util.gcp import gcp_utils
41+
from util.gcp.gcp_utils import (
4242
detect_gae,
4343
is_appscript_project,
4444
all_projects,
@@ -51,7 +51,7 @@
5151
is_project_enabled,
5252
pubsub_token,
5353
is_in_test_or_dev_project,
54-
is_test_or_dev_configuration,
54+
is_test_configuration,
5555
iris_homepage_text,
5656
)
5757
from util.utils import log_time, timing
@@ -73,11 +73,10 @@
7373

7474
@app.route("/")
7575
def index():
76-
7776
increment_invocation_count("index")
7877
with gae_memory_logging("index"):
7978
msg = iris_homepage_text()
80-
if config_utils.is_test_or_dev_configuration():
79+
if config_utils.is_test_configuration():
8180
msg += "\nI'm running in test or dev mode."
8281

8382
logging.info(
@@ -88,7 +87,6 @@ def index():
8887

8988
@app.route("/_ah/warmup")
9089
def warmup():
91-
9290
increment_invocation_count("warmup")
9391
with gae_memory_logging("warmup"):
9492
logging.info("warmup() called")
@@ -129,32 +127,41 @@ def __get_enabled_projects():
129127
enabled_projs = configured_as_enabled
130128
else:
131129
all_proj = all_projects()
132-
# In my testing, we do NOT get appscript projects in the list.
133-
# There is a small chance that with other permissions, these appscript projects would appear.
134-
# so here we filter them out.
135130

131+
# In some cases, lots of appscript projects would appear.
132+
# so here we filter them out. However, In my testing, we do NOT get appscript projects in the list.
136133
nonappscript_projects = (p for p in all_proj if not is_appscript_project(p))
137-
138-
enabled_only = (
139-
p for p in nonappscript_projects if config_utils.is_project_enabled(p)
140-
)
134+
# The following filtering is probably useless since the else-clause that
135+
# that we are in is reached only if there are no explicitly enabled projects.
136+
enabled_only = (p for p in nonappscript_projects if config_utils.is_project_enabled(p))
141137
enabled_projs = list(enabled_only)
142138
enabled_projs.sort()
143139
if not enabled_projs:
144140
raise Exception("No projects enabled at all")
145-
141+
explain = []
146142
if ( # These are three indications that we are running in dev/test
147-
not detect_gae()
148-
or is_test_or_dev_configuration()
149-
or is_in_test_or_dev_project(current_project_id())
143+
not detect_gae()
144+
or is_test_configuration()
145+
or is_in_test_or_dev_project(current_project_id())
150146
):
147+
if not detect_gae():
148+
explain.append("Not running in App Engine")
149+
if is_test_configuration():
150+
explain.append("Using a test configuration file " + config_utils.config_test_file())
151+
if is_in_test_or_dev_project(current_project_id()):
152+
explain.append("Running a project " + current_project_id() +
153+
" which has one of the markers of a test project" +
154+
" configured under key test_or_dev_project_markers")
151155
max_proj_in_dev = 3
152156
if len(enabled_projs) > max_proj_in_dev:
157+
assert explain, "If we got here, one of the conditioned should have been true"
153158
raise Exception(
154-
"""In development or testing, we support no more than {max_proj_in_dev} projects, \
159+
f"""When running Iris in development/testing mode, \
160+
we support no more than {max_proj_in_dev} projects, \
155161
to avoid accidentally flooding the system.
156162
{len(enabled_projs)} projects are available, which exceeds that.
157-
See README.md for explanation.
163+
We are in development/testing mode because:
164+
{"; ".join(explain)}
158165
"""
159166
)
160167
return enabled_projs
@@ -165,9 +172,9 @@ def __send_pubsub_per_projectplugin(configured_projects):
165172
for project_id in configured_projects:
166173
for plugin_cls in PluginHolder.plugins:
167174
if (
168-
not plugin_cls.is_labeled_on_creation()
169-
or plugin_cls.relabel_on_cron()
170-
or config_utils.label_all_on_cron()
175+
not plugin_cls.is_labeled_on_creation()
176+
or plugin_cls.relabel_on_cron()
177+
or config_utils.label_all_on_cron()
171178
):
172179
pubsub_utils.publish(
173180
msg=json.dumps(
@@ -191,7 +198,6 @@ def __send_pubsub_per_projectplugin(configured_projects):
191198

192199
@app.route("/label_one", methods=["POST"])
193200
def label_one():
194-
195201
increment_invocation_count("label_one")
196202
with gae_memory_logging("label_one"):
197203

plugin.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from googleapiclient import discovery
1010
from googleapiclient import errors
1111

12-
from util import gcp_utils, config_utils
12+
from util import config_utils
13+
from util.gcp import gcp_utils
1314
from util.config_utils import (
1415
is_copying_labels_from_project,
1516
iris_prefix,
@@ -222,6 +223,9 @@ def plugin_cls_by_name(cls, name) -> Type[Plugin]:
222223
@classmethod
223224
@log_time
224225
def init(cls):
226+
"""Loads the classes, but does not create instances, which happens
227+
in get_plugin_instance"""
228+
225229
def load_plugin_class(name) -> Type:
226230
module_name = PLUGINS_MODULE + "." + name
227231
__import__(module_name)
@@ -231,6 +235,7 @@ def load_plugin_class(name) -> Type:
231235
loaded = []
232236
for _, module, _ in pkgutil.iter_modules([PLUGINS_MODULE]):
233237
if config_utils.is_plugin_enabled(module):
238+
234239
plugin_class = load_plugin_class(module)
235240
cls.plugins[
236241
plugin_class
@@ -241,6 +246,7 @@ def load_plugin_class(name) -> Type:
241246

242247
@classmethod
243248
def get_plugin_instance(cls, plugin_cls):
249+
"""Lazy-initialize the instance. The classes are loaded in init()"""
244250
with cls.__lock:
245251
assert plugin_cls in cls.plugins, plugin_cls + " " + cls.plugins
246252
plugin_instance = cls.plugins[plugin_cls]

plugins/bigquery.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from ratelimit import limits, sleep_and_retry
1010

1111
from plugin import Plugin
12-
from util import gcp_utils
13-
from util.gcp_utils import add_loaded_lib
12+
from util.gcp import gcp_utils
13+
from util.gcp.gcp_utils import add_loaded_lib
1414
from util.utils import log_time, timing, dict_to_camelcase
1515

1616

plugins/buckets.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from functools import lru_cache
33

44
from plugin import Plugin
5-
from util import gcp_utils
6-
from util.gcp_utils import add_loaded_lib
5+
from util.gcp import gcp_utils
6+
from util.gcp.gcp_utils import add_loaded_lib
77
from util.utils import log_time, timing, dict_to_camelcase
88

99

plugins/disks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from googleapiclient import errors
77

88
from gce_base.gce_zonal_base import GceZonalBase
9-
from util import gcp_utils
10-
from util.gcp_utils import add_loaded_lib
9+
from util.gcp import gcp_utils
10+
from util.gcp.gcp_utils import add_loaded_lib
1111
from util.utils import log_time
1212

1313

plugins/instances.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from googleapiclient import errors
77

88
from gce_base.gce_zonal_base import GceZonalBase
9-
from util import gcp_utils
10-
from util.gcp_utils import add_loaded_lib
9+
from util.gcp import gcp_utils
10+
from util.gcp.gcp_utils import add_loaded_lib
1111
from util.utils import log_time
1212

1313

plugins/snapshots.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from googleapiclient import errors
55

66
from gce_base.gce_base import GceBase
7-
from util import gcp_utils
8-
from util.gcp_utils import add_loaded_lib
7+
from util.gcp import gcp_utils
8+
from util.gcp.gcp_utils import add_loaded_lib
99
from util.utils import log_time, timing
1010

1111

plugins/subscriptions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from googleapiclient import errors
66

77
from plugin import Plugin
8-
from util.gcp_utils import (
8+
from util.gcp.gcp_utils import (
99
cloudclient_pb_obj_to_dict,
1010
cloudclient_pb_objects_to_list_of_dicts,
1111
add_loaded_lib,

plugins/topics.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from googleapiclient import errors
66

77
from plugin import Plugin
8-
from util.gcp_utils import (
8+
from util.gcp.gcp_utils import (
99
cloudclient_pb_obj_to_dict,
1010
cloudclient_pb_objects_to_list_of_dicts,
1111
add_loaded_lib,

scripts/_deploy-project.sh

+4-3
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ if [[ ! -f "config-test.yaml" ]] && [[ ! -f "config.yaml" ]]; then
2828
fi
2929

3030
ABBREV__=$(gcloud app describe --project $PROJECT_ID | grep defaultHostname |egrep -o "\.[a-z][a-z]\.")
31-
GAE_REGION_ABBREV=${ABBREV__:1:2}
31+
GAE_MULTIREGION_ABBREV=${ABBREV__:1:2} # Something like uc (us-central) or sa (southeast-asia)
3232

3333
GAE_SVC=$(grep "service:" app.yaml | awk '{print $2}')
34+
3435
# The following line depends on the the export PYTHON_PATH="." above.
3536
PUBSUB_VERIFICATION_TOKEN=$(python3 ./util/print_pubsub_token.py)
36-
LABEL_ONE_SUBSCRIPTION_ENDPOINT="https://${GAE_SVC}-dot-${PROJECT_ID}.${GAE_REGION_ABBREV}.r.appspot.com/label_one?token=${PUBSUB_VERIFICATION_TOKEN}"
37-
DO_LABEL_SUBSCRIPTION_ENDPOINT="https://${GAE_SVC}-dot-${PROJECT_ID}.${GAE_REGION_ABBREV}.r.appspot.com/do_label?token=${PUBSUB_VERIFICATION_TOKEN}"
37+
LABEL_ONE_SUBSCRIPTION_ENDPOINT="https://${GAE_SVC}-dot-${PROJECT_ID}.${GAE_MULTIREGION_ABBREV}.r.appspot.com/label_one?token=${PUBSUB_VERIFICATION_TOKEN}"
38+
DO_LABEL_SUBSCRIPTION_ENDPOINT="https://${GAE_SVC}-dot-${PROJECT_ID}.${GAE_MULTIREGION_ABBREV}.r.appspot.com/do_label?token=${PUBSUB_VERIFICATION_TOKEN}"
3839

3940
declare -A enabled_services
4041
while read -r svc _; do

0 commit comments

Comments
 (0)