Skip to content

Commit 1fc5b3a

Browse files
authored
Support sending events to multiple Dataset accounts via K8s annotations (#1238)
* Support sending events to multiple Dataset accounts via K8s annotations * Support sending events to multiple Dataset accounts via K8s annotations * Script executable permission * Addressing PR comments * Addressing PR comments * Addressing PR comments * Addressing PR comments * Addressing PR comments * Addressing PR comments
1 parent ae9f3d6 commit 1fc5b3a

23 files changed

+1495
-164
lines changed

.circleci/smoketest_docker.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ echo "Uploader container ID == ${uploader_hostname}"
145145
echo "Using smoketest.py script from ${SMOKE_TESTS_SCRIPT_BRANCH} branch and URL ${SMOKE_TESTS_SCRIPT_URL}"
146146

147147
function print_debugging_info_on_exit() {
148+
echo ""
149+
echo "::group::Scalyr Agent status"
150+
echo ""
151+
docker exec ${contname_agent} scalyr-agent-2 status -v || true
152+
echo "::endgroup::"
153+
148154
echo ""
149155
echo "::group::Docker logs for ${contname_agent} container"
150156
echo ""

.github/actions/install-k8s-agent/action.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ inputs:
99
scalyr_api_key:
1010
description: "Write API key to be used by the agent."
1111
required: true
12+
scalyr_api_key_team_2:
13+
description: "Write API key to be used by the agent."
14+
required: false
15+
scalyr_api_key_team_3:
16+
description: "Write API key to be used by the agent."
17+
required: false
18+
scalyr_api_key_team_4:
19+
description: "Write API key to be used by the agent."
20+
required: false
1221
scalyr_cluster_name:
1322
description: "Cluster name to use."
1423
required: true
@@ -80,6 +89,21 @@ runs:
8089
8190
# Define api key
8291
kubectl create secret generic scalyr-api-key --namespace scalyr --from-literal=scalyr-api-key="${{ inputs.scalyr_api_key }}"
92+
93+
# Create a secret if the scalyr_api_key_team_2 is set
94+
if [ ! -z "${{ inputs.scalyr_api_key_team_2 }}" ]; then
95+
kubectl create secret generic scalyr-api-key-team-2 --namespace scalyr --from-literal=scalyr-api-key="${{ inputs.scalyr_api_key_team_2 }}"
96+
fi
97+
98+
# Create a secret if the scalyr_api_key_team_3 is set
99+
if [ ! -z "${{ inputs.scalyr_api_key_team_3 }}" ]; then
100+
kubectl create secret generic scalyr-api-key-team-3 --namespace scalyr --from-literal=scalyr-api-key="${{ inputs.scalyr_api_key_team_3 }}"
101+
fi
102+
103+
# Create a secret if the scalyr_api_key_team_4 is set
104+
if [ ! -z "${{ inputs.scalyr_api_key_team_4 }}" ]; then
105+
kubectl create secret generic scalyr-api-key-team-4 --namespace scalyr --from-literal=scalyr-api-key="${{ inputs.scalyr_api_key_team_4 }}"
106+
fi
83107
84108
# Create configmap
85109
kubectl create configmap --namespace scalyr scalyr-config \

.github/workflows/agent-build-new.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ jobs:
9090
CT_AWS_DEV_EC2_SECRET_KEY: ${{ secrets.CT_AWS_DEV_EC2_SECRET_KEY }}
9191
CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_WRITE: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_WRITE }}
9292
CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_READ: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_READ }}
93+
SCALYR_API_KEY_READ_2: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_2_READ }}
94+
SCALYR_API_KEY_READ_3: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_3_READ }}
95+
SCALYR_API_KEY_READ_4: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_4_READ }}
96+
SCALYR_API_KEY_WRITE_2: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_2_WRITE }}
97+
SCALYR_API_KEY_WRITE_3: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_3_WRITE }}
98+
SCALYR_API_KEY_WRITE_4: ${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_4_WRITE }}
9399
PULL_REGISTRY_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME_PROD_ACCOUNT }}
94100
PULL_REGISTRY_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD_PROD_ACCOUNT }}
95101
PUBLISH_REGISTRY_USERNAME: ${{ (github.ref_type == 'tag' || github.ref_name == 'master') && secrets.DOCKER_HUB_USERNAME_PROD_ACCOUNT || secrets.DOCKER_HUB_USERNAME_TEST_ACCOUNT }}

.github/workflows/reusable-agent-build-container-images.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ on:
4444
required: true
4545
CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_READ:
4646
required: true
47+
SCALYR_API_KEY_READ_2:
48+
required: true
49+
SCALYR_API_KEY_READ_3:
50+
required: true
51+
SCALYR_API_KEY_READ_4:
52+
required: true
53+
SCALYR_API_KEY_WRITE_2:
54+
required: true
55+
SCALYR_API_KEY_WRITE_3:
56+
required: true
57+
SCALYR_API_KEY_WRITE_4:
58+
required: true
4759
PULL_REGISTRY_USERNAME:
4860
required: true
4961
PULL_REGISTRY_PASSWORD:
@@ -369,9 +381,11 @@ jobs:
369381
minikube image ls
370382
kubectl apply -f tests/e2e/k8s_k8s_monitor/std_printer_deployment.yaml
371383
kubectl apply -f tests/e2e/k8s_k8s_monitor/long_message_printer_deployment.yaml
384+
kubectl apply -f tests/e2e/k8s_k8s_monitor/multiple_account_printers.yaml
372385
373386
kubectl wait --for=condition=ready pod -l app=std-printer
374387
kubectl wait --for=condition=ready pod -l app=long-message-printer
388+
kubectl wait --for=condition=ready pod -l app=multiple-account-printer
375389
kubectl get pods -A
376390
377391
export APP_POD_NAME=$(kubectl get pod --namespace=default --selector=app=std-printer -o jsonpath="{.items[0].metadata.name}")
@@ -392,12 +406,17 @@ jobs:
392406
kubectl apply -f tests/e2e/k8s_events_monitor/cronjob_v1.yaml
393407
394408
kubectl get cronjob -A
409+
- name: Wait random time to make it easier for the cloud github runners
410+
run: sleep $((RANDOM % 60))
395411

396412
- name: Create scalyr-agent-2 daemonset
397413
uses: ./.github/actions/install-k8s-agent/
398414
with:
399415
scalyr_server: "agent.scalyr.com"
400416
scalyr_api_key: "${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_WRITE }}"
417+
scalyr_api_key_team_2: "${{ secrets.SCALYR_API_KEY_WRITE_2 }}"
418+
scalyr_api_key_team_3: "${{ secrets.SCALYR_API_KEY_WRITE_3 }}"
419+
scalyr_api_key_team_4: "${{ secrets.SCALYR_API_KEY_WRITE_4 }}"
401420
scalyr_cluster_name: "${K8S_CLUSTER_NAME}"
402421
scalyr_k8s_events_disable: "false"
403422
main_yaml_path: "tests/e2e/scalyr-agent-2-daemonset.yaml"
@@ -520,6 +539,23 @@ jobs:
520539
echo "CronJob events checks"
521540
./scripts/cicd/scalyr-query.sh '$serverHost="'${SCALYR_AGENT_POD_NAME}'" $logfile="/var/log/scalyr-agent-2/kubernetes_events.log" $parser="k8sEvents" k8s-kind="CronJob" involvedObjectKind="CronJob" involvedObjectName="hello" watchEventType="ADDED" reason="SawCompletedJob"'
522541
542+
- name: Verify multiaccount records have been ingested
543+
timeout-minutes: 14
544+
env:
545+
scalyr_api_key_team: "${{ secrets.CT_SCALYR_TOKEN_PROD_US_CLOUDTECH_TESTING_READ }}"
546+
scalyr_api_key_team_2: "${{ secrets.SCALYR_API_KEY_READ_2 }}"
547+
scalyr_api_key_team_3: "${{ secrets.SCALYR_API_KEY_READ_3 }}"
548+
scalyr_api_key_team_4: "${{ secrets.SCALYR_API_KEY_READ_4 }}"
549+
SCALYR_AGENT_POD_NAME: "${{ env.SCALYR_AGENT_POD_NAME }}"
550+
ACCOUNT_NAME: "[email protected]"
551+
ACCOUNT_NAME_2: "[email protected]"
552+
ACCOUNT_NAME_3: "[email protected]"
553+
ACCOUNT_NAME_4: "[email protected]"
554+
run: |
555+
echo 'Looking for multiple account logs'
556+
557+
./scripts/cicd/verify-multiaccount-records-have-been-ingested.sh
558+
523559
- name: Notify Slack on Failure
524560
if: ${{ failure() && github.ref_name == 'master' }}
525561
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
@@ -530,6 +566,7 @@ jobs:
530566
steps: ${{ toJson(steps) }}
531567
channel: '#eng-dataset-cloud-tech'
532568

569+
533570
k8s_open_metrics_monitor_tests:
534571
name: OpenMetrics Monitor - k8s ${{ inputs.builder_name }} ${{ matrix.k8s_version.version }}-${{ matrix.k8s_version.runtime}}
535572
runs-on: ubuntu-20.04

docs/monitors/kubernetes_monitor.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,26 @@ fields behave differently when configured via k8s annotations:
3030
* lineGroupers (not supported at all)
3131
* path (the path is always fixed for k8s container logs)
3232

33+
### Configuring multiple accounts per container
34+
35+
Containers can be assigned one or more Scalyr API keys by specifying the `log.config.scalyr.com/{container_name}.teams.{team_number}.secret` annotation.
36+
The `container_name` is the name of the container as specified in the pod spec, and the `team_number` is a unique number for each team.
37+
The `secret` is the name of the secret holding the Scalyr API key for the team.
38+
A default fallback api key can be specified by using the `log.config.scalyr.com/teams.{team_number}.secret` annotation.
39+
The monitor first looks into the container specific annotation, and if not found, it falls back to the default annotation or the global configuration api key.
40+
For example, if you had a pod with three containers `cont1`, `cont2` and `cont3` and you wanted to assign different Scalyr API keys to each container,
41+
you could specify the following annotations:
42+
43+
log.config.scalyr.com/teams.1.secret: "scalyr-api-key-team-2"
44+
log.config.scalyr.com/cont1.teams.2.secret: "scalyr-api-key-team-3"
45+
log.config.scalyr.com/cont2.teams.1.secret: "scalyr-api-key-team-3"
46+
log.config.scalyr.com/cont2.teams.2.secret: "scalyr-api-key-team-4"
47+
48+
In this example
49+
* `cont1` would use the api key from `scalyr-api-key-team-3` secret
50+
* `cont2` would be sending the data to two teams accessible by api keys stored in `scalyr-api-key-team-3` and `scalyr-api-key-team-4` secrets.
51+
* `cont3` would use the default api key from `scalyr-api-key-team-2` secret
52+
3353
### Excluding Logs
3454

3555
Containers and pods can be specifically included/excluded from having their logs collected and

k8s/no-kustomize/scalyr-service-account.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ metadata:
1212
name: scalyr-clusterrole
1313
rules:
1414
- apiGroups: [""]
15-
resources: ["namespaces","pods","replicationcontrollers"]
15+
resources: ["namespaces","pods","replicationcontrollers", "secrets"]
1616
verbs: ["get","list"]
1717
- apiGroups: [""]
1818
resources: ["nodes"]

scalyr_agent/agent_main.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,7 @@ def __generate_status(self, warn_on_rate_limit=False):
18771877
@rtype: AgentStatus
18781878
"""
18791879
# Basic agent stats first.
1880+
18801881
result = AgentStatus()
18811882
result.launch_time = self.__start_time
18821883
result.user = self.__controller.get_current_user()
@@ -1892,7 +1893,6 @@ def __generate_status(self, warn_on_rate_limit=False):
18921893
# Describe the status of the configuration file.
18931894
config_result = ConfigStatus()
18941895
result.config_status = config_result
1895-
18961896
config_result.last_check_time = self.__last_config_check_time
18971897
if self.__current_bad_config is not None:
18981898
config_result.path = self.__current_bad_config.file_path
@@ -2274,15 +2274,14 @@ def __report_status_to_file(self):
22742274
# We do a little dance to write the status. We write it to a temporary file first, and then
22752275
# move it into the real location after the write has finished. This way, the process watching
22762276
# the file we are writing does not accidentally read it when it is only partially written.
2277+
22772278
tmp_file_path = os.path.join(
22782279
self.__config.agent_data_path, "last_status.tmp"
22792280
)
22802281
final_file_path = os.path.join(self.__config.agent_data_path, "last_status")
2281-
22822282
if os.path.isfile(final_file_path):
22832283
os.remove(final_file_path)
22842284
tmp_file = open(tmp_file_path, "w")
2285-
22862285
agent_status = self.__generate_status()
22872286

22882287
if not status_format or status_format == "text":

scalyr_agent/builtin_monitors/docker_monitor.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,7 @@ def __create_docker_logger(self, log, last_request):
14831483
name,
14841484
stream,
14851485
log["log_config"]["path"],
1486+
log["log_config"],
14861487
self._config,
14871488
last_request,
14881489
)
@@ -1504,6 +1505,7 @@ def __init__(
15041505
name,
15051506
stream,
15061507
log_path,
1508+
log_config,
15071509
config,
15081510
last_request=None,
15091511
max_log_size=20 * 1024 * 1024,
@@ -1516,6 +1518,7 @@ def __init__(
15161518
# stderr or stdout
15171519
self.stream = stream
15181520
self.log_path = log_path
1521+
self.log_config = log_config
15191522
self.stream_name = name + "-" + stream
15201523

15211524
self.__max_previous_lines = config.get("max_previous_lines")

0 commit comments

Comments
 (0)