Provide fallback for instance-id.

This commit is contained in:
Michael Lipp 2024-02-17 16:47:10 +01:00
parent 24f762d28c
commit 599f64da4c
3 changed files with 39 additions and 14 deletions

View file

@ -34,6 +34,9 @@
# ... # ...
# "userData": # "userData":
# ... # ...
#
# If .metaData.instance-id is missing, an id is generated from the
# config file's modification timestamp.
# Define the VM (required) # Define the VM (required)
"vm": "vm":

View file

@ -24,6 +24,8 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermission;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -39,9 +41,14 @@ import org.jdrupes.vmoperator.util.FsdUtils;
*/ */
@SuppressWarnings("PMD.ExcessivePublicCount") @SuppressWarnings("PMD.ExcessivePublicCount")
public class Configuration implements Dto { public class Configuration implements Dto {
private static final String CI_INSTANCE_ID = "instance-id";
@SuppressWarnings("PMD.FieldNamingConventions") @SuppressWarnings("PMD.FieldNamingConventions")
protected final Logger logger = Logger.getLogger(getClass().getName()); protected final Logger logger = Logger.getLogger(getClass().getName());
/** Configuration timestamp */
public Instant asOf;
/** The data dir. */ /** The data dir. */
public Path dataDir; public Path dataDir;
@ -259,6 +266,7 @@ public class Configuration implements Dto {
} }
checkDrives(); checkDrives();
checkCloudInit();
return true; return true;
} }
@ -372,4 +380,18 @@ public class Configuration implements Dto {
return true; return true;
} }
private void checkCloudInit() {
if (cloudInit == null) {
return;
}
// Provide default for instance-id
if (cloudInit.metaData == null) {
cloudInit.metaData = new HashMap<>();
}
if (!cloudInit.metaData.containsKey(CI_INSTANCE_ID)) {
cloudInit.metaData.put(CI_INSTANCE_ID, "v" + asOf.getEpochSecond());
}
}
} }

View file

@ -39,10 +39,10 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.time.Instant;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
@ -200,6 +200,7 @@ public class Runner extends Component {
.build()); .build());
private final JsonNode defaults; private final JsonNode defaults;
@SuppressWarnings("PMD.UseConcurrentHashMap") @SuppressWarnings("PMD.UseConcurrentHashMap")
private final File configFile;
private Configuration config = new Configuration(); private Configuration config = new Configuration();
private final freemarker.template.Configuration fmConfig; private final freemarker.template.Configuration fmConfig;
private CommandDefinition swtpmDefinition; private CommandDefinition swtpmDefinition;
@ -252,16 +253,16 @@ public class Runner extends Component {
attach(qemuMonitor = new QemuMonitor(channel())); attach(qemuMonitor = new QemuMonitor(channel()));
attach(new StatusUpdater(channel())); attach(new StatusUpdater(channel()));
// Configuration store with file in /etc/opt (default) configFile = new File(cmdLine.getOptionValue('c',
File config = new File(cmdLine.getOptionValue('c',
"/etc/opt/" + APP_NAME.replace("-", "") + "/config.yaml")); "/etc/opt/" + APP_NAME.replace("-", "") + "/config.yaml"));
// Don't rely on night config to produce a good exception // Don't rely on night config to produce a good exception
// for this simple case // for this simple case
if (!Files.isReadable(config.toPath())) { if (!Files.isReadable(configFile.toPath())) {
throw new IOException("Cannot read configuration file " + config); throw new IOException(
"Cannot read configuration file " + configFile);
} }
attach(new YamlConfigurationStore(channel(), config, false)); attach(new YamlConfigurationStore(channel(), configFile, false));
fire(new WatchFile(config.toPath())); fire(new WatchFile(configFile.toPath()));
} }
/** /**
@ -286,21 +287,20 @@ public class Runner extends Component {
@Handler @Handler
public void onConfigurationUpdate(ConfigurationUpdate event) { public void onConfigurationUpdate(ConfigurationUpdate event) {
event.structured(componentPath()).ifPresent(c -> { event.structured(componentPath()).ifPresent(c -> {
var newConf = yamlMapper.convertValue(c, Configuration.class);
newConf.asOf = Instant.ofEpochSecond(configFile.lastModified());
if (event instanceof InitialConfiguration) { if (event instanceof InitialConfiguration) {
processInitialConfiguration(c); processInitialConfiguration(newConf);
return; return;
} }
logger.fine(() -> "Updating configuration"); logger.fine(() -> "Updating configuration");
var newConf = yamlMapper.convertValue(c, Configuration.class);
rep.fire(new RunnerConfigurationUpdate(newConf, state)); rep.fire(new RunnerConfigurationUpdate(newConf, state));
}); });
} }
private void processInitialConfiguration( private void processInitialConfiguration(Configuration newConfig) {
Map<String, Object> runnerConfiguration) {
try { try {
config = yamlMapper.convertValue(runnerConfiguration, config = newConfig;
Configuration.class);
if (!config.check()) { if (!config.check()) {
// Invalid configuration, not used, problems already logged. // Invalid configuration, not used, problems already logged.
config = null; config = null;