레이블이 jq인 게시물을 표시합니다. 모든 게시물 표시
레이블이 jq인 게시물을 표시합니다. 모든 게시물 표시

argo-workflow parameter json escape

# argo-workflow parameter 로 json 형태를 전달 받았을떄
# single quotation 으로 감싸지 않으면 " escape 가 되지 않는다.

# test 
# argo worfklow version: 3.4.4
# workflow
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: ysoftman-test
  namespace: ysoftman-workflow
spec:
  serviceAccountName: workflow-template
  entrypoint: ysoftman
  templates:
    - name: ysoftman
      steps:
        - - name: ysoftman
            template: print-data
            arguments:
              parameters:
                - name: data1
                  value: "{\"a\":\"apple     lemon\"}"
                - name: data2
                  value: '{"b":"banana"}'

    - name: print-data
      inputs:
        parameters:
          - name: data1
          - name: data2
      script:
        image: "alpine"
        command: [sh]
        source: |
          echo '{{inputs.parameters.data1}}'
          echo '{{inputs.parameters.data2}}'
          echo '{{inputs.parameters}}'
          # invalid JSON 
          echo "{{inputs.parameters.data1}}"
          echo "{{inputs.parameters.data2}}"
          echo "{{inputs.parameters}}"
          # invalid JSON 
          echo {{inputs.parameters.data1}}
          echo {{inputs.parameters.data2}}
          echo {{inputs.parameters}}
          sleep 1000

# workflow pod log 결과
{"a":"apple     lemon"}
{"b":"banana"}
[{"name":"data1","value":"{\"a\":\"apple     lemon\"}"},{"name":"data2","value":"{\"b\":\"banana\"}"}]
{a:apple lemon}
{b:banana}
[{name:data1,value:{"a":"apple lemon"}},{name:data2,value:{"b":"banana"}}]
{a:apple     lemon}
{b:banana}
[{name:data1,value:{"a":"apple     lemon"}},{name:data2,value:{"b":"banana"}}]

#####

# data3 의 값이 json 이고 필드값으로 yaml, xml 등이 escaped 로 된 복잡한 파라메터인 경우 다음과 같이 처리해도 올바른 JSON 으로 출력되지 않는다.
echo '{{inputs.parameters.data3}}' # /argo/staging/script 에러
echo {{inputs.parameters.data3}} # " 가 빠진 invalid JSON
echo -e {{inputs.parameters.data3}} # "가 빠지고 \n 등에서 /argo/staging/script 에러

# jq 가 포함된 이지미를 사용해 script 에 다음과 같이 환경변수를 파싱해서 사용했다.
echo "$ARGO_TEMPLATE" | jq -r '.inputs.parameters[] | select(.name=="data3").value' | jq -r .workflow_yaml > /tmp/data.yaml

k8s pod log tool stern

# stern 커맨드를 사용하면 k8s 의 n 개의 pod 로그를 한번에 볼수 있다.
# ysoftman 네임스페이스의 aaa 이름(정규표현 가능) 로그 보기
stern "aaa" -n ysoftman

# 전체 네임스페이스에서 aaa 이름(정규표현 가능) 로그 보기
stern "aaa" -A

# 전체 네임스페이스에서 aaa 이름(정규표현 가능) 로그 보기
# 로그 중 json 포맷만 보기, jq 로 포맷팅해서 보면 좋다.
stern "aaa" -A -o json | jq

runc 사용하기

# runc 는 docker, kubernetes(k8s)등에서 사용하는 OCI(Open Container Initiative) 표준을 준수하는 container 기동(spawning and running) CLI 툴이다.

# golang 설치
wget https://go.dev/dl/go1.17.5.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local/ -zxf go1.17.5.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version

# runc 빌드 및 설치(최신 golang 버전 필요)
cd runc
make && sudo make install

# 일반유저(vagrant)도 docker 명령을 실행할 수 있게 vagrant 계정을 docker 그룹에 추가
# 한번 exit 하고 다시 로그인해야 한다.
sudo usermod -aG docker vagrant

# busybox 이미지의 파일시스템(파일들)을 tar 로 export
docker export $(docker create busybox) -o busybox_exported.tar

# root 계정으로 전환
sudo -Es

# container 에 압축 풀기
# runc 기동시 rootfs 이름의 디렉토리를 찾는다.
cd ~
mkdir -p ./ysoftman_container/rootfs
tar xvf busybox_exported.tar -C ./ysoftman_container/rootfs

# runc 에서 사용할 명세서 생성
# 기본 명세의 config.json 파일이 생성된다.
# spec -> create a new specification file
cd ysoftman_container
tree -L 2
runc spec
ls config.json

# runc 로 ysoftman1 이름의 컨테이너 기동
runc run ysoftman1

# ysoftman1 컨테이너에서 namespace 확인
ls -ahl /proc/$$/ns

# 호스트 터미널 하나더 열고 root 계정으로 전환
sudo -Es

# 호스트에서 runc 같와 runc 가 실행한 sh 프로세스가 확인
ps -ef | grep -E "runc| sh$"

# 호스트에서 
# runc 네임스페이스 확인
lsns -p $(ps -ef | grep -v grep | grep "runc run ysoftman1" | awk '{print $2}')

# ysoftman1컨테이너(runc)가 실행한 sh pid 로 namespace 상태 확인
lsns -p $(ps --ppid=$(ps -ef | grep -v grep | grep "runc run ysoftman1" | awk '{print $2}') -o pid | grep -v PID)

# 호스트에서 runc 로 기동된 컨테이너 리스트 보기
runc list

# 테스트 결과

# runc help
checkpoint  checkpoint a running container
create      create a container
delete      delete any resources held by the container often used with detached container
events      display container events such as OOM notifications, cpu, memory, and IO usage statistics
exec        execute new process inside the container
kill        kill sends the specified signal (default: SIGTERM) to the container's init process
list        lists containers started by runc with the given root
pause       pause suspends all processes inside the container
ps          ps displays the processes running inside a container
restore     restore a container from a previous checkpoint
resume      resumes all processes that have been previously paused
run         create and run a container
spec        create a new specification file
start       executes the user defined process in a created container
state       output the state of a container
update      update container resource constraints
features    show the enabled features

#####

# 위 golang, runc, busybox 준비되어 있는 상태에서
# rootless container 생성해 보기
# root 계정이라면 일반 계정으로 나오기
exit

# ysoftman_rootless_container 에 압축풀기
cd ~
mkdir -p ./ysoftman_rootless_container/rootfs
tar xvf busybox_exported.tar -C ./ysoftman_rootless_container/rootfs

# rootless 옵션으로 runc 에서 사용할 명세서 생성
cd ysoftman_rootless_container
runc spec --rootless

# /tmp/runc 를 루트로 하는 ysoftman_rootless_container 실행
runc --root /tmp/runc run ysoftman_rootless_container

# 컨터이너에서 user id 와 네임스페이스 확인
id
ls -l /proc/$$/ns

# 호스트에서
# 루트 경로 및 state.json 확인해보기
tree /tmp/runc
cat /tmp/runc/ysoftman_rootless_container/state.json | jq . | head -10

# 호스트에서 runc 같와 runc 가 실행한 sh 프로세스가 확인
ps -ef | grep -E "runc| sh$"

# runc 네임스페이스 확인
lsns -p $(ps -ef | grep -v grep | grep "runc run ysoftman_rootless_container" | awk '{print $2}')

# ysoftman1컨테이너(runc)가 실행한 sh pid 로 namespace 상태 확인
lsns -p $(ps --ppid=$(ps -ef | grep -v grep | grep "runc run ysoftman_rootless_container" | awk '{print $2}') -o pid | grep -v PID)

# user 네이스페이스 id 가 ysoftman_rootless_container 가 호스트와 다르다.
# ysoftman_rootless_container 의 root 로 보이지만 호스트의 root는 아니다.

# 테스트 결과

aws cli command

# AWS CLI 설치
https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/install-cliv2-mac.html
# mac
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /

# linux
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# AWS > IAM > 사용자 > 보안자격증명 > 액세스 키 만들기
# 액세스 키ID: xxxxx
# 비밀 액세스 키ID: xxxxx (액세스 키는 만들기 팝업에서만 보이기 때문에 이때 적어둬야함, 이때 못 보면 새로 만들어야함)
# AWS CLI 명령
# aws 접속 설정
aws configure
AWS Access Key ID [None]: xxxxx
AWS Secret Access Key [None]: xxxxx
Default region name [None]: ap-northeast-2
Default output format [None]: json

# aws 접속 설정 수정
vi ~/.aws/credentials
vi ~/.aws/config

# eks 연결 설정
aws eks update-kubeconfig --region ap-northeast-2 --name ysoftman-dev

# ecr 클라언트 인증
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin xxxxx.dkr.ecr.ap-northeast-2.amazonaws.com

# elb(classic) 리스트 파악
aws elb describe-load-balancers

# elb tag key 중 "ysoftman" 가 포함된 설정 보기
aws elb describe-load-balancers | rg -i loadbalancername | awk '{print $2}' | sed -e "s/\"//g" -e "s/,//g" | xargs aws elb describe-tags --load-balancer-names | jq '.TagDescriptions[] | select (.Tags[].Key | contains("ysoftman"))'

# elbv2(nlb, alb) 리스트 파악
aws elbv2 describe-load-balancers

# elbv2 LoadBalancerName 중 "ysoftman" 가 포함된 설정 보기 (arn 기준으로 찾는다.)
aws elbv2 describe-load-balancers | rg -i arn | awk '{print $2}' | sed -e "s/\"//g" -e "s/,//g" | xargs aws elbv2 describe-load-balancers --load-balancer-arns | jq '.LoadBalancers[] | select (.LoadBalancerName | contains("ysoftman"))'

# ec2 network acls 설정 보기
aws ec2 describe-network-acls


#####

# AWS > IAM > 사용자 > 권한 > 기존 정책 직접 연결 > AmazonS3FullAccess 선택 후 다음(권한추가)

# AWS > S3 > 버킷(bill-xxxxx) 생성 또는 
aws s3 mb s3://bill-xxxx

# s3 버킷 리스트(접속 확인)
aws s3 ls | grep bill-xxxxx

# billtest.txt 업로드
aws s3 cp billtest.txt s3://bill-xxxxx

# abc 디렉토리 업로드
aws s3 cp ./abc s3://bill-xxxxx/abc --recursive
# 또는 
aws s3 sync ./abc s3://bill-xxxxx/abc

# abc 디렉토리 삭제
aws s3 rm s3://bill-xxxxx/abc --recursive

JSON number type range

# json number 타입의 값이 커지면 사용하는 프로그램에 따라 값이 달라 질 수 있다.
# 다음과 같은 json_sample.json 이 있을때,
{
    "strval": "ysoftman",
    "intval1": -123456789123456789,
    "intval2": 123456789123456789,
    "intval3": 123456789123456789123456789123456789,
    "floatval1": -1.123456789123456789,
    "floatval2": 1.123456789123456789123456789,
    "floatval3": 1.123456789123456789123456789123456789
}
# JSON number 스펙을 보면 범위에 제한은 없지만
# JSON 을 사용하는 대부분의 프로그램이 IEEE754 64bit 의 범위 제한이 있다.
IEEE754 64bit 표준에 따라

# 2^64(9223372036854775808 ~ 9223372036854775807) 까지 표시할 수 있다.
# 이 범위를 넘어가면 int 타입은 0, float 타입은 범위 내까지만 표현된다.
{
    StrVal: "ysoftman",
    IntVal1: -123456789123456789,
    IntVal2: 123456789123456789,
    IntVal3: 0,
    FloatVal1: -1.1234567891234568,
    FloatVal2: 1.1234567891234568,
    FloatVal3: 1.1234567891234568
}

# jq 도 float 타입은 64bit 범위 까지만 지원한다.
# man jq : jq currently only has IEEE754 double-precision (64-bit) floating point number support 
# 하지만 정수형은 지수 형태로 최대한 표현된다.
# jq  . ./json_sample.json
{
  "strval": "ysoftman",
  "intval1": -123456789123456780,
  "intval2": 123456789123456780,
  "intval3": 1.2345678912345678e+35,
  "floatval1": -1.1234567891234568,
  "floatval2": 1.1234567891234568,
  "floatval3": 1.1234567891234568
}

# javascript JSON.parse() 도 jq 와 같은 결과
floatval1: -1.1234567891234568
floatval2: 1.1234567891234568
floatval3: 1.1234567891234568
intval1: -123456789123456780
intval2: 123456789123456780
intval3: 1.2345678912345678e+35
strval: "ysoftman"

jq command

# 커맨드 라인으로 json data 를 grep 할때 jq 를 사용하면 편하다.

# 맥에서 설치
brew install jq

# centos 에서 설치
yum install jq

# jq 를 이용한 json data grep
# 다음 test.json 있을때
cat > test.json << zzz
{
  "name": "bundling",
  "version": "1.0.0",
  "description": "테스트",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --watch",
    "build": "webpack -p"
  },
  "keywords": ["lemon", "orange", "apple"],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "webpack": "^3.10.0"
  },
  "aaa-bbb": "hypen-test",
  "aaa.bbb": "ccc",
  "aaa": { "bbb.ccc" : "ddd"},
  "arrayobj" : [
    {"name":"lemon", "price":200, "desc":"lemon_desc" },
    {"name":"apple", "price":300, "desc":"apple_desc" },
    {"name":"orange", "price":100, "desc":"orange_desc" }
  ]
}
zzz

# json 보기
jq . test.json

# json 여부 판단하기
# object, array 면 json
# number, string 등이면 json 이 아닌것으로 판단
jq type test.json

# script object 가져오기
jq .scripts test.json

# cat 과 파이프를 사용해도 된다.
# script object 가져오기
cat test.json | jq .scripts

# 키 이름만 가져오기
jq 'keys' test.json

# dependencies 아래 키 이름만 가져오기
jq '.dependencies|keys' test.json

# script.start 키 값 가져오기
jq .scripts.start test.json

# -r(--raw-output)을 사용하면 "aaa" -> aaa 로 "제거
jq -r .scripts.start test.json

# script 의 start 와 build 필드 값 가져오기
jq '.scripts | "\(.start) \(.build)"'  test.json

# keywords arrary 가져오기
jq .keywords test.json

# keywords 두번째 값 가져오기
jq ".keywords[1]" test.json

# keywords 0,1 원소 가져오기
jq ".keywords[:2]" test.json

# keywords 마지막 원소 가져오기
jq ".keywords[-1]" test.json

# keywords 값 순회하기
jq ".keywords[]" test.json

# keywords 원소 개수
jq ".keywords | length"  test.json

# keywords 와 arrayobj의 name 가져오기
jq '.keywords, .arrayobj[].name' test.json

# keywords 는 AA 필드명의 값으로 하는 오브젝트 와 arrayobj의 name은 BB 필드명의 값으로 해서 가져오기
jq '{"AA":.keywords}, {"BB":.arrayobj[].name}' test.json 

# AA 와 BB 를 하나의 오브젝트로 가져오기
jq '{"AA":.keywords, "BB":.arrayobj[].desc}' test.json

# 쉘 변수는 '$변수' 로 사용
var1="ysoftman"; jq '{"AA":.keywords, "BB":.arrayobj[].desc, "CC":"'${var1}'"}' test.json

# name 필드로 정렬(알파벳 오른 차순)
jq '.arrayobj | sort_by(.name)' test.json

# price 필드로 정렬(숫자 오름 차순)
jq '.arrayobj | sort_by(.price)' test.json

# sort_by 의 입력은 [](배열)이어야 한다.
# 입력 json 이 [] 아니라면 -s(--slurp)로 array 변경해서 처리한다.
jq '.arrayobj[]' test.json | jq -s 'sort_by(.price)'  

# 필드명에 . - 등이 있는 경우 ""안에 넣어야 한다.
# 참고로 https://jsonapi.org/format/#document-member-names 을 보면 . 은 필드명을 쓰지 말라고 한다.
jq '."aaa-bbb"' test.json
jq '."aaa.bbb"' test.json
jq '.aaa["bbb.ccc"]' test.json

# 오브젝트(mylist) 리스트 중 특정 필드(name)만 가져오기
jq ".mylist[]".name

# array 요소 중 name 필드값이 특정값인 경우만 가져오기
jq '.arrayobj[] | select(.name == "orange")' test.json

# array 요소 중 name 필드값이 "l" 이 포함된 경우만 가져오기
jq '.arrayobj[] | select(.name | contains ("l"))' test.json

# array 요소 중 name 필드값이 "l" 이 포함 안된 경우만 가져오기
jq '.arrayobj[] | select(.name | contains ("l") | not)' test.json

# addobj 추가하기
jq '. + {"addobj": {"field1": "added_field1", "field2": "added_field2"}}' test.json > test2.json

# author 와 main 필드 값 변경하기
jq '.author="ysoftman" | .main="main.js"' test.json > test2.json

# test2.json 에서 addobj.field2 삭제하기
jq 'del(.addobj.field1)' test2.json

# object list 만들기
echo '[]' | jq '.+[{"a":"aaa","a1":111},{"b":"bbb","b1":222}]'

#####

# mjson 으로 json pretty(indent,들여쓰기) 하기
# mjson 설치
sudo pip install mjson

# 들여쓰기 형태로 보기
echo '{"a":1,"b":2}' | mjson

#####

# jq-1.6 에서 다음과 같이 .[]로 사용하면 문법에러가 발생한다.
cat out.json | jq -r '.status.nodes.[]'
jq: error: syntax error, unexpected '[', expecting FORMAT or QQSTRING_START (Unix shell quoting issues?) at <top-level>, line 1:
.aaa.[]
jq: 1 compile error

# jq-1.6 에서는 다음과 같이 . 없이 사용해야 에러가 발생하지 않는다.
cat out.json | jq -r '.status.node[]'

# 참고로 jq-1.7.1 로 다운받아 실행하면 아래 2가지 방식 모두 된다.
wget https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux64
cat out.json | ./jq-linux64 -r '.status.nodes[]'
cat out.json | ./jq-linux64 -r '.status.nodes.[]'

#####

# interactive json viewer
# jq 쿼리문을 테스트할때 유용하다.