/* * Copyright 2014 by SCSK Corporation. * * This file is part of PrimeCloud Controller(TM). * * PrimeCloud Controller(TM) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * PrimeCloud Controller(TM) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>. */ package jp.primecloud.auto.common.component; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import jp.primecloud.auto.exception.AutoException; import jp.primecloud.auto.util.CommandUtils; import jp.primecloud.auto.util.CommandUtils.CommandResult; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <p> * DNSサーバのレコードを制御するClassです。 * </p> * */ public class DnsStrategy implements DnsStrategyInterface { private static final Log log = LogFactory.getLog(DnsStrategy.class); protected String dnsServer; protected int timeToLive = 3600; /** * {@inheritDoc} */ @Override public void addForward(String fqdn, String ipAddress) { List<String> commands = createCommands(); List<String> stdins = createAddForward(fqdn, ipAddress); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // 正引きレコードの追加に失敗 AutoException exception = new AutoException("ECOMMON-000201", fqdn, ipAddress); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // 正引きの確認 long timeout = 10000L; long startTime = System.currentTimeMillis(); while (true) { String hostAddress = getHostAddress(fqdn); if (StringUtils.equals(ipAddress, hostAddress)) { break; } if (System.currentTimeMillis() - startTime > timeout) { // タイムアウト発生時 throw new AutoException("ECOMMON-000202", fqdn, ipAddress, hostAddress); } try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } /** * {@inheritDoc} */ @Override public void addReverse(String fqdn, String ipAddress) { List<String> commands = createCommands(); List<String> stdins = createAddReverse(fqdn, ipAddress); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // 逆引きレコードの追加に失敗 AutoException exception = new AutoException("ECOMMON-000203", fqdn, ipAddress); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // 逆引きの確認 long timeout = 10000L; long startTime = System.currentTimeMillis(); while (true) { String hostName = getHostName(ipAddress); if (StringUtils.equals(fqdn, hostName)) { break; } if (System.currentTimeMillis() - startTime > timeout) { // タイムアウト発生時 throw new AutoException("ECOMMON-000204", ipAddress, fqdn, hostName); } try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } /** * {@inheritDoc} */ @Override public void addCanonicalName(String fqdn, String canonicalName) { List<String> commands = createCommands(); List<String> stdins = createAddCanonicalName(fqdn, canonicalName); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // CNAMEレコードの追加に失敗 AutoException exception = new AutoException("ECOMMON-000205", fqdn, canonicalName); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // CNAMEの確認はしない(参照先ホスト名を解決できない場合もあるため) } /** * {@inheritDoc} */ @Override public void deleteForward(String fqdn) { List<String> commands = createCommands(); List<String> stdins = createDeleteForward(fqdn); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // 正引きレコードの削除に失敗 AutoException exception = new AutoException("ECOMMON-000207", fqdn); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // 正引きの確認 long timeout = 10000L; long startTime = System.currentTimeMillis(); while (true) { String hostAddress = getHostAddress(fqdn); if (hostAddress == null) { break; } if (System.currentTimeMillis() - startTime > timeout) { // タイムアウト発生時 throw new AutoException("ECOMMON-000208", fqdn, hostAddress); } try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } /** * {@inheritDoc} */ @Override public void deleteReverse(String ipAddress) { List<String> commands = createCommands(); List<String> stdins = createDeleteReverse(ipAddress); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // 逆引きレコードの削除に失敗 AutoException exception = new AutoException("ECOMMON-000209", ipAddress); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // 逆引きの確認 long timeout = 10000L; long startTime = System.currentTimeMillis(); while (true) { String hostName = getHostName(ipAddress); if (StringUtils.equals(ipAddress, hostName)) { break; } if (System.currentTimeMillis() - startTime > timeout) { // タイムアウト発生時 throw new AutoException("ECOMMON-000210", ipAddress, hostName); } try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } /** * {@inheritDoc} */ @Override public void deleteCanonicalName(String fqdn) { List<String> commands = createCommands(); List<String> stdins = createDeleteCanonicalName(fqdn); CommandResult result = execute(commands, stdins); if (result.getExitValue() != 0) { // CNAMEレコードの削除に失敗 AutoException exception = new AutoException("ECOMMON-000211", fqdn); exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE)); throw exception; } // CNAMEの確認 long timeout = 10000L; long startTime = System.currentTimeMillis(); while (true) { String cname = getCanonicalName(fqdn); if (cname == null) { break; } if (System.currentTimeMillis() - startTime > timeout) { // タイムアウト発生時 throw new AutoException("ECOMMON-000212", fqdn, cname); } try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } /** * 実行するコマンドを作成します。 * * @return */ protected List<String> createCommands() { List<String> commands = new ArrayList<String>(); commands.add("/usr/bin/nsupdate"); commands.add("-d"); return commands; } /** * 標準入力に与える内容の共通部分を作成します。 * * @return */ protected List<String> createStdinsCommon() { List<String> stdins = new ArrayList<String>(); stdins.add("server " + dnsServer); return stdins; } protected List<String> createAddForward(String fqdn, String ipAddress) { List<String> in = createStdinsCommon(); in.add("update delete " + fqdn + " IN A"); in.add("update add " + fqdn + " " + timeToLive + " IN A " + ipAddress); in.add("send"); in.add("quit"); return in; } protected List<String> createAddReverse(String fqdn, String ipAddress) { String reverseName = createReverseName(ipAddress); List<String> in = createStdinsCommon(); in.add("update delete " + reverseName + " IN PTR"); in.add("update add " + reverseName + " " + timeToLive + " IN PTR " + fqdn); in.add("send"); in.add("quit"); return in; } protected List<String> createAddCanonicalName(String fqdn, String canonicalName) { List<String> in = createStdinsCommon(); in.add("update delete " + fqdn + " IN CNAME"); in.add("update add " + fqdn + " " + timeToLive + " IN CNAME " + canonicalName); in.add("send"); in.add("quit"); return in; } protected List<String> createDeleteForward(String fqdn) { List<String> in = createStdinsCommon(); in.add("update delete " + fqdn + " IN A"); in.add("send"); in.add("quit"); return in; } protected List<String> createDeleteReverse(String ipAddress) { String reverseName = createReverseName(ipAddress); List<String> in = createStdinsCommon(); in.add("update delete " + reverseName + " IN PTR"); in.add("send"); in.add("quit"); return in; } protected List<String> createDeleteCanonicalName(String fqdn) { List<String> in = createStdinsCommon(); in.add("update delete " + fqdn + " IN CNAME"); in.add("send"); in.add("quit"); return in; } protected String createReverseName(String ipAddress) { // 逆引きレコード名の作成 StringBuilder reverseName = new StringBuilder(); String[] splits = StringUtils.split(ipAddress, '.'); for (int i = splits.length - 1; i >= 0; i--) { reverseName.append(splits[i]).append('.'); } reverseName.append("in-addr.arpa"); return reverseName.toString(); } protected CommandResult execute(List<String> commands, List<String> stdins) { if (log.isDebugEnabled()) { log.debug(commands); log.debug(stdins); } CommandResult result = CommandUtils.execute(commands, stdins); if (log.isDebugEnabled()) { log.debug(ReflectionToStringBuilder.toString(result)); } return result; } protected String getHostAddress(String fqdn) { try { InetAddress address = InetAddress.getByName(fqdn); return address.getHostAddress(); } catch (UnknownHostException e) { return null; } } protected String getHostName(String ipAddress) { byte[] addr = new byte[4]; String[] octets = StringUtils.split(ipAddress, ".", 4); for (int i = 0; i < 4; i++) { addr[i] = (byte) Integer.parseInt(octets[i]); } InetAddress address; try { address = InetAddress.getByAddress(addr); return address.getCanonicalHostName(); } catch (UnknownHostException e) { return null; } } protected String getCanonicalName(String fqdn) { try { InetAddress address = InetAddress.getByName(fqdn); return address.getCanonicalHostName(); } catch (UnknownHostException e) { return null; } } /** * dnsServerを設定します。 * * @param dnsServer dnsServer */ public void setDnsServer(String dnsServer) { this.dnsServer = dnsServer; } /** * timeToLiveを設定します。 * * @param timeToLive timeToLive */ public void setTimeToLive(int timeToLive) { this.timeToLive = timeToLive; } }