Prepare org reference inventory and stewardship assignment review
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e782-9f45-7382-afff-77ad665b88ec
This commit is contained in:
parent
25dd4626e0
commit
660c429838
19 changed files with 54017 additions and 19 deletions
52
tools/runtime_inventory.py
Normal file
52
tools/runtime_inventory.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Project only names, image paths and GitOps source fields; never query Secrets."""
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
from urllib.parse import urlsplit, urlunsplit
|
||||
|
||||
|
||||
def get(resource):
|
||||
r=subprocess.run(['kubectl','get',resource,'-A','-o','json'],capture_output=True,text=True)
|
||||
if r.returncode:
|
||||
raise RuntimeError('Read failed for '+resource)
|
||||
return json.loads(r.stdout)['items']
|
||||
|
||||
|
||||
def safe_url(value):
|
||||
p=urlsplit(value)
|
||||
return urlunsplit((p.scheme,p.hostname or '',p.path,'','')) if p.scheme else value.split('?')[0]
|
||||
|
||||
|
||||
def main():
|
||||
ap=argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument('--output',required=True)
|
||||
args=ap.parse_args()
|
||||
nodes=get('nodes')
|
||||
addresses={a['address'] for n in nodes for a in n.get('status',{}).get('addresses',[])}
|
||||
if '92.205.62.239' not in addresses:
|
||||
raise RuntimeError('Expected railiance01 node IP not found; refusing wrong-cluster capture')
|
||||
rows=[]
|
||||
for resource in ['deployments','statefulsets','daemonsets','jobs','cronjobs','services.serving.knative.dev','clusters.postgresql.cnpg.io']:
|
||||
for item in get(resource):
|
||||
spec=item.get('spec',{})
|
||||
pod=spec.get('jobTemplate',{}).get('spec',{}).get('template',{}).get('spec',{}) if item['kind']=='CronJob' else spec.get('template',{}).get('spec',{})
|
||||
images=sorted({c['image'] for key in ['containers','initContainers'] for c in pod.get(key,[]) if c.get('image')})
|
||||
if spec.get('imageName'): images.append(spec['imageName'])
|
||||
rows.append({'kind':item['kind'],'namespace':item['metadata'].get('namespace'),'name':item['metadata']['name'],
|
||||
'images':images,'image_pull_secret_names':sorted(x['name'] for x in pod.get('imagePullSecrets',[])),
|
||||
'owners':[{'kind':o['kind'],'name':o['name']} for o in item['metadata'].get('ownerReferences',[])]})
|
||||
apps=[]
|
||||
for i in get('applications.argoproj.io'):
|
||||
s=i['spec']; sources=s.get('sources',[])+([s['source']] if s.get('source') else [])
|
||||
apps.append({'name':i['metadata']['name'],'namespace':i['metadata']['namespace'],'project':s.get('project'),
|
||||
'sources':[{k:safe_url(v) if k=='repoURL' else v for k,v in src.items() if k in ['repoURL','path','chart','targetRevision']} for src in sources]})
|
||||
projects=[{'name':i['metadata']['name'],'namespace':i['metadata']['namespace'],
|
||||
'sourceRepos':[safe_url(x) for x in i['spec'].get('sourceRepos',[])]} for i in get('appprojects.argoproj.io')]
|
||||
result={'cluster':'railiance01','node_ip_verified':'92.205.62.239','coverage':'All namespaces; workload controller units, not pod/replicaset duplicates. Jobs may be historical; owners retained. Secrets never queried.',
|
||||
'workloads':sorted(rows,key=lambda r:(r['namespace'] or '',r['kind'],r['name'])),
|
||||
'applications':sorted(apps,key=lambda r:r['name']),'projects':sorted(projects,key=lambda r:r['name'])}
|
||||
with open(args.output,'w') as f: json.dump(result,f,indent=2,sort_keys=True);f.write('\n')
|
||||
print('Captured',len(rows),'controllers;',len(apps),'Applications;',len(projects),'AppProjects')
|
||||
|
||||
if __name__=='__main__': main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue