Skip to content

Instantly share code, notes, and snippets.

@ynott
Created December 16, 2024 08:39
Show Gist options
  • Save ynott/fa33d36f26f0e5c00f69c65564dbb456 to your computer and use it in GitHub Desktop.
Save ynott/fa33d36f26f0e5c00f69c65564dbb456 to your computer and use it in GitHub Desktop.
Ruby script that retrieves PowerDNS records and saves them in YML format (PowerDNSに保存されている既存のレコードを取得してYML形式で保存するRubyスクリプト)
#!/usr/bin/env ruby
require 'net/http'
require 'uri'
require 'json'
require 'yaml'
# UNSET Proxy
ENV['http_proxy'] = ''
ENV['https_proxy'] = ''
# PowerDNS APIの設定
API_URL = 'http://localhost:8081' # PowerDNS API URL
API_KEY = 'password' # API Secret here.
SERVER_ID = 'localhost' # Server ID ( Normally 'localhost' )
# リクエスト用ヘッダー
HEADERS = {
'X-API-Key' => API_KEY,
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
# デバッグモード
DEBUG = false
# HTTP接続のセットアップ
def setup_http_connection(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.open_timeout = 5 # 接続タイムアウトを5秒に設定
http.read_timeout = 10 # 読み取りタイムアウトを10秒に設定
http
end
# APIリクエストの実行
def make_api_request(uri, request_type = :get)
http = setup_http_connection(uri)
request = case request_type
when :get
Net::HTTP::Get.new(uri.request_uri, HEADERS)
else
raise "Unsupported request type: #{request_type}"
end
begin
puts "Making request to: #{uri}" if DEBUG
response = http.request(request)
unless response.is_a?(Net::HTTPSuccess)
raise "API request failed: #{response.code} - #{response.message}"
end
puts "Response body: #{response.body}" if DEBUG
JSON.parse(response.body)
rescue JSON::ParserError => e
raise "Failed to parse API response: #{e.message}"
rescue => e
raise "API request error: #{e.message}"
end
end
# ゾーン一覧の取得
def fetch_zones
begin
uri = URI.parse("#{API_URL}/servers/#{SERVER_ID}/zones")
response_data = make_api_request(uri)
response_data.map { |zone| zone['id'] }
rescue => e
puts "Error fetching zones: #{e.message}"
exit 1
end
end
# 個別ゾーンの詳細を取得(レコードを含む)
def fetch_zone_details(zone_id)
begin
uri = URI.parse("#{API_URL}/servers/#{SERVER_ID}/zones/#{URI.encode_www_form_component(zone_id)}")
zone_data = make_api_request(uri)
puts "\nZone data keys: #{zone_data.keys}" if DEBUG
# Ansibleプレイブック形式に変換
formatted_data = {
'name' => zone_data['name'],
'properties' => {
'kind' => zone_data['kind'],
'nameservers' => [], # NS レコードから抽出
'soa' => {}, # SOA レコードから抽出
'rrsets' => []
}
}
if zone_data['rrsets']
zone_data['rrsets'].each do |rrset|
case rrset['type']
when 'SOA'
# SOAレコードの処理
if rrset['records'] && !rrset['records'].empty?
soa_parts = rrset['records'].first['content'].split(' ')
formatted_data['properties']['soa'] = {
'mname' => soa_parts[0],
'rname' => soa_parts[1]
}
end
when 'NS'
# NSレコードの処理
formatted_data['properties']['nameservers'] = rrset['records'].map { |r| r['content'] }
else
# その他のレコードの処理
formatted_data['properties']['rrsets'] << {
'name' => rrset['name'],
'type' => rrset['type'],
'records' => rrset['records'].map { |r| { 'content' => r['content'] } }
}
end
end
end
formatted_data
rescue => e
puts "Error fetching details for zone #{zone_id}: #{e.message}"
nil
end
end
# ゾーンごとのレコードをYAML形式で保存
def save_zones_to_yaml(zone_ids)
# スクリプトのディレクトリを取得
script_dir = File.dirname(File.expand_path(__FILE__))
zone_ids.each do |zone_id|
begin
puts "\nProcessing zone: #{zone_id}" if DEBUG
# 各ゾーンの詳細情報を取得
zone = fetch_zone_details(zone_id)
next unless zone
# ゾーン名からファイル名を生成し、スクリプトのディレクトリと結合
file_name = "backup_#{zone['name'].chomp('.').gsub('/', '_')}.yaml"
full_path = File.join(script_dir, file_name)
# YAMLデータの生成
yaml_data = zone.to_yaml
# デバッグ情報
if DEBUG
puts "Zone data to be saved:"
puts yaml_data
puts "✓ Successfully saved #{file_name} (#{zone['properties']['rrsets']&.length || 0} records)"
else
puts zone['name'].chomp('.')
end
# ファイルに書き込み
File.open(full_path, 'w') { |file| file.write(yaml_data) }
rescue => e
puts "× Failed to save zone #{zone_id}: #{e.message}"
end
end
end
# メイン処理
begin
puts "Starting PowerDNS backup process..." if DEBUG
puts "Connecting to PowerDNS API at #{API_URL}" if DEBUG
zone_ids = fetch_zones
if zone_ids.empty?
puts "Warning: No zones found" if DEBUG
exit 0
end
puts "Found #{zone_ids.length} zones" if DEBUG
save_zones_to_yaml(zone_ids)
puts "Backup process completed successfully" if DEBUG
rescue => e
puts "Fatal error: #{e.message}"
exit 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment