package io.fathom.auto.haproxy; import io.fathom.auto.TimeSpan; import java.io.File; import java.io.FileWriter; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HaproxyInstance { private static final Logger log = LoggerFactory.getLogger(HaproxyInstance.class); private HaproxyProcess haproxyProcess; private final HaproxyConfig config; public HaproxyInstance(HaproxyConfig config) { this.config = config; } public void run() throws IOException { File mirrorDir = new File("/var/haproxy/mirror/data"); File keysDir = new File("/var/haproxy/keys"); mkdirs(mirrorDir); mkdirs(keysDir); ConfigSync configSync = config.getConfigSync(mirrorDir); boolean firstSyncDone = false; while (!firstSyncDone) { boolean readOkay = false; try { int errors = configSync.firstSync(); if (errors == 0) { log.info("Completed initial sync successfully"); readOkay = true; } else { log.info("Errors while syncing; count={}", errors); } } catch (Exception e) { log.error("Error during initial sync", e); } if (readOkay) { try { installNewConfigFile(mirrorDir, keysDir); configSync.markClean(); firstSyncDone = true; } catch (Exception e) { log.error("Error installing haproxy config", e); } } TimeSpan.seconds(1).sleep(); } while (true) { try { // TODO: Subscribe for notifications?? log.info("Checking for DB updates"); int errors = configSync.refresh(); if (errors == 0) { log.info("Completed refresh successfully"); if (configSync.isDirty()) { try { installNewConfigFile(mirrorDir, keysDir); configSync.markClean(); } catch (Exception e) { log.error("Error installing haproxy config", e); } } TimeSpan.minutes(1).sleep(); } else { log.info("Errors during refresh: {}", errors); TimeSpan.seconds(1).sleep(); } } catch (Exception e) { log.error("Error during refresh", e); } } } private static void mkdirs(File dir) throws IOException { if (!dir.exists()) { if (!dir.mkdirs()) { throw new IOException("Unable to create directory: " + dir.getAbsolutePath()); } } } private void installNewConfigFile(File mirrorDir, File keysDir) throws IOException, InterruptedException { File tempFile = null; try { HaproxyConfigBuilder target = new HaproxyConfigBuilder(mirrorDir, keysDir, config.getSecretKeys()); target.setDefaultHost(config.getDefaultHost()); tempFile = File.createTempFile("haproxy", "cfg"); // TODO: Don't refresh every time?? log.warn("We refresh the secret keys every time"); config.getSecretKeys().refresh(); target.visitDir(target.getMirrorDir()); try (FileWriter writer = new FileWriter(tempFile)) { target.generateConfig(writer); } if (!HaproxyProcess.validate(tempFile)) { throw new IllegalStateException("Haproxy returned error when validating file"); } // TODO: Backup old config file?? log.info("Installing new config file"); tempFile.renameTo(HaproxyProcess.CONFIG_FILE); tempFile = null; ensureHaproxy(); } finally { if (tempFile != null) { tempFile.delete(); } } } private void ensureHaproxy() throws IOException, InterruptedException { if (haproxyProcess == null) { haproxyProcess = HaproxyProcess.find(); } if (haproxyProcess == null) { haproxyProcess = HaproxyProcess.start(); } else { haproxyProcess.reload(); } } }