samconfig.toml 에서 sam deploy 자동 y 설정하기

cmd log
1
2
3
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
  • deploy를 자주하다보면 이 y 누르는게 힘들다…

samconfig.toml 설정하기

samconfig.toml
1
2
3
4
5
6
7
8
9
10
version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "test-sam-app"
s3_bucket = "00000000000000000000000000000000000000000000000000000000000"
s3_prefix = "test-sam-app"
region = "ap-northeast-2"
confirm_changeset = false
capabilities = "CAPABILITY_IAM"
  • 처음 배포할때 -g옵션에서 설정했던것이 samconfig.toml에 저장되어있다
1
confirm_changeset = false
  • 여기서 confirm_changeset을 flase로 바꿔주면 중간에 확인 과정을 생략할 수 있다
  • 편안..!

sam 시작하기

  • sam을 이용해서 hello world 프로젝트 만들어 보기
  • nodejs로 만든다

전제조건

SAM(Serverless Application Model)

  • 겁나 어려워 보이는데 그냥 람다 생성기라고 생각하면 된다
  • 로컬에서 편하게 vscode로 람다함수짜고 yml 파일 수정해서..!
  • 로컬 테스트 환경도 제공한다!

따라하기

cmd
1
2
3
4
5
6
7
sam init

C:\tmp>sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice:
  • 1번, 1번해서
  • AWS Quick Start Templates, nodejs 를 골라준다
cmd
1
Project name [sam-app]: hello-world
  • 프로젝트명 설정하면, 샘플 프로젝트를 가져온다
cmd
1
2
3
4
5
6
7
8
9
10
AWS quick start application templates:
1 - Hello World Example
2 - Step Functions Sample App (Stock Trader)
3 - Quick Start: From Scratch
4 - Quick Start: Scheduled Events
5 - Quick Start: S3
6 - Quick Start: SNS
7 - Quick Start: SQS
8 - Quick Start: Web Backend
Template selection: 1
  • 1번 선택하여 헬로월드 템플릿을 받아온다
cmd
1
cd hello-world
  • 이제 생성된 프로젝트로 들어간다
1
2
3
4
5
6
7
8
9
10
11
.
├── events
│ └── event.json
├── hello-world
│ ├── tests/
│ ├── .npmignore
│ ├── app.js
│ └── package.json
├── .gitignore
├── README.md
└── template.yaml
  • 디렉터리 구조는 이러하다
  • 여기서 중요한 파일은 hello-world/app.jstemplate.yaml이다

  • 2개 파일 소스 대충 어떻게 생겼는지 봐보고 빌드해본다
cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sam build

C:\tmp\hello-world>sam build
Building function 'HelloWorldFunction'
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc

Build Succeeded

Built Artifacts : .aws-sam\build
Built Template : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
  • .aws-sam 이라는 폴더가 생성된다
1
2
3
4
5
6
7
.aws-sam
└── build
├── HelloWorldFunction
│ ├── node_modules/
│ ├── app.js
│ └── package.json
└── template.yaml
  • 이제 배포해보자
cmd
1
sam deploy -g
  • 배포하자. -g옵션은 --guided 와 동일하다
  • 이 옵션은 최초에 배포할때만 사용된다
cmd log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Configuring SAM deploy
======================

Looking for samconfig.toml : Not found

Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: test-sam-app
AWS Region [us-east-1]: ap-northeast-2
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to samconfig.toml [Y/n]: y
  • 먼저 Stack Name을 지정해준다. 공란으로 하면 sam-app으로 적용된다
  • 다음은 리전 설정이다. 나는 서울 ap-northeast-2로 지정했다
  • 다음은 전부다 y 해준다
cmd log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CloudFormation stack changeset
----------------
Operation LogicalResourceId ResourceType
----------------
+ Add HelloWorldFunctionHelloWorldPermissionProd AWS::Lambda::Permission
+ Add HelloWorldFunctionRole AWS::IAM::Role
+ Add HelloWorldFunction AWS::Lambda::Function
+ Add ServerlessRestApiDeployment47fc2d5f9d AWS::ApiGateway::Deployment
+ Add ServerlessRestApiProdStage AWS::ApiGateway::Stage
+ Add ServerlessRestApi AWS::ApiGateway::RestApi
----------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-2:111111111111:changeSet/samcli-deploy1600652952/89cf8cb3-a626-44ef-bd26-815dacedaa8e


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
  • 또 어쩌구 저쩌구 나오면서 마지막 확인을 받는데 y 해준다
cmd log
1
Successfully created/updated stack - test-sam-app in ap-northeast-2
  • 그러면 시간이 쫌 걸리면서 aws에 올라가게 된다

  • samconfig.toml 파일이 생성된 것을 확인할 수 있다

  • 이제 브라우저를 열어서 aws lambda 로 들어간다

  • 위와 같이 [스택네임]-HelloWorldFunction이름의 함수 하나가 생성되었다
  • 눌러서 들어간다
  • 이런 화면이 나온다
  • api 게이트웨이를 클릭한다. 그러면 아래 화면이 api 게이트웨이로 바뀐다. 거기서 다시 세부 정보를 클릭해서 api 엔드포인트를 확인한다
  • 엔드포인트를 눌러 접속한다
  • {"message":"hello world"}이 보이면 성공이다
  • 이렇게 다짜고짜 sam으로 람다를 만들어 보았다

해설

  • sam Hello World Example template를 이용해서 람다를 만들었다
  • 이 람다는 어떤 주소로 접속하면 hello world를 반환하는 람다이다
  • 현재 프로젝트 구조를 잘 살펴보면 sam을 익히면 된다
  • 먼저 이 {"message":"hello world"}는 어디서 왔을까?
hello-world/app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
exports.lambdaHandler = async (event, context) => {
try {
// const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: 'hello world',
// location: ret.data.trim()
}),
};
} catch (err) {
console.log(err);
return err;
}

return response;
};
  • lambdaHandler라는 함수가 있는데 response객체를 반환한다
  • 근데 우리는 {“message”:”hello world”} 만 보이니까 body에 있는 내용을 조작하면 우리가 원하는 내용을 보낼 수 있겠구나 생각할 수 있다
  • 그러면 이 함수를 실행시키는 트리거, s22xid3g26.execute-api.ap-northeast-2.amazonaws.com/Prod/hello
  • api 게이트웨이의 엔드포인트는 어디서 설정되었을까?
template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs12.x
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
  • template.yaml을 보면 Events 아래 Type: Api가 보인다
  • hello라는 Path로 get 요청이 왔을때 라고 이해할 수 있다

  • 이제 이를 토대로 람다를 업그레이드 해보자

124 나라 숫자

124 나라 숫자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// https://programmers.co.kr/learn/courses/30/lessons/12899
function solution12909(n) {
var answer = [];
var arr = '';
var N = n;

var seq = ['4', '1', '2'];
// console.log(seq[seq.length - 1]);
while (true) {
var tmp = n % 3;

answer.push(tmp);
// if (n <= 2) {
// break;
// }

if (tmp == 0) {
n = (n - tmp - 3) / 3;
} else {
n = (n - tmp) / 3;
}

if (n == 0) {
break;
}
}

while (answer.length != 0) {
arr += seq[answer.pop()];
}

// console.log(answer);
// console.log(N, arr);
// console.log("------------");
return arr;
}

해설

  • 124라는 나라의 이상한 진법으로 변환해야 하는 문제이다
  • 10진법 124 나라 10진법 124 나라
    1 1 6 14
    2 2 7 21
    3 4 8 22
    4 11 9 24
    5 12 10 41
  • 이렇게 이상한 숫자로 변환시키는 문제이다
  • 3진법 같아 보이지만 여기에는 함정이 있다….
  • 3진법이 아닌데 3개 숫자로만 표현해야한다
  • 경험으로 알게된.. 자릿수가 바뀔때 이상하게 바뀐다는 건데..
  • 나머지가 0이 될 경우에 == n이 3의 배수의 경우에 추가로 처리해줘야한다
  • 이해?를 돕기위해 그림을 그렸다
  • 왼쪽이 일반적인.. 상식적인 3진수이고
  • 오른쪽이 124 나라의 수이다
  • 중간은 124 나라의 수인데, 3진수와 시작을 똑같이 하기 위해 조작한 것이다
  • 3진수와 중간을 비교해보면 중간중간 정신나간 부분이 보인다
  • 이런 특징? 때문에 124나라는 적은 자릿수로 더 많은 숫자를 표현할 수 있다

  • 이문제는 해결법을 짠하고 알아냈다기보다
  • 계속 해보면서 알게된 규칙들을 적용시키면서 풀린거라
  • 설명을 잘 못하겠다..

  • 숫자 때문에 헷갈려 죽을뻔..
  • 아무튼 정신나간 124 나라이다

가장 큰 정사각형 찾기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// https://programmers.co.kr/learn/courses/30/lessons/12905
// 가장 큰 정사각형 찾기
function solution(board) {
var answer = 1;

var lownum = board.length;
var colnum = board[0].length;
console.log(lownum, colnum);

if (lownum == 1 || colnum == 1) {
var maxRow = board.map(function (row) {
return Math.max.apply(null, row);
});
var max = Math.max.apply(null, maxRow);

return max;
}

var max = 0;

for (var q = 1; q < board.length; q++) {
for (var w = 1; w < board[0].length; w++) {
if (board[q][w] == 0) {
continue;
}
var arr = [board[q - 1][w - 1], board[q - 1][w], board[q][w - 1]];
board[q][w] = Math.min.apply(null, arr) + 1;
max = Math.max(max, board[q][w]);
}
}

answer = max * max;

// console.log(maxRow, max);
console.log(answer);
return answer;
}

해설

  • 2차원 배열이 입력으로 들어온다

  • 2차월 연속된 1 이 이루는 가장 큰 정사각형의 넓이를 반환해야 한다

  • 먼저 입력된 보드가 행과 열 어느 하나가 1인 경우 1또는 0을 반환한다

  • 이제 1이 아닌 경우에 복잡해 지는데..

  • 0과 1로만 이루어진 보드를 갱신해 나갈거다

  • board[1][1] 부터 시작해서 이전 3개를 살펴볼것이다

  • 이때 board[1][1]이 0 이면 패스한다. 1이면 ㄱㄱ

  • 위, 왼쪽, 왼쪽 대각선위를 살펴서 가장 작은 숫자를 찾는다

  • 그런다음에 board[1][1]에 가장 작은 숫자 + 1을 대입한다

  • board[1][2] 로 이동해서 같은 것을 반복한다

  • 그림으로 보면 이렇다

  • step1] board[1][1] 일때

  • step1] board[1][2] 일때

  • 반복…

  • 결과]

  • 위 처럼 계속 갱신하고 보드에 마지막에 도달하면 끝이 난다

  • 이후에 board 내에서 가장 높은 숫자를 찾는다. 그러면 3이라는 숫자를 얻을 수 있다

  • 넓이를 반환하고 했으니까 3*3 해서 9를 반환하면 된다

완주하지 못한 선수

완주하지 못한 선수
1
2
3
4
5
6
7
8
9
10
11
12
13
// https://programmers.co.kr/learn/courses/30/lessons/42576
const solution = (participant, completion) => {
let objComletion = {};

completion.forEach((item) => {
!objComletion[item] ? (objComletion[item] = 1) : objComletion[item]++;
});

for (let i = 0; i < participant.length; i++)
if (!objComletion[participant[i]] || --objComletion[participant[i]] < 0)
return participant[i];
};
result = solution(['leo', 'kiki', 'eden'], ['eden', 'kiki']);
  • 효율성때문에 골치 아픈 문제

해설

  • solution(['leo', 'kiki', 'eden'], ['eden', 'kiki'])
  • 이런식으로 이름이 들어간 2개의 배열이 들어온다
  • 첫번째 배열은 참가자명단이고
  • 두번째 배열은 완주자명단이다
  • 완주하지 못한 사람을 반환하면 된다
  • 그런데 동명이인이 있을 수 있다
  • 중첩 반복문으로 풀다가 효율성에서 실패했다
  • 해쉬를 써서 풀라는데, 그러다 생각한데 객체를 만들어서 접근하는 방식이다..
  • objComletion라는 객체를 하나 생성하고
  • 반복분으로 objComletion.사람이름 으로 초기화한다
  • 초기화할때 멤버가 없으면 1로 초기화하고 이미 존재하면 ++해서 동명이인 처리를 했다
  • participant(참가자) 배열로 반목문을 돌면서 사람이름으로 다이렉트로 접근하니까 효율성이 엄청 좋아졌다
  • 멤버가 없거나, 0일경우 완주하지 못한 선수를 잡아낼 수 있다

잡담

  • 이 문제 풀면서 겉멋 코드에 맛들려서 안쓰던 화살표 함수도 쓰고…
  • 변수명 &, _ 이런거도 써봤다..ㅋㅋ
  • 효율성 획기적으로 줄여서 기분이 좋았다

모의고사

모의고사
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// https://programmers.co.kr/learn/courses/30/lessons/42840
function solution(answers) {
const a = [1, 2, 3, 4, 5];
const b = [2, 1, 2, 3, 2, 4, 2, 5];
const c = [3, 3, 1, 1, 2, 2, 4, 4, 5, 5];

let count = [0, 0, 0];
answers.forEach((element, index) => {
a[index % a.length] == element ? count[0]++ : null;
b[index % b.length] == element ? count[1]++ : null;
c[index % c.length] == element ? count[2]++ : null;
});
let result = [];
let max = Math.max.apply(null, count);
count.forEach((item, idx) => {
if (max == item) {
result.push(idx + 1);
}
});
return result;
}
solution([1, 2, 3, 4, 5]);

해설

  • 입력으로 정답 배열이 들어온다
  • a,b,c 세 사람이 있다
  • 사람마다 찍기 타입이 있다
  • 각자 자신만의 패턴으로 문제를 찍었을때 가장 문제를 많이 맞힌 사람을 반환한다
  • 일단 찍기타입을 정의하고,
  • 각 사람마다 정답이면 카운트를 늘린다!
  • 나머지 연산으로 패턴을 지속한다. c[index % c.length]
  • 그 중에서 가장 많이 맞춘 사람 배열을 반환한다. (1~다수)

체육복

체육복
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// https://programmers.co.kr/learn/courses/30/lessons/42862
function solution(n, lost, reserve) {
var answer = 0;

let arr = [];
for (let i = 0; i < n; i++) {
arr[i] = 1;
}

for (let i = 0; i < reserve.length; i++) {
arr[reserve[i] - 1]++;
}

for (let i = 0; i < lost.length; i++) {
arr[lost[i] - 1]--;
}

for (let i = 0; i < arr.length; i++) {
// 앞에사람꺼 빌리기
if (arr[i] == 0) {
if (arr[i - 1] == 2) {
arr[i - 1]--;
arr[i]++;
continue;
}
// 뒤에사람꺼 빌리기
else if (arr[i + 1] == 2) {
arr[i + 1]--;
arr[i]++;
continue;
}
}
}

const result = arr.filter((value, index) => {
return value != 0;
});

return result.length;
}
solution(5, [2, 4], [1, 3, 5]);

해설

  • 체육복을 입을 수 있는 사람의 수를 구하는 문제다
  • 체육복을 빌릴 수 있는데, 앞 뒤 사람의 체육복만 빌릴 수 있다
  • 먼저 arr 배열을 초기화한다. lost는 -1, reserve는 +1
  • 앞에서부터 순차적으로 앞사람확인하고 여벌이 있으면 빌린다
  • 앞사람없으면 뒤에서 빌린다

2016년

2016년
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// https://programmers.co.kr/learn/courses/30/lessons/12901
// 1월:31일
// 2월:29일
// 3월:31일
// 4월:30일
// 5월:31일
// 6월:30일
// 7월:31일
// 8월:31일
// 9월:30일
// 10월:31일
// 11월:30일
// 12월:31일
function solution(a, b) {
const days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const dow = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'];
let eachFirstDow = [5];
let tmp;
// setup process
for (let i = 1; i < a; i++) {
tmp = days[i - 1] % 7;
console.log(i + 1, dow[(eachFirstDow[i - 1] + tmp) % 7]);
eachFirstDow[i] = (eachFirstDow[i - 1] + tmp) % 7;
}
eachFirstDow.forEach((item) => {
console.log(dow[item]);
});
tmp = (b - 1) % 7;
return dow[(eachFirstDow[a - 1] + tmp) % 7];
}
result = solution(10, 1);
result = solution(5, 24);

해설

  • 2016년은 윤년이다
  • a월 b일을 입력받았을때 무슨요일인지 반환하는 문제이다
  • 나는 dow에 요일을 넣었다
  • 1월 1일은 무슨 요일인지 확인한다
  • 확인 결과 금요일이다
  • 첫번째 반복문에서 각 월 1일의 요일을 구한다
  • a월 1일의 요일에서 (b-1)일을 더하고 7로 나누면 해당일의 요일을 구할 수 있다

소수 찾기

소수 찾기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// https://programmers.co.kr/learn/courses/30/lessons/12921
function solution(n) {
var answer = 0;
let sosu = [];
let arr = {};
for (let i = 2; i <= n; i++) {
arr[i] = 1;
}

for (let index = 2; index <= n; index++) {
const element = arr[index];
if (element == 0) {
console.log('index', index);
continue;
}
sosu.push(index);
let a = 2;
// 지금 현재 값을
while (true) {
if (!(arr[index * a] + 1)) {
break;
}
arr[index * a++] = 0;
console.log(index * a);
}
}
console.log('소수:', sosu);
return sosu.length;
}
result = solution(10);
  • 효율성 통과하기 어려웠다

해설

  • 정수 n을 입력받으면 1부터 n 사이의 소수의 개수를 반환한다
  • 효율성을 통과할려면 에라토스테네스의 체를 써야한다
  • 에라토스테네스의 체 알고리즘을 구현한다
  • 글로 적힌거 봣는데 하나도 이해가 안되서, 위 그림을 보고 구현했다. (역시 그림이 최고!)
  • 첫번째 반복문에서 2부터 n까지 1로 초기화한다
  • 이제 2부터 n까지 반복문을 돈다
  • 처음에 2는 소수다. 소수 배열에 추가하고 while루프에서 arr배열에서 2의 2배수를 전부 지운다
  • 여기서 지운다는 것은 arr[2의배수] = 0 으로 만드는 것!
  • 그러면 다음 루프 3… 똑같이한다
  • 그다음 4에서 arr[4] == 0 이기때문에 바로 패스한다
  • … 반복
  • 내 글로된 설명보다 그림보는게 훨씬 이해에 빠를것이다!

에라토스테네스의 체

  • 소수를 찾는 방법

약수의 합

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// https://programmers.co.kr/learn/courses/30/lessons/12928
function solution(n) {
if (n == 0 || n == 1) {
return n;

let arr = [1, n];
console.log(Math.sqrt(n));
for (let index = 2; index <= Math.sqrt(n); index++) {
if (n % index == 0) {
arr.push(index);
if (index == Math.sqrt(n)) {
} else {
arr.push(n / index);
}
}
}
console.log(arr);
return arr.reduce((prev, curr) => {
console.log(prev, curr);
return curr + prev;
}, 0);
}
result = solution(12); //28

해설

  • 정수를 입력받으면 모든 약수의 합을 반환한다
  • 0, 1인 경우 바로 반환한다
  • 무조건 약수인 1과 자기자신으로 약수가 저장될 배열을 초기화한다
  • 2부터 n의 제곱근까지 반복문을 돌면서 나누어 떨어지는지 판단한다
  • 나누어 떨어지면 약수 배열에 추가한다
  • 약수는 항상 세트로 존재하기 때문에, 제곱근의 경우가 아니라면 n / index 도 약수로 추가한다
  • reduce로 약수배열의 합을 구한다