Skip to content

Commit 865fc43

Browse files
committed
support new --extra-tag argument, tag all resources
We now tag all resources with the arkime_cluster tag. Can also use --extra-tag <key> <value> to have more tags added to all resources
1 parent c23499d commit 865fc43

File tree

6 files changed

+94
-103
lines changed

6 files changed

+94
-103
lines changed

cdk-lib/cloud-demo.ts

+20
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,37 @@ const env: Environment = {
2525

2626
switch(params.type) {
2727
case 'ClusterMgmtParams': {
28+
function addTags (stack: cdk.Stack) {
29+
const clusterParams = params as prms.ClusterMgmtParams;
30+
cdk.Tags.of(stack).add('arkime_cluster', clusterParams.nameCluster);
31+
32+
if (clusterParams.userConfig.extraTags) {
33+
for (const tag of clusterParams.userConfig.extraTags) {
34+
cdk.Tags.of(stack).add(tag.key, tag.value);
35+
}
36+
}
37+
}
2838
const captureBucketStack = new CaptureBucketStack(app, params.stackNames.captureBucket, {
2939
env: env,
3040
planCluster: params.planCluster,
3141
ssmParamName: params.nameCaptureBucketSsmParam,
3242
});
43+
addTags(captureBucketStack);
3344

3445
const captureVpcStack = new CaptureVpcStack(app, params.stackNames.captureVpc, {
3546
env: env,
3647
planCluster: params.planCluster,
3748
});
49+
addTags(captureVpcStack);
3850

3951
const osDomainStack = new OpenSearchDomainStack(app, params.stackNames.osDomain, {
4052
env: env,
4153
captureVpc: captureVpcStack.vpc,
4254
planCluster: params.planCluster,
4355
ssmParamName: params.nameOSDomainSsmParam,
4456
});
57+
addTags(osDomainStack);
58+
4559
osDomainStack.addDependency(captureVpcStack);
4660

4761
const captureNodesStack = new CaptureNodesStack(app, params.stackNames.captureNodes, {
@@ -59,6 +73,8 @@ case 'ClusterMgmtParams': {
5973
ssmParamNameCluster: params.nameClusterSsmParam,
6074
userConfig: params.userConfig
6175
});
76+
addTags(captureNodesStack);
77+
6278
captureNodesStack.addDependency(captureBucketStack);
6379
captureNodesStack.addDependency(captureVpcStack);
6480
captureNodesStack.addDependency(osDomainStack);
@@ -73,6 +89,7 @@ case 'ClusterMgmtParams': {
7389
env: env,
7490
captureVpc: captureVpcStack.vpc
7591
});
92+
addTags(captureTgwStack);
7693
captureTgwStack.addDependency(captureVpcStack);
7794

7895
const viewerVpcStack = new ViewerVpcStack(app, params.stackNames.viewerVpc, {
@@ -81,6 +98,8 @@ case 'ClusterMgmtParams': {
8198
captureVpc: captureVpcStack.vpc,
8299
viewerVpcPlan: params.planCluster.viewerVpc
83100
});
101+
addTags(viewerVpcStack);
102+
84103
viewerVpcStack.addDependency(captureVpcStack);
85104
viewerVpcStack.addDependency(captureNodesStack);
86105
viewerVpcStack.addDependency(captureTgwStack);
@@ -102,6 +121,7 @@ case 'ClusterMgmtParams': {
102121
planCluster: params.planCluster,
103122
userConfig: params.userConfig,
104123
});
124+
addTags(viewerNodesStack);
105125
viewerNodesStack.addDependency(captureBucketStack);
106126
viewerNodesStack.addDependency(vpcStackToUse);
107127
viewerNodesStack.addDependency(osDomainStack);

cdk-lib/core/context-types.ts

+9
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export interface UserConfig {
9898
replicas: number;
9999
pcapDays: number;
100100
viewerPrefixList: string;
101+
extraTags: ExtraTag[]
101102
}
102103

103104
/**
@@ -112,3 +113,11 @@ export interface ClusterMgmtStackNames {
112113
viewerNodes: string;
113114
viewerVpc: string;
114115
}
116+
117+
/**
118+
* Structure to hold the Extra Tags
119+
*/
120+
export interface ExtraTag {
121+
key: string;
122+
value: string
123+
}

manage_arkime.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,25 @@ def demo_traffic_destroy(ctx):
130130
default=None,
131131
type=click.STRING,
132132
required=False)
133+
@click.option(
134+
"--extra-tag",
135+
help=("Extra AWS Tag to apply to all resources."),
136+
default=None,
137+
nargs=2,
138+
type=(click.STRING, click.STRING),
139+
multiple=True,
140+
required=False)
133141
@click.pass_context
134142
def cluster_create(ctx, name, expected_traffic, spi_days, history_days, replicas, pcap_days, preconfirm_usage,
135-
just_print_cfn, capture_cidr, viewer_cidr, viewer_prefix_list):
143+
just_print_cfn, capture_cidr, viewer_cidr, viewer_prefix_list, extra_tag):
136144
profile = ctx.obj.get("profile")
137145
region = ctx.obj.get("region")
146+
extra_tags = []
147+
if extra_tag:
148+
for key, value in extra_tag:
149+
extra_tags.append({"key": key, "value": value})
138150
cmd_cluster_create(profile, region, name, expected_traffic, spi_days, history_days, replicas, pcap_days,
139-
preconfirm_usage, just_print_cfn, capture_cidr, viewer_cidr, viewer_prefix_list)
151+
preconfirm_usage, just_print_cfn, capture_cidr, viewer_cidr, viewer_prefix_list, extra_tags)
140152
cli.add_command(cluster_create)
141153

142154
@click.command(help="Tears down the Arkime Cluster in your account; by default, leaves your data intact")

manage_arkime/commands/cluster_create.py

+9-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
import shutil
55
import sys
6-
from typing import Callable, List
6+
from typing import Callable, List, Tuple, Dict
77

88
import arkime_interactions.config_wrangling as config_wrangling
99
from aws_interactions.acm_interactions import upload_default_elb_cert
@@ -31,7 +31,8 @@
3131
logger = logging.getLogger(__name__)
3232

3333
def cmd_cluster_create(profile: str, region: str, name: str, expected_traffic: float, spi_days: int, history_days: int, replicas: int,
34-
pcap_days: int, preconfirm_usage: bool, just_print_cfn: bool, capture_cidr: str, viewer_cidr: str, viewer_prefix_list: str):
34+
pcap_days: int, preconfirm_usage: bool, just_print_cfn: bool, capture_cidr: str, viewer_cidr: str, viewer_prefix_list: str,
35+
extra_tags: List[Dict[str, str]]):
3536
logger.debug(f"Invoking cluster-create with profile '{profile}' and region '{region}'")
3637

3738
aws_provider = AwsClientProvider(aws_profile=profile, aws_region=region)
@@ -50,7 +51,7 @@ def cmd_cluster_create(profile: str, region: str, name: str, expected_traffic: f
5051

5152
# Generate our capacity plan, then confirm it's what the user expected and it's safe to proceed with the operation
5253
previous_user_config = _get_previous_user_config(name, aws_provider)
53-
next_user_config = _get_next_user_config(name, expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list, aws_provider)
54+
next_user_config = _get_next_user_config(name, expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list, extra_tags, aws_provider)
5455
previous_capacity_plan = _get_previous_capacity_plan(name, aws_provider)
5556
next_capacity_plan = _get_next_capacity_plan(next_user_config, previous_capacity_plan, capture_cidr, viewer_cidr, aws_provider)
5657

@@ -82,9 +83,6 @@ def cmd_cluster_create(profile: str, region: str, name: str, expected_traffic: f
8283
# Deploy the CFN resources
8384
cdk_client.deploy(stacks_to_deploy, context=create_context)
8485

85-
# Tag the OpenSearch Domain
86-
_tag_domain(name, aws_provider)
87-
8886
# Kick off Events to ensure that ISM is set up on the CFN-created OpenSearch Domain
8987
_configure_ism(name, next_user_config.historyDays, next_user_config.spiDays, next_user_config.replicas, aws_provider)
9088

@@ -156,7 +154,7 @@ def _get_previous_user_config(cluster_name: str, aws_provider: AwsClientProvider
156154
return UserConfig(None, None, None, None, None)
157155

158156
def _get_next_user_config(cluster_name: str, expected_traffic: float, spi_days: int, history_days: int, replicas: int,
159-
pcap_days: int, viewer_prefix_list: str, aws_provider: AwsClientProvider) -> UserConfig:
157+
pcap_days: int, viewer_prefix_list: str, extra_tags: str, aws_provider: AwsClientProvider) -> UserConfig:
160158
# At least one parameter isn't defined
161159
if None in [expected_traffic, spi_days, replicas, pcap_days, history_days, viewer_prefix_list]:
162160
# Re-use the existing configuration if it exists
@@ -183,14 +181,16 @@ def _get_next_user_config(cluster_name: str, expected_traffic: float, spi_days:
183181
user_config.pcapDays = pcap_days
184182
if viewer_prefix_list is not None:
185183
user_config.viewerPrefixList = viewer_prefix_list
184+
if extra_tags is not None:
185+
user_config.extraTags = extra_tags
186186
return user_config
187187

188188
# Existing configuration doesn't exist, use defaults
189189
except ssm_ops.ParamDoesNotExist:
190-
return UserConfig(expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list)
190+
return UserConfig(expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list, extra_tags)
191191
# All of the parameters defined
192192
else:
193-
return UserConfig(expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list)
193+
return UserConfig(expected_traffic, spi_days, history_days, replicas, pcap_days, viewer_prefix_list, extra_tags)
194194

195195
def _get_previous_capacity_plan(cluster_name: str, aws_provider: AwsClientProvider) -> ClusterPlan:
196196
# Pull the existing plan, if possible
@@ -358,21 +358,6 @@ def _configure_ism(cluster_name: str, history_days: int, spi_days: int, replicas
358358
aws_provider
359359
)
360360

361-
def _tag_domain(cluster_name: str, aws_provider: AwsClientProvider):
362-
os_domain_Arn = ssm_ops.get_ssm_param_json_value(
363-
constants.get_opensearch_domain_ssm_param_name(cluster_name),
364-
"domainArn",
365-
aws_provider
366-
)
367-
368-
opensearch_client = aws_provider.get_opensearch()
369-
opensearch_client.add_tags(
370-
ARN=os_domain_Arn,
371-
TagList=[
372-
{"Key": "arkime_cluster", "Value": cluster_name},
373-
]
374-
)
375-
376361
def _get_stacks_to_deploy(cluster_name: str, next_user_config: UserConfig, next_capacity_plan: ClusterPlan) -> List[str]:
377362
# This list defines what actually gets deployed, as opposed to what the CDK has in its blueprint as being available
378363
# to deploy.

manage_arkime/core/user_config.py

+27-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from dataclasses import dataclass, fields
22
import logging
3-
from typing import Dict
3+
from typing import Dict, List
44

55
from core.capacity_planning import (MINIMUM_TRAFFIC, DEFAULT_SPI_DAYS, DEFAULT_REPLICAS, DEFAULT_S3_STORAGE_DAYS, DEFAULT_HISTORY_DAYS)
66

@@ -14,30 +14,31 @@ class UserConfig:
1414
replicas: int
1515
pcapDays: int
1616
viewerPrefixList: str = None
17+
extraTags: List[Dict[str, str]] = None
18+
19+
def __init__(self, expectedTraffic: float, spiDays: int, historyDays: int, replicas: int, pcapDays: int, viewerPrefixList: str = None, extraTags: List[Dict[str, str]] = []):
20+
self.expectedTraffic = expectedTraffic
21+
self.spiDays = spiDays
22+
self.historyDays = historyDays
23+
self.replicas = replicas
24+
self.pcapDays = pcapDays
25+
self.viewerPrefixList = viewerPrefixList
26+
self.extraTags = extraTags
1727

18-
def __init__(self, expectedTraffic: float, spiDays: int, historyDays: int, replicas: int, pcapDays: int, viewerPrefixList: str = None):
1928
if (expectedTraffic is None):
20-
expectedTraffic = MINIMUM_TRAFFIC
29+
self.expectedTraffic = MINIMUM_TRAFFIC
2130

2231
if (spiDays is None):
23-
spiDays = DEFAULT_SPI_DAYS
32+
self.spiDays = DEFAULT_SPI_DAYS
2433

2534
if (historyDays is None):
26-
historyDays = DEFAULT_HISTORY_DAYS
35+
self.historyDays = DEFAULT_HISTORY_DAYS
2736

2837
if (replicas is None):
29-
replicas = DEFAULT_REPLICAS
38+
self.replicas = DEFAULT_REPLICAS
3039

3140
if (pcapDays is None):
32-
pcapDays = DEFAULT_S3_STORAGE_DAYS
33-
34-
35-
self.expectedTraffic = expectedTraffic
36-
self.spiDays = spiDays
37-
self.historyDays = historyDays
38-
self.replicas = replicas
39-
self.pcapDays = pcapDays
40-
self.viewerPrefixList = viewerPrefixList
41+
self.pcapDays = DEFAULT_S3_STORAGE_DAYS
4142

4243
""" Only process fields we still need, this allows us to ignore config no longer used """
4344
@classmethod
@@ -47,12 +48,21 @@ def from_dict(cls, d):
4748
return cls(**valid_kwargs)
4849

4950
def __eq__(self, other):
51+
set1 = None
52+
if self.extraTags is not None:
53+
set1 = {frozenset(d.items()) for d in self.extraTags}
54+
55+
set2 = None
56+
if other.extraTags is not None:
57+
set2 = {frozenset(d.items()) for d in other.extraTags}
58+
5059
return (self.expectedTraffic == other.expectedTraffic and
5160
self.spiDays == other.spiDays and
5261
self.historyDays == other.historyDays and
5362
self.replicas == other.replicas and
5463
self.pcapDays == other.pcapDays and
55-
self.viewerPrefixList == other.viewerPrefixList)
64+
self.viewerPrefixList == other.viewerPrefixList and
65+
set1 == set2)
5666

5767
def to_dict(self) -> Dict[str, any]:
5868
return {
@@ -62,5 +72,6 @@ def to_dict(self) -> Dict[str, any]:
6272
'pcapDays': self.pcapDays,
6373
'historyDays': self.historyDays,
6474
'viewerPrefixList': self.viewerPrefixList,
75+
'extraTags': self.extraTags,
6576
}
6677

0 commit comments

Comments
 (0)