tayo 0.2.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/lib/tayo/commands/cf.rb +142 -121
- data/lib/tayo/commands/gh.rb +0 -9
- data/lib/tayo/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d2af6b108a756159090d922a64ba1e159590c4b0d0a17978c67a14794828f147
|
|
4
|
+
data.tar.gz: ef4333b8b9094ab0e040c330338cc61eaa4c9f13ea52a6cfc19354d7d3fcd92d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ae8aa7b218f16d90aec6ed99d7a0ee96884dd84b033faf6d359811c9d7105ea4ffc224d11093d626a207d6be15dc89b8eed74ae51c3991ff107ae263c851fcc
|
|
7
|
+
data.tar.gz: d6759cafa8c5c33ea27ab65c736109bb4575d2a9f658adbea2dec7b9a5f0ed827ed3e760a7f21581dca55767e73c7a33a5f0308bf68f90fe2619090a9e1315a4
|
data/lib/tayo/commands/cf.rb
CHANGED
|
@@ -12,61 +12,78 @@ module Tayo
|
|
|
12
12
|
def execute
|
|
13
13
|
puts "☁️ Cloudflare DNS 설정을 시작합니다...".colorize(:green)
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
puts "❌ Rails 프로젝트가 아닙니다. Rails 프로젝트 루트에서 실행해주세요.".colorize(:red)
|
|
17
|
-
return
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# 1. 도메인 입력받기
|
|
21
|
-
domain_info = get_domain_input
|
|
22
|
-
|
|
23
|
-
# 2. Cloudflare 토큰 생성 페이지 열기 및 권한 안내
|
|
15
|
+
# 1. Cloudflare 토큰 생성 페이지 열기 및 권한 안내
|
|
24
16
|
open_token_creation_page
|
|
25
|
-
|
|
26
|
-
#
|
|
17
|
+
|
|
18
|
+
# 2. 토큰 입력받기
|
|
27
19
|
token = get_cloudflare_token
|
|
28
|
-
|
|
29
|
-
#
|
|
20
|
+
|
|
21
|
+
# 3. Cloudflare API로 도메인 목록 조회 및 선택
|
|
30
22
|
selected_zone = select_cloudflare_zone(token)
|
|
31
|
-
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
|
|
23
|
+
|
|
24
|
+
# 4. 기존 레코드 목록 표시
|
|
25
|
+
show_existing_records(token, selected_zone)
|
|
26
|
+
|
|
27
|
+
# 5. 서비스 도메인 입력받기
|
|
28
|
+
domain_info = get_domain_input(selected_zone)
|
|
29
|
+
|
|
30
|
+
# 6. 홈서버 연결 정보 입력받기
|
|
31
|
+
server_info = get_server_info
|
|
32
|
+
|
|
33
|
+
# 7. DNS 레코드 추가/수정
|
|
34
|
+
setup_dns_record(token, selected_zone, domain_info, server_info)
|
|
35
|
+
|
|
36
|
+
# 8. config/deploy.yml 업데이트
|
|
37
|
+
update_deploy_config(domain_info, server_info)
|
|
40
38
|
|
|
41
39
|
puts "\n🎉 Cloudflare DNS 설정이 완료되었습니다!".colorize(:green)
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
# 변경사항 커밋
|
|
44
42
|
commit_cloudflare_changes(domain_info)
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
private
|
|
48
46
|
|
|
49
|
-
def
|
|
50
|
-
|
|
47
|
+
def get_domain_input(zone)
|
|
48
|
+
prompt = TTY::Prompt.new
|
|
49
|
+
zone_name = zone['name']
|
|
50
|
+
|
|
51
|
+
puts "📝 서비스 도메인을 설정합니다.".colorize(:yellow)
|
|
52
|
+
puts " 선택된 Zone: #{zone_name}".colorize(:gray)
|
|
53
|
+
|
|
54
|
+
use_subdomain = prompt.yes?("서브도메인을 사용하시겠습니까? (예: app.#{zone_name})")
|
|
55
|
+
|
|
56
|
+
if use_subdomain
|
|
57
|
+
subdomain = prompt.ask("서브도메인을 입력하세요 (예: app, api, www):") do |q|
|
|
58
|
+
q.validate(/\A[a-zA-Z0-9-]+\z/, "올바른 서브도메인을 입력해주세요 (영문, 숫자, 하이픈만 가능)")
|
|
59
|
+
end
|
|
60
|
+
full_domain = "#{subdomain}.#{zone_name}"
|
|
61
|
+
{ type: :subdomain, domain: full_domain, zone: zone_name, subdomain: subdomain }
|
|
62
|
+
else
|
|
63
|
+
{ type: :root, domain: zone_name, zone: zone_name }
|
|
64
|
+
end
|
|
51
65
|
end
|
|
52
66
|
|
|
53
|
-
def
|
|
67
|
+
def get_server_info
|
|
54
68
|
prompt = TTY::Prompt.new
|
|
55
|
-
|
|
56
|
-
puts "\n
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
q.validate(/\A
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# 도메인이 루트인지 서브도메인인지 판단
|
|
63
|
-
parts = domain.split('.')
|
|
64
|
-
if parts.length == 2
|
|
65
|
-
{ type: :root, domain: domain, zone: domain }
|
|
66
|
-
else
|
|
67
|
-
zone = parts[-2..-1].join('.')
|
|
68
|
-
{ type: :subdomain, domain: domain, zone: zone, subdomain: parts[0..-3].join('.') }
|
|
69
|
+
|
|
70
|
+
puts "\n🖥️ 홈서버 연결 정보를 입력합니다.".colorize(:yellow)
|
|
71
|
+
|
|
72
|
+
server_address = prompt.ask("홈서버 IP 또는 도메인을 입력하세요:") do |q|
|
|
73
|
+
q.validate(/\A.+\z/, "서버 정보를 입력해주세요")
|
|
69
74
|
end
|
|
75
|
+
|
|
76
|
+
ssh_user = prompt.ask("SSH 사용자 계정을 입력하세요:", default: "root")
|
|
77
|
+
|
|
78
|
+
# IP인지 도메인인지 판단
|
|
79
|
+
is_ip = server_address.match?(/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/)
|
|
80
|
+
record_type = is_ip ? 'A' : 'CNAME'
|
|
81
|
+
|
|
82
|
+
{
|
|
83
|
+
address: server_address,
|
|
84
|
+
ssh_user: ssh_user,
|
|
85
|
+
record_type: record_type
|
|
86
|
+
}
|
|
70
87
|
end
|
|
71
88
|
|
|
72
89
|
def open_token_creation_page
|
|
@@ -79,12 +96,10 @@ module Tayo
|
|
|
79
96
|
puts "\n다음 권한으로 토큰을 생성해주세요:".colorize(:yellow)
|
|
80
97
|
puts ""
|
|
81
98
|
puts "한국어 화면:".colorize(:gray)
|
|
82
|
-
puts "• 영역 → DNS → 읽기".colorize(:white)
|
|
83
99
|
puts "• 영역 → DNS → 편집".colorize(:white)
|
|
84
100
|
puts " (영역 리소스는 '모든 영역' 선택)".colorize(:gray)
|
|
85
101
|
puts ""
|
|
86
102
|
puts "English:".colorize(:gray)
|
|
87
|
-
puts "• Zone → DNS → Read".colorize(:white)
|
|
88
103
|
puts "• Zone → DNS → Edit".colorize(:white)
|
|
89
104
|
puts " (Zone Resources: Select 'All zones')".colorize(:gray)
|
|
90
105
|
puts ""
|
|
@@ -171,18 +186,53 @@ module Tayo
|
|
|
171
186
|
exit 1
|
|
172
187
|
end
|
|
173
188
|
|
|
174
|
-
def
|
|
189
|
+
def show_existing_records(token, zone)
|
|
175
190
|
puts "\n🔍 기존 DNS 레코드를 확인합니다...".colorize(:yellow)
|
|
176
|
-
|
|
191
|
+
|
|
177
192
|
zone_id = zone['id']
|
|
178
193
|
zone_name = zone['name']
|
|
179
|
-
|
|
180
|
-
#
|
|
181
|
-
records =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
194
|
+
|
|
195
|
+
# Zone의 모든 A/CNAME 레코드 조회
|
|
196
|
+
records = get_all_dns_records(token, zone_id, ['A', 'CNAME'])
|
|
197
|
+
|
|
198
|
+
if records.empty?
|
|
199
|
+
puts " 등록된 A/CNAME 레코드가 없습니다.".colorize(:gray)
|
|
200
|
+
else
|
|
201
|
+
puts " #{zone_name}의 기존 레코드:".colorize(:cyan)
|
|
202
|
+
records.each do |record|
|
|
203
|
+
puts " • #{record['name']} → #{record['content']} (#{record['type']})".colorize(:white)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
puts ""
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def get_all_dns_records(token, zone_id, types)
|
|
211
|
+
records = []
|
|
212
|
+
|
|
213
|
+
types.each do |type|
|
|
214
|
+
uri = URI("https://api.cloudflare.com/client/v4/zones/#{zone_id}/dns_records")
|
|
215
|
+
uri.query = URI.encode_www_form({ type: type })
|
|
216
|
+
|
|
217
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
218
|
+
http.use_ssl = true
|
|
219
|
+
|
|
220
|
+
request = Net::HTTP::Get.new(uri)
|
|
221
|
+
request['Authorization'] = "Bearer #{token}"
|
|
222
|
+
request['Content-Type'] = 'application/json'
|
|
223
|
+
|
|
224
|
+
response = http.request(request)
|
|
225
|
+
|
|
226
|
+
if response.code == '200'
|
|
227
|
+
data = JSON.parse(response.body)
|
|
228
|
+
records.concat(data['result'] || [])
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
records.sort_by { |r| r['name'] }
|
|
233
|
+
rescue => e
|
|
234
|
+
puts "⚠️ DNS 레코드 조회 중 오류: #{e.message}".colorize(:yellow)
|
|
235
|
+
[]
|
|
186
236
|
end
|
|
187
237
|
|
|
188
238
|
def get_dns_records(token, zone_id, name, types)
|
|
@@ -216,73 +266,41 @@ module Tayo
|
|
|
216
266
|
return []
|
|
217
267
|
end
|
|
218
268
|
|
|
219
|
-
def setup_dns_record(token, zone, domain_info,
|
|
269
|
+
def setup_dns_record(token, zone, domain_info, server_info)
|
|
220
270
|
puts "\n⚙️ DNS 레코드를 설정합니다...".colorize(:yellow)
|
|
221
|
-
|
|
222
|
-
# 홈서버 IP/URL 입력받기
|
|
223
|
-
prompt = TTY::Prompt.new
|
|
224
|
-
|
|
225
|
-
server_info = prompt.ask("홈서버 IP 또는 도메인을 입력하세요:") do |q|
|
|
226
|
-
q.validate(/\A.+\z/, "서버 정보를 입력해주세요")
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# SSH 사용자 계정 입력받기
|
|
230
|
-
ssh_user = prompt.ask("SSH 사용자 계정을 입력하세요:", default: "root")
|
|
231
|
-
|
|
232
|
-
# IP인지 도메인인지 판단
|
|
233
|
-
is_ip = server_info.match?(/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/)
|
|
234
|
-
record_type = is_ip ? 'A' : 'CNAME'
|
|
235
|
-
|
|
271
|
+
|
|
236
272
|
zone_id = zone['id']
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
273
|
+
target_domain = domain_info[:domain]
|
|
274
|
+
server_address = server_info[:address]
|
|
275
|
+
record_type = server_info[:record_type]
|
|
276
|
+
|
|
277
|
+
# 대상 도메인의 기존 A/CNAME 레코드 확인
|
|
278
|
+
existing_records = get_dns_records(token, zone_id, target_domain, ['A', 'CNAME'])
|
|
279
|
+
|
|
280
|
+
if existing_records.any?
|
|
281
|
+
existing_record = existing_records.first
|
|
282
|
+
|
|
248
283
|
# 동일한 타입이고 같은 값이면 건너뛰기
|
|
249
|
-
if existing_record['type'] == record_type && existing_record['content'] ==
|
|
284
|
+
if existing_record['type'] == record_type && existing_record['content'] == server_address
|
|
250
285
|
puts "✅ DNS 레코드가 이미 올바르게 설정되어 있습니다.".colorize(:green)
|
|
251
|
-
puts " #{
|
|
286
|
+
puts " #{target_domain} → #{server_address} (#{record_type} 레코드)".colorize(:gray)
|
|
252
287
|
else
|
|
253
288
|
# 타입이 다르거나 값이 다른 경우 삭제 후 재생성
|
|
254
289
|
puts "⚠️ 기존 레코드를 삭제하고 새로 생성합니다.".colorize(:yellow)
|
|
255
|
-
puts " 기존: #{existing_record['content']} (#{existing_record['type']}) → 새로운: #{
|
|
256
|
-
|
|
290
|
+
puts " 기존: #{existing_record['content']} (#{existing_record['type']}) → 새로운: #{server_address} (#{record_type})".colorize(:gray)
|
|
291
|
+
|
|
257
292
|
# 기존 레코드 삭제
|
|
258
293
|
delete_dns_record(token, zone_id, existing_record['id'])
|
|
259
|
-
|
|
294
|
+
|
|
260
295
|
# 새 레코드 생성
|
|
261
|
-
create_dns_record(token, zone_id,
|
|
296
|
+
create_dns_record(token, zone_id, target_domain, record_type, server_address)
|
|
262
297
|
end
|
|
263
298
|
else
|
|
264
299
|
# DNS 레코드 생성
|
|
265
|
-
create_dns_record(token, zone_id,
|
|
300
|
+
create_dns_record(token, zone_id, target_domain, record_type, server_address)
|
|
266
301
|
end
|
|
267
|
-
|
|
268
|
-
# 최종 도메인 정보 저장
|
|
269
|
-
@final_domain = final_domain[:full_domain]
|
|
270
|
-
@server_info = server_info
|
|
271
|
-
@ssh_user = ssh_user
|
|
272
|
-
end
|
|
273
302
|
|
|
274
|
-
|
|
275
|
-
case domain_info[:type]
|
|
276
|
-
when :root
|
|
277
|
-
if existing_records.any?
|
|
278
|
-
puts "⚠️ 루트 도메인에 이미 레코드가 있습니다. app.#{zone_name}을 사용합니다.".colorize(:yellow)
|
|
279
|
-
{ name: "app.#{zone_name}", full_domain: "app.#{zone_name}" }
|
|
280
|
-
else
|
|
281
|
-
{ name: zone_name, full_domain: zone_name }
|
|
282
|
-
end
|
|
283
|
-
when :subdomain
|
|
284
|
-
{ name: domain_info[:domain], full_domain: domain_info[:domain] }
|
|
285
|
-
end
|
|
303
|
+
puts " #{target_domain} → #{server_address}".colorize(:cyan)
|
|
286
304
|
end
|
|
287
305
|
|
|
288
306
|
def create_dns_record(token, zone_id, name, type, content)
|
|
@@ -340,53 +358,56 @@ module Tayo
|
|
|
340
358
|
exit 1
|
|
341
359
|
end
|
|
342
360
|
|
|
343
|
-
def update_deploy_config(domain_info)
|
|
361
|
+
def update_deploy_config(domain_info, server_info)
|
|
344
362
|
puts "\n📝 배포 설정을 업데이트합니다...".colorize(:yellow)
|
|
345
|
-
|
|
363
|
+
|
|
346
364
|
config_file = "config/deploy.yml"
|
|
347
|
-
|
|
365
|
+
final_domain = domain_info[:domain]
|
|
366
|
+
server_address = server_info[:address]
|
|
367
|
+
ssh_user = server_info[:ssh_user]
|
|
368
|
+
|
|
348
369
|
unless File.exist?(config_file)
|
|
349
370
|
puts "⚠️ config/deploy.yml 파일이 없습니다.".colorize(:yellow)
|
|
350
371
|
return
|
|
351
372
|
end
|
|
352
|
-
|
|
373
|
+
|
|
353
374
|
content = File.read(config_file)
|
|
354
|
-
|
|
375
|
+
|
|
355
376
|
# proxy.host 설정 업데이트
|
|
356
377
|
if content.include?("proxy:")
|
|
357
|
-
content.gsub!(/(\s+host:\s+).*$/, "\\1#{
|
|
378
|
+
content.gsub!(/(\s+host:\s+).*$/, "\\1#{final_domain}")
|
|
358
379
|
else
|
|
359
380
|
# proxy 섹션이 없으면 추가
|
|
360
|
-
proxy_config = "\n# Proxy configuration\nproxy:\n ssl: true\n host: #{
|
|
381
|
+
proxy_config = "\n# Proxy configuration\nproxy:\n ssl: true\n host: #{final_domain}\n"
|
|
361
382
|
content += proxy_config
|
|
362
383
|
end
|
|
363
|
-
|
|
384
|
+
|
|
364
385
|
# servers 설정 업데이트
|
|
365
386
|
if content.match?(/servers:\s*\n\s*web:\s*\n\s*-\s*/)
|
|
366
|
-
content.gsub!(/(\s*servers:\s*\n\s*web:\s*\n\s*-\s*)[\d.]+/, "\\1#{
|
|
387
|
+
content.gsub!(/(\s*servers:\s*\n\s*web:\s*\n\s*-\s*)[\d.]+/, "\\1#{server_address}")
|
|
367
388
|
end
|
|
368
|
-
|
|
389
|
+
|
|
369
390
|
# ssh user 설정 업데이트
|
|
370
|
-
if
|
|
391
|
+
if ssh_user && ssh_user != "root"
|
|
371
392
|
if content.match?(/^ssh:/)
|
|
372
393
|
# 기존 ssh 섹션 업데이트
|
|
373
|
-
content.gsub!(/^ssh:\s*\n\s*user:\s*\w+/, "ssh:\n user: #{
|
|
394
|
+
content.gsub!(/^ssh:\s*\n\s*user:\s*\w+/, "ssh:\n user: #{ssh_user}")
|
|
374
395
|
else
|
|
375
396
|
# ssh 섹션 추가 (accessories 섹션 앞에 추가)
|
|
376
397
|
if content.match?(/^# Use accessory services/)
|
|
377
|
-
content.gsub!(/^# Use accessory services/, "# Use a different ssh user than root\nssh:\n user: #{
|
|
398
|
+
content.gsub!(/^# Use accessory services/, "# Use a different ssh user than root\nssh:\n user: #{ssh_user}\n\n# Use accessory services")
|
|
378
399
|
else
|
|
379
400
|
# 파일 끝에 추가
|
|
380
|
-
content += "\n# Use a different ssh user than root\nssh:\n user: #{
|
|
401
|
+
content += "\n# Use a different ssh user than root\nssh:\n user: #{ssh_user}\n"
|
|
381
402
|
end
|
|
382
403
|
end
|
|
383
404
|
end
|
|
384
|
-
|
|
405
|
+
|
|
385
406
|
File.write(config_file, content)
|
|
386
407
|
puts "✅ config/deploy.yml이 업데이트되었습니다.".colorize(:green)
|
|
387
|
-
puts " proxy.host: #{
|
|
388
|
-
puts " servers.web: #{
|
|
389
|
-
puts " ssh.user: #{
|
|
408
|
+
puts " proxy.host: #{final_domain}".colorize(:gray)
|
|
409
|
+
puts " servers.web: #{server_address}".colorize(:gray)
|
|
410
|
+
puts " ssh.user: #{ssh_user}".colorize(:gray) if ssh_user && ssh_user != "root"
|
|
390
411
|
end
|
|
391
412
|
|
|
392
413
|
def commit_cloudflare_changes(domain_info)
|
data/lib/tayo/commands/gh.rb
CHANGED
|
@@ -12,11 +12,6 @@ module Tayo
|
|
|
12
12
|
def execute
|
|
13
13
|
puts "🚀 GitHub 저장소 및 컨테이너 레지스트리 설정을 시작합니다...".colorize(:green)
|
|
14
14
|
|
|
15
|
-
unless rails_project?
|
|
16
|
-
puts "❌ Rails 프로젝트가 아닙니다. Rails 프로젝트 루트에서 실행해주세요.".colorize(:red)
|
|
17
|
-
return
|
|
18
|
-
end
|
|
19
|
-
|
|
20
15
|
puts "\n[1/7] GitHub CLI 설치 확인".colorize(:blue)
|
|
21
16
|
check_github_cli
|
|
22
17
|
|
|
@@ -50,10 +45,6 @@ module Tayo
|
|
|
50
45
|
|
|
51
46
|
private
|
|
52
47
|
|
|
53
|
-
def rails_project?
|
|
54
|
-
File.exist?("Gemfile") && File.exist?("config/application.rb")
|
|
55
|
-
end
|
|
56
|
-
|
|
57
48
|
def check_github_cli
|
|
58
49
|
if system("gh --version", out: File::NULL, err: File::NULL)
|
|
59
50
|
puts "✅ GitHub CLI가 이미 설치되어 있습니다.".colorize(:green)
|
data/lib/tayo/version.rb
CHANGED