@nuvlore/extension-bds 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +3 -0
- package/agents/bds-airflow-job-status-readonly.yaml +123 -0
- package/agents/bds-disk-investigator.yaml +112 -0
- package/agents/bds-inventory-readonly.yaml +60 -0
- package/agents/bds-oncall-reporter.yaml +113 -0
- package/agents/bds-prism-service-proxy-timeout-readonly.yaml +105 -0
- package/agents/bds-scylla-tenant-bucket-readonly.yaml +104 -0
- package/agents/bds-tenant-data-operation-log-readonly.yaml +98 -0
- package/agents/bds-yarn-app-health-readonly.yaml +114 -0
- package/agents/pharos-alert-investigator.yaml +81 -0
- package/package.json +60 -0
- package/skills/bds-airflow-job-status-investigation/SKILL.md +104 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-access-runbook.md +35 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-bas-dr-runbook.md +42 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-copy-and-migration-runbook.md +63 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-job-status-runbook.md +15 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-output-runbook.md +28 -0
- package/skills/bds-airflow-job-status-investigation/references/airflow-snapshot-runbook.md +38 -0
- package/skills/bds-disk-io-alert-investigation/SKILL.md +116 -0
- package/skills/bds-hadoop-review/SKILL.md +66 -0
- package/skills/bds-machine-inventory/SKILL.md +48 -0
- package/skills/bds-oncall-followup/SKILL.md +71 -0
- package/skills/bds-oncall-followup/references/oncall-followup-runbook.md +58 -0
- package/skills/bds-prism-service-proxy-timeout-investigation/SKILL.md +73 -0
- package/skills/bds-prism-service-proxy-timeout-investigation/references/service-proxy-timeout-runbook.md +48 -0
- package/skills/bds-scylla-tenant-bucket-investigation/SKILL.md +73 -0
- package/skills/bds-scylla-tenant-bucket-investigation/references/tenant-bucket-runbook.md +91 -0
- package/skills/bds-tenant-data-operation-log-investigation/SKILL.md +89 -0
- package/skills/bds-yarn-app-health-investigation/SKILL.md +77 -0
- package/skills/bds-yarn-app-health-investigation/references/yarn-app-health-runbook.md +53 -0
- package/skills/pharos-alert-investigation/SKILL.md +80 -0
- package/src/bds-atomic-log-tools.mjs +300 -0
- package/src/bds-team-membership-claude-output.mjs +36 -0
- package/src/bds-team-membership-quality.mjs +90 -0
- package/tools/bds_airflow_dag_log_read.mjs +24 -0
- package/tools/bds_airflow_job_status_command_pack.mjs +587 -0
- package/tools/bds_bas_log_read.mjs +23 -0
- package/tools/bds_bdm_httpd_log_read.mjs +24 -0
- package/tools/bds_chef_client_log_read.mjs +23 -0
- package/tools/bds_dashboard_links.mjs +178 -0
- package/tools/bds_dashboard_query_knowledge.mjs +258 -0
- package/tools/bds_dashboard_query_read.mjs +120 -0
- package/tools/bds_disk_io_alert_command_pack.mjs +287 -0
- package/tools/bds_environment_host_lookup.mjs +741 -0
- package/tools/bds_hdfs_datanode_log_read.mjs +23 -0
- package/tools/bds_hdfs_journalnode_log_read.mjs +23 -0
- package/tools/bds_hdfs_namenode_log_read.mjs +23 -0
- package/tools/bds_hdfs_path_knowledge.mjs +324 -0
- package/tools/bds_information_source_knowledge.mjs +356 -0
- package/tools/bds_kms_log_read.mjs +23 -0
- package/tools/bds_log_path_knowledge.mjs +267 -0
- package/tools/bds_machine_inventory.mjs +434 -0
- package/tools/bds_mapreduce_historyserver_log_read.mjs +23 -0
- package/tools/bds_migration_service_operation_command_pack.mjs +233 -0
- package/tools/bds_oncall_followup_payload_draft.mjs +285 -0
- package/tools/bds_pharos_query_pack.mjs +218 -0
- package/tools/bds_portal_operation_knowledge.mjs +212 -0
- package/tools/bds_prism_clone_status_links.mjs +129 -0
- package/tools/bds_prism_service_proxy_timeout_query_pack.mjs +224 -0
- package/tools/bds_public_cloud_pod_log_read.mjs +18 -0
- package/tools/bds_scylla_tenant_bucket_command_pack.mjs +323 -0
- package/tools/bds_service_proxy_log_read.mjs +23 -0
- package/tools/bds_spark_historyserver_log_read.mjs +32 -0
- package/tools/bds_spas_mt_log_read.mjs +23 -0
- package/tools/bds_tenant_data_operation_log_command_pack.mjs +321 -0
- package/tools/bds_yarn_app_health_command_pack.mjs +529 -0
- package/tools/bds_yarn_nodemanager_log_read.mjs +23 -0
- package/tools/bds_yarn_resourcemanager_log_read.mjs +23 -0
- package/tools/bds_zookeeper_log_read.mjs +23 -0
- package/tools/confluence_handoff_page_draft.mjs +173 -0
- package/vendor/dashboard/src/grafana-dashboard-query.mjs +61 -0
- package/vendor/extension-read-only-toolkit/LICENSE +202 -0
- package/vendor/extension-read-only-toolkit/README.md +29 -0
- package/vendor/extension-read-only-toolkit/package.json +46 -0
- package/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +222 -0
- package/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +440 -0
- package/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +180 -0
- package/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +1 -0
- package/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +45 -0
- package/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +26 -0
- package/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +170 -0
- package/vendor/extension-workday-infra-access/LICENSE +202 -0
- package/vendor/extension-workday-infra-access/README.md +3 -0
- package/vendor/extension-workday-infra-access/agents/workday-infra-access-readonly.yaml +183 -0
- package/vendor/extension-workday-infra-access/package.json +49 -0
- package/vendor/extension-workday-infra-access/skills/workday-infra-access/SKILL.md +102 -0
- package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-boundary-runbook.md +43 -0
- package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-runbook.md +15 -0
- package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-scylla-cloud-runbook.md +39 -0
- package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-spc-argo-runbook.md +99 -0
- package/vendor/extension-workday-infra-access/src/workday-access-profiles.mjs +194 -0
- package/vendor/extension-workday-infra-access/tools/aws_cust_federated_readonly_command_pack.mjs +234 -0
- package/vendor/extension-workday-infra-access/tools/gcp_readonly_command_pack.mjs +167 -0
- package/vendor/extension-workday-infra-access/tools/public_cloud_access_status.mjs +48 -0
- package/vendor/extension-workday-infra-access/tools/workday_boundary_login.mjs +460 -0
- package/vendor/extension-workday-infra-access/tools/workday_private_cloud_sudo_readonly_command.mjs +386 -0
- package/vendor/extension-workday-infra-access/tools/workday_public_cloud_environment_map.mjs +189 -0
- package/vendor/extension-workday-infra-access/tools/workday_public_cloud_kubernetes_read.mjs +297 -0
- package/vendor/extension-workday-infra-access/tools/workday_public_cloud_spc_login.mjs +505 -0
- package/vendor/extension-workday-infra-access/tools/workday_spc_argo_readonly_command_pack.mjs +215 -0
- package/vendor/extension-workday-infra-access/workflows/public-cloud-readonly-investigation.js +99 -0
- package/workflows/bds-airflow-job-status-investigation.js +168 -0
- package/workflows/bds-disk-io-alert-investigation.js +173 -0
- package/workflows/bds-oncall-followup.js +112 -0
- package/workflows/bds-prism-service-proxy-timeout-investigation.js +69 -0
- package/workflows/bds-scylla-tenant-bucket-investigation.js +139 -0
- package/workflows/bds-tenant-data-operation-log-investigation.js +189 -0
- package/workflows/bds-yarn-app-health-investigation.js +217 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
export const description = "Generate a atomic-helper, read-only Scylla tenant bucket source/Kubernetes/S3A command pack; does not call Bitbucket, Kubernetes, or hadoop fs.";
|
|
2
|
+
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { defineReadOnlyTool, fail, ok } from "@nuvlore/extension-read-only-toolkit/devops-diagnostics";
|
|
5
|
+
import { ReadOnlyStep } from "@nuvlore/extension-read-only-toolkit/read-only-command-pack";
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_SCYLLA_BDM_POD,
|
|
8
|
+
DEFAULT_SCYLLA_NAMESPACE,
|
|
9
|
+
ScyllaAccessProfile
|
|
10
|
+
} from "@nuvlore/extension-workday-infra-access/src/workday-access-profiles.mjs";
|
|
11
|
+
|
|
12
|
+
const DEFAULT_CLUSTER = "s0130";
|
|
13
|
+
const DEFAULT_NAMESPACE = DEFAULT_SCYLLA_NAMESPACE;
|
|
14
|
+
const DEFAULT_BDM_POD = DEFAULT_SCYLLA_BDM_POD;
|
|
15
|
+
const DEFAULT_BDM_REPO_URL = "https://bitbucket.workday.com/projects/BDS/repos/sirius/browse";
|
|
16
|
+
const S0130_BDS_TENANT_BUCKET = "scylla-250478721519-wd-scylla-s0130-bds-tenant";
|
|
17
|
+
|
|
18
|
+
const SAFETY_RULES = [
|
|
19
|
+
"source-code-first: read BDM tenant-health code before concluding what unhealthy means",
|
|
20
|
+
"read-only only: kcsb get, ConfigMap reads, and hadoop fs list/read commands from a BDM pod",
|
|
21
|
+
"Bitbucket reads are read-only; local clone or pull is optional human-reviewed local cache work only",
|
|
22
|
+
"prefer BDM pods for S3A tenant bucket inspection because they carry the BDS Hadoop runtime",
|
|
23
|
+
"build and verify the SPC/Kubernetes connection first, then use either kcsb or an explicit kubeconfig-backed kubectl equivalent",
|
|
24
|
+
"never use hadoop fs -get for listing; it downloads data to the local filesystem",
|
|
25
|
+
"never use hadoop fs -put, -rm, -mkdir, -touchz, -mv, -cp, -chmod, -chown, or any write-oriented filesystem operation",
|
|
26
|
+
"do not use aws s3 inside BDM or bds-service-proxy pods as the observed path lacks AWS CLI credentials",
|
|
27
|
+
"do not assume hdfs exists in new BDM or bds-service-proxy images; use hadoop fs",
|
|
28
|
+
"never print tenant key material or decrypted file contents unless explicitly approved; prefer status-only decrypt/read probes",
|
|
29
|
+
"treat unauthenticated SIR curl 401 as reachability/auth-boundary evidence only, not as evidence for the real BDS authenticated key-fetch flow",
|
|
30
|
+
"do not use curl -k for SIR checks unless the URL is HTTPS; the observed in-cluster SIR endpoint uses HTTP"
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const clusterSchema = z
|
|
34
|
+
.string()
|
|
35
|
+
.min(1)
|
|
36
|
+
.max(64)
|
|
37
|
+
.regex(/^[A-Za-z0-9_.:-]+$/);
|
|
38
|
+
|
|
39
|
+
const kubernetesNameSchema = z
|
|
40
|
+
.string()
|
|
41
|
+
.min(1)
|
|
42
|
+
.max(253)
|
|
43
|
+
.regex(/^[a-z0-9]([-a-z0-9.]*[a-z0-9])?$/);
|
|
44
|
+
|
|
45
|
+
const bucketSchema = z
|
|
46
|
+
.string()
|
|
47
|
+
.min(3)
|
|
48
|
+
.max(255)
|
|
49
|
+
.regex(/^[a-z0-9][a-z0-9.-]*[a-z0-9]$/)
|
|
50
|
+
.optional();
|
|
51
|
+
|
|
52
|
+
const pathNameSchema = z
|
|
53
|
+
.string()
|
|
54
|
+
.min(1)
|
|
55
|
+
.max(160)
|
|
56
|
+
.regex(/^[A-Za-z0-9_.-]+$/)
|
|
57
|
+
.optional();
|
|
58
|
+
|
|
59
|
+
const urlSchema = z
|
|
60
|
+
.string()
|
|
61
|
+
.trim()
|
|
62
|
+
.url()
|
|
63
|
+
.max(2048)
|
|
64
|
+
.default(DEFAULT_BDM_REPO_URL);
|
|
65
|
+
|
|
66
|
+
class BdsScyllaTenantBucketCommandPack {
|
|
67
|
+
constructor(input) {
|
|
68
|
+
this.cluster = input.cluster ?? DEFAULT_CLUSTER;
|
|
69
|
+
this.namespace = input.namespace ?? DEFAULT_NAMESPACE;
|
|
70
|
+
this.bdmPod = input.bdmPod ?? DEFAULT_BDM_POD;
|
|
71
|
+
this.environmentName = input.environmentName;
|
|
72
|
+
this.tenantName = input.tenantName;
|
|
73
|
+
this.bdmRepoUrl = input.bdmRepoUrl ?? DEFAULT_BDM_REPO_URL;
|
|
74
|
+
this.bucketName = input.bucketName ?? (this.cluster === DEFAULT_CLUSTER ? S0130_BDS_TENANT_BUCKET : undefined);
|
|
75
|
+
this.scyllaAccess = new ScyllaAccessProfile({
|
|
76
|
+
cluster: this.cluster,
|
|
77
|
+
namespace: this.namespace,
|
|
78
|
+
bdmPod: this.bdmPod
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
bucketRef() {
|
|
83
|
+
return this.bucketName ?? "<bds-tenant.bucket.name from bucketdetails-config>";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
dataPath() {
|
|
87
|
+
return `s3a://${this.bucketRef()}/data/`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
tenantPath() {
|
|
91
|
+
if (!this.tenantName) {
|
|
92
|
+
return `s3a://${this.bucketRef()}/data/tenants/`;
|
|
93
|
+
}
|
|
94
|
+
const tenantSegment = this.environmentName
|
|
95
|
+
? `${this.environmentName}.${this.tenantName}`
|
|
96
|
+
: `<ENV_NAME>.${this.tenantName}`;
|
|
97
|
+
return `s3a://${this.bucketRef()}/data/tenants/${tenantSegment}/`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
brokenDsInfoPath() {
|
|
101
|
+
return `${this.tenantPath()}ted/opa/consistency_check/brokenDsInfo.json`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tenantFolderRule() {
|
|
105
|
+
return this.tenantName
|
|
106
|
+
? `data/tenants/${this.environmentName ? `${this.environmentName}.` : "<ENV_NAME>."}${this.tenantName}`
|
|
107
|
+
: "data/tenants/<ENV_NAME>.<tenantName>";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
commands() {
|
|
111
|
+
return [
|
|
112
|
+
new ReadOnlyStep({
|
|
113
|
+
id: "00-source-code-map",
|
|
114
|
+
purpose: "Read BDM source before interpreting tenant health so the RCA uses the real unhealthy criteria.",
|
|
115
|
+
command: [
|
|
116
|
+
"Use bitbucket_api_read on /rest/api/latest/projects/BDS/repos/sirius, or perform an optional HITL local cache clone:",
|
|
117
|
+
"git clone --filter=blob:none https://bitbucket.workday.com/scm/BDS/sirius.git <local-cache>/bds-sirius",
|
|
118
|
+
"Then search for tenant health code with read-only grep patterns: tenant health, TenantHealth, tenant_health, unhealthy, brokenDsInfo, consistency_check, operationsLog"
|
|
119
|
+
].join("\n"),
|
|
120
|
+
expectedEvidence: "source files and exact predicates that translate tenant data state into healthy/unhealthy status"
|
|
121
|
+
}),
|
|
122
|
+
new ReadOnlyStep({
|
|
123
|
+
id: "01-current-pods",
|
|
124
|
+
purpose: "Confirm BDM and related BDS pods in the connected Scylla customer namespace.",
|
|
125
|
+
command: "kcsb get pod",
|
|
126
|
+
expectedEvidence: "BDM pod names and readiness, especially bdm-0/bdm-1"
|
|
127
|
+
}),
|
|
128
|
+
new ReadOnlyStep({
|
|
129
|
+
id: "02-bucket-config",
|
|
130
|
+
purpose: "Read the source of truth for the tenant bucket name before using an S3A path.",
|
|
131
|
+
command: this.scyllaAccess.bucketConfigCommand(),
|
|
132
|
+
expectedEvidence: "data.bds-tenant.bucket.name and endpoint"
|
|
133
|
+
}),
|
|
134
|
+
new ReadOnlyStep({
|
|
135
|
+
id: "03-active-tenant-census",
|
|
136
|
+
purpose: "Separate active BDS tenants from stale or disabled tenant folders before judging blast radius.",
|
|
137
|
+
command: [
|
|
138
|
+
this.scyllaAccess.podExec(`curl -fsS --max-time 5 http://127.0.0.1:8083/metrics | awk -F\\" '/bds_stats_tenant_/ && /isActiveTenant=\\"true\\"/ {print $2}' | sort -u`),
|
|
139
|
+
this.scyllaAccess.podExec(`hadoop fs -ls s3a://${this.bucketRef()}/data/tenants/ | awk '/\\.<tenant-or-env-pattern>/ {print $NF}'`)
|
|
140
|
+
].join("\n"),
|
|
141
|
+
expectedEvidence: "active tenant names from BDM metrics and bucket tenant folders counted separately"
|
|
142
|
+
}),
|
|
143
|
+
new ReadOnlyStep({
|
|
144
|
+
id: "04-enter-bdm",
|
|
145
|
+
purpose: "Enter a BDM pod that has the BDS Hadoop runtime and hadoop fs command.",
|
|
146
|
+
command: `kcsb exec -it ${this.bdmPod} -- bash`,
|
|
147
|
+
expectedEvidence: "interactive shell prompt in the BDM pod"
|
|
148
|
+
}),
|
|
149
|
+
new ReadOnlyStep({
|
|
150
|
+
id: "05-list-data-root",
|
|
151
|
+
purpose: "List the tenant bucket data root with hadoop fs, not aws s3 or hdfs.",
|
|
152
|
+
command: `hadoop fs -ls ${this.dataPath()}`,
|
|
153
|
+
expectedEvidence: "data root listing, normally including data/tenants"
|
|
154
|
+
}),
|
|
155
|
+
new ReadOnlyStep({
|
|
156
|
+
id: "06-list-tenant-path",
|
|
157
|
+
purpose: "List the tenant-specific path when environment and tenant are known.",
|
|
158
|
+
command: `hadoop fs -ls ${this.tenantPath()}`,
|
|
159
|
+
expectedEvidence: "tenant path existence using data/tenants/<ENV_NAME>.<tenantName>, ownership, permissions, and normal children such as operationsLog.csv, ted, and tmp"
|
|
160
|
+
}),
|
|
161
|
+
new ReadOnlyStep({
|
|
162
|
+
id: "07-read-consistency-file",
|
|
163
|
+
purpose: "Read only the tenant consistency-check file when investigating unhealthy tenant status.",
|
|
164
|
+
command: `hadoop fs -cat ${this.brokenDsInfoPath()}`,
|
|
165
|
+
expectedEvidence: "broken dataset information or a clear file-not-found/access error"
|
|
166
|
+
}),
|
|
167
|
+
new ReadOnlyStep({
|
|
168
|
+
id: "08-key-fetch-and-decrypt-errors",
|
|
169
|
+
purpose: "Correlate BDM read failures with bds-service-proxy/SIR key-fetch and decrypt errors without exposing keys.",
|
|
170
|
+
command: [
|
|
171
|
+
this.scyllaAccess.podLogs({ pattern: `Exception while reading predefined file|Existing files are not readable|Failed attempt to read file|${this.tenantName ?? "<tenantName>"}` }),
|
|
172
|
+
"kcsb logs deploy/bds-service-proxy -c bds-service-proxy --since=4h | egrep 'Service unavailable|Response status: 503|Response code 503|BdsCipherClient|KMSClientException|Error in decrypt|<tenantName>'"
|
|
173
|
+
].join("\n"),
|
|
174
|
+
expectedEvidence: "specific timestamped BDM read error, SIR 503 key endpoint, BdsCipherClient decrypt error, and downstream 500/KMSClientException"
|
|
175
|
+
}),
|
|
176
|
+
new ReadOnlyStep({
|
|
177
|
+
id: "09-healthy-tenant-comparison",
|
|
178
|
+
purpose: "Compare with other active tenants to distinguish tenant-specific failure from cluster-wide BDM, bucket, or service-proxy failure.",
|
|
179
|
+
command: [
|
|
180
|
+
this.scyllaAccess.podLogs({ pattern: "Successfully read predefined file|Tenant \\[.*\\] is healthy" }),
|
|
181
|
+
"Optionally run status-only hadoop fs -cat >/dev/null checks for other active tenants; do not print key material or file contents."
|
|
182
|
+
].join("\n"),
|
|
183
|
+
expectedEvidence: "healthy active tenants completing the same predefined-file read/decrypt path"
|
|
184
|
+
}),
|
|
185
|
+
new ReadOnlyStep({
|
|
186
|
+
id: "10-sir-front-door-reachability",
|
|
187
|
+
purpose: "When the failure is a SIR key-fetch 503, distinguish service front-door reachability from the authenticated tenant-specific key-fetch result.",
|
|
188
|
+
command: [
|
|
189
|
+
"kcsb exec deploy/bds-service-proxy -c bds-service-proxy -- sh -lc 'for h in sir-<env>.sir sir-<env>.sir.svc sir-<env>.sir.svc.cluster.local; do getent hosts \"$h\" || nslookup \"$h\" || true; curl -sS -o /dev/null -w \"root_code=%{http_code} connect=%{time_connect} total=%{time_total}\\n\" --connect-timeout 3 --max-time 8 \"http://${h}:11710/\"; done'",
|
|
190
|
+
"kcsb exec deploy/bds-service-proxy -c bds-service-proxy -- sh -lc 'for t in <failingTenant> <healthyTenant1> <healthyTenant2>; do curl -sS -o /dev/null -w \"${t}_unauth_code=%{http_code} connect=%{time_connect} total=%{time_total}\\n\" --connect-timeout 3 --max-time 8 \"http://sir-<env>.sir:11710/internalapi/key/v1/${t}/bdstenant/encoded?kid=kid\"; done'"
|
|
191
|
+
].join("\n"),
|
|
192
|
+
expectedEvidence: "DNS resolution and quick 404/401 responses prove the SIR front door is reachable from bds-service-proxy; 401 from manual curl is unauthenticated probe evidence only"
|
|
193
|
+
}),
|
|
194
|
+
new ReadOnlyStep({
|
|
195
|
+
id: "11-cross-namespace-rbac-boundary",
|
|
196
|
+
purpose: "Before saying SIR, Galahad, OMS, or ORS pods/logs are missing or unavailable, verify whether the operator can read those namespaces.",
|
|
197
|
+
command: [
|
|
198
|
+
this.scyllaAccess.rbacBoundaryCommand(),
|
|
199
|
+
"If RBAC says no for sir/galahad/ors/oms, report that direct backend pod/log verification is blocked and route the tenant-specific 503 to the owning channel."
|
|
200
|
+
].join("\n"),
|
|
201
|
+
expectedEvidence: "RBAC yes/no for backend namespaces, separating lack of access from service availability claims"
|
|
202
|
+
})
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
antiPatterns() {
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
command: `aws s3 ls s3://${this.bucketRef()}/data/`,
|
|
210
|
+
reason: "Observed inside BDM and bds-service-proxy pods as NoCredentials."
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
command: `hdfs dfs -ls ${this.dataPath()}`,
|
|
214
|
+
reason: "New BDM and bds-service-proxy images may not include hdfs; KDC pods may lack the S3A class."
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
command: `hadoop fs -get ${this.dataPath()}`,
|
|
218
|
+
reason: "This downloads to local disk and can fail with local mkdir errors; it is not a list operation."
|
|
219
|
+
}
|
|
220
|
+
];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
toMarkdown() {
|
|
224
|
+
return [
|
|
225
|
+
"# BDS Scylla Tenant Bucket Read-Only Command Pack",
|
|
226
|
+
"",
|
|
227
|
+
`Cluster: ${this.cluster}`,
|
|
228
|
+
`Namespace: ${this.namespace}`,
|
|
229
|
+
`BDM pod: ${this.bdmPod}`,
|
|
230
|
+
this.bucketName ? `Bucket: ${this.bucketName}` : "Bucket: read from `bucketdetails-config` first",
|
|
231
|
+
`BDM repo: ${this.bdmRepoUrl}`,
|
|
232
|
+
this.environmentName ? `Environment: ${this.environmentName}` : "",
|
|
233
|
+
this.tenantName ? `Tenant: ${this.tenantName}` : "",
|
|
234
|
+
"",
|
|
235
|
+
"## Tenant Folder Rule",
|
|
236
|
+
"",
|
|
237
|
+
`Tenant folder: \`${this.tenantFolderRule()}\``,
|
|
238
|
+
"",
|
|
239
|
+
"A healthy discovered tenant folder commonly lists `operationsLog.csv`, `ted`, and `tmp` under that path.",
|
|
240
|
+
"Do not treat tenant folder count as active tenant count; use BDM metrics or EMS-derived BDM behavior for active BDS tenants.",
|
|
241
|
+
"For SIR key-fetch 503 cases, prove BDS-side reachability from `bds-service-proxy` before asking Galahad/OMS/ORS to inspect the backend. A manual unauthenticated HTTP 401 is only a reachability/auth-boundary signal; the real business-flow evidence comes from bds-service-proxy authenticated request logs.",
|
|
242
|
+
"Use `curl -k` only for HTTPS probes. The observed in-cluster SIR key endpoint is HTTP, so `-k` does not change that check.",
|
|
243
|
+
"",
|
|
244
|
+
"## Safety Boundary",
|
|
245
|
+
"",
|
|
246
|
+
...SAFETY_RULES.map((rule) => `- ${rule}`),
|
|
247
|
+
"",
|
|
248
|
+
"## Read-Only Commands",
|
|
249
|
+
"",
|
|
250
|
+
...this.commands().map((command) => command.toMarkdown()),
|
|
251
|
+
"",
|
|
252
|
+
"## Do Not Use",
|
|
253
|
+
"",
|
|
254
|
+
...this.antiPatterns().map((entry) => `- \`${entry.command}\`: ${entry.reason}`),
|
|
255
|
+
"",
|
|
256
|
+
"Procedure, interpretation, and RCA shape live in the `bds-scylla-tenant-bucket-investigation` skill and runbook."
|
|
257
|
+
].filter(Boolean).join("\n");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
toJson() {
|
|
261
|
+
return {
|
|
262
|
+
cluster: this.cluster,
|
|
263
|
+
namespace: this.namespace,
|
|
264
|
+
bdmPod: this.bdmPod,
|
|
265
|
+
bdmRepoUrl: this.bdmRepoUrl,
|
|
266
|
+
bucketName: this.bucketName,
|
|
267
|
+
environmentName: this.environmentName,
|
|
268
|
+
tenantName: this.tenantName,
|
|
269
|
+
scyllaAccess: this.scyllaAccess.toJson(),
|
|
270
|
+
tenantFolderRule: this.tenantFolderRule(),
|
|
271
|
+
expectedTenantChildren: ["operationsLog.csv", "ted", "tmp"],
|
|
272
|
+
sourceSearchPatterns: ["tenant health", "TenantHealth", "tenant_health", "unhealthy", "brokenDsInfo", "consistency_check", "operationsLog"],
|
|
273
|
+
activeTenantSignals: ["bds_stats_tenant_* isActiveTenant=\"true\"", "BDM getBDSTenants(Some(\"Active\")) health-check behavior"],
|
|
274
|
+
keyDecryptErrorSignals: ["SIR 503 Service Unavailable", "BdsCipherClient Error in decrypt", "KMSClientException Status code : 500"],
|
|
275
|
+
sirReachabilitySignals: ["bds-service-proxy DNS resolves SIR service", "manual unauthenticated SIR HTTP probe returns 404 or 401 quickly", "curl -k is irrelevant for HTTP endpoints"],
|
|
276
|
+
backendRbacBoundary: ["kubectl auth can-i get pods/services/endpoints/deployments.apps in sir", "galahad", "ors", "oms"],
|
|
277
|
+
safetyBoundary: SAFETY_RULES,
|
|
278
|
+
commands: this.commands().map((command) => command.toJson()),
|
|
279
|
+
antiPatterns: this.antiPatterns()
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function buildResponse(input) {
|
|
285
|
+
const commandPack = new BdsScyllaTenantBucketCommandPack(input);
|
|
286
|
+
if (input.format === "json") {
|
|
287
|
+
return JSON.stringify(commandPack.toJson(), null, 2);
|
|
288
|
+
}
|
|
289
|
+
return commandPack.toMarkdown();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const sharedTool = defineReadOnlyTool({
|
|
293
|
+
name: "bds_scylla_tenant_bucket_command_pack",
|
|
294
|
+
description: "Generate a atomic-helper, read-only Scylla tenant bucket source/Kubernetes/S3A command pack; does not call Bitbucket, Kubernetes, or hadoop fs.",
|
|
295
|
+
inputSchema: {
|
|
296
|
+
cluster: clusterSchema.default(DEFAULT_CLUSTER),
|
|
297
|
+
namespace: kubernetesNameSchema.default(DEFAULT_NAMESPACE),
|
|
298
|
+
bdmPod: kubernetesNameSchema.default(DEFAULT_BDM_POD),
|
|
299
|
+
bdmRepoUrl: urlSchema.describe("BDM source repository URL used to inspect tenant-health logic."),
|
|
300
|
+
environmentName: pathNameSchema.describe("Optional tenant environment name, for example WD504-IMPL."),
|
|
301
|
+
tenantName: pathNameSchema.describe("Optional tenant name, for example schellman1."),
|
|
302
|
+
bucketName: bucketSchema.describe("Optional bucket name. If omitted for s0130, the observed bds-tenant bucket is used; otherwise read bucketdetails-config first."),
|
|
303
|
+
format: z.enum(["markdown", "json"]).default("markdown")
|
|
304
|
+
},
|
|
305
|
+
annotations: { openWorldHint: true },
|
|
306
|
+
async handler(input) {
|
|
307
|
+
try {
|
|
308
|
+
return ok(buildResponse(input));
|
|
309
|
+
} catch (error) {
|
|
310
|
+
return fail(error);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
export default {
|
|
316
|
+
name: sharedTool.name,
|
|
317
|
+
description,
|
|
318
|
+
inputSchema: sharedTool.inputSchema,
|
|
319
|
+
meta: sharedTool.meta,
|
|
320
|
+
annotations: sharedTool.annotations,
|
|
321
|
+
invoke: sharedTool.invoke,
|
|
322
|
+
handler: sharedTool.handler
|
|
323
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const description = "Read private-cloud BDS service proxy HAProxy logs through the approved Boundary sudo read tool.";
|
|
2
|
+
|
|
3
|
+
import { createPrivateCloudLogReadTool, fixedPrivateLogSpec } from "../src/bds-atomic-log-tools.mjs";
|
|
4
|
+
|
|
5
|
+
const spec = fixedPrivateLogSpec({
|
|
6
|
+
toolName: "bds_service_proxy_log_read",
|
|
7
|
+
description: "Read private-cloud BDS service proxy HAProxy logs through the approved Boundary sudo read tool.",
|
|
8
|
+
path: "/var/log/haproxy.log"
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const __test = spec;
|
|
12
|
+
|
|
13
|
+
const sharedTool = createPrivateCloudLogReadTool(spec);
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
name: sharedTool.name,
|
|
17
|
+
description,
|
|
18
|
+
inputSchema: sharedTool.inputSchema,
|
|
19
|
+
meta: sharedTool.meta,
|
|
20
|
+
annotations: sharedTool.annotations,
|
|
21
|
+
invoke: sharedTool.invoke,
|
|
22
|
+
handler: sharedTool.handler
|
|
23
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const description = "Read private-cloud Spark History Server Kubernetes logs from the bds-k8s-services namespace through the approved Boundary sudo read tool.";
|
|
2
|
+
|
|
3
|
+
import { createPrivateCloudLogReadTool, PRIVATE_K8S_LOG_EXTRA_SCHEMA, privateK8sLogCommand } from "../src/bds-atomic-log-tools.mjs";
|
|
4
|
+
|
|
5
|
+
function buildCommand(input) {
|
|
6
|
+
return privateK8sLogCommand(input, {
|
|
7
|
+
namespace: "bds-k8s-services",
|
|
8
|
+
deployment: "bds-shs-shs-1",
|
|
9
|
+
container: "bds-shs"
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const __test = {
|
|
14
|
+
buildCommand
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const sharedTool = createPrivateCloudLogReadTool({
|
|
18
|
+
toolName: "bds_spark_historyserver_log_read",
|
|
19
|
+
description: "Read private-cloud Spark History Server Kubernetes logs from the bds-k8s-services namespace through the approved Boundary sudo read tool.",
|
|
20
|
+
extraSchema: PRIVATE_K8S_LOG_EXTRA_SCHEMA,
|
|
21
|
+
buildCommand
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: sharedTool.name,
|
|
26
|
+
description,
|
|
27
|
+
inputSchema: sharedTool.inputSchema,
|
|
28
|
+
meta: sharedTool.meta,
|
|
29
|
+
annotations: sharedTool.annotations,
|
|
30
|
+
invoke: sharedTool.invoke,
|
|
31
|
+
handler: sharedTool.handler
|
|
32
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const description = "Read SPAS-MT logs from a private-cloud SPAS-MT endpoint host through the approved Boundary sudo read tool.";
|
|
2
|
+
|
|
3
|
+
import { createPrivateCloudLogReadTool, fixedPrivateLogSpec } from "../src/bds-atomic-log-tools.mjs";
|
|
4
|
+
|
|
5
|
+
const spec = fixedPrivateLogSpec({
|
|
6
|
+
toolName: "bds_spas_mt_log_read",
|
|
7
|
+
description: "Read SPAS-MT logs from a private-cloud SPAS-MT endpoint host through the approved Boundary sudo read tool.",
|
|
8
|
+
path: "/data/workday-spas-mt/1.0.0/log/spas.log"
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const __test = spec;
|
|
12
|
+
|
|
13
|
+
const sharedTool = createPrivateCloudLogReadTool(spec);
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
name: sharedTool.name,
|
|
17
|
+
description,
|
|
18
|
+
inputSchema: sharedTool.inputSchema,
|
|
19
|
+
meta: sharedTool.meta,
|
|
20
|
+
annotations: sharedTool.annotations,
|
|
21
|
+
invoke: sharedTool.invoke,
|
|
22
|
+
handler: sharedTool.handler
|
|
23
|
+
};
|