aboutsummaryrefslogtreecommitdiffstats
path: root/config-model-api/src/main/java
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /config-model-api/src/main/java
Publish
Diffstat (limited to 'config-model-api/src/main/java')
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationFile.java179
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationMetaData.java149
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java260
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ComponentInfo.java21
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeployLogger.java16
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java182
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/FileRegistry.java35
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/RuleConfigDeriver.java14
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/UnparsedConfigDefinition.java14
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/package-info.java7
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java42
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java22
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java19
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java23
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java13
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java10
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java14
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java28
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java48
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java33
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/Model.java99
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java43
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java28
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java39
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java9
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java46
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java87
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java5
28 files changed, 1485 insertions, 0 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationFile.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationFile.java
new file mode 100644
index 00000000000..585fb6902ab
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationFile.java
@@ -0,0 +1,179 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import com.yahoo.path.Path;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An application file represents a file within an application package. This class can be used to traverse the entire
+ * application package file structure, as well as read and write files to it, and create directories.
+ *
+ * @author lulf
+ * @since 5.1
+ */
+public abstract class ApplicationFile implements Comparable<ApplicationFile> {
+ private static final String metaDir = ".meta";
+ public static final String ContentStatusNew = "new";
+ public static final String ContentStatusChanged = "changed";
+ public static final String ContentStatusDeleted = "deleted";
+ protected final Path path;
+ private static final PathFilter defaultFilter = path1 -> true;
+
+ protected ApplicationFile(Path path) {
+ this.path = path;
+ }
+
+ /**
+ * Check whether or not this file is a directory.
+ *
+ * @return true if it is, false if not.
+ */
+ public abstract boolean isDirectory();
+
+ /**
+ * Test whether or not this file exists.
+ *
+ * @return true if it exists, false if not.
+ */
+ public abstract boolean exists();
+
+ /**
+ * Create a {@link Reader} for the contents of this file.
+ *
+ * @return A {@link Reader} that should be closed after use.
+ * @throws FileNotFoundException if the file is not found.
+ */
+ public abstract Reader createReader() throws FileNotFoundException;
+
+
+ /**
+ * Create an {@link InputStream} for the contents of this file.
+ *
+ * @return An {@link InputStream} that should be closed after use.
+ * @throws FileNotFoundException if the file is not found.
+ */
+ public abstract InputStream createInputStream() throws FileNotFoundException;
+
+ /**
+ * Create a directory at the path represented by this file. Parent directories will
+ * be automatically created.
+ *
+ * @return this
+ * @throws IllegalArgumentException if the directory already exists.
+ */
+ public abstract ApplicationFile createDirectory();
+
+ /**
+ * Write the contents from this reader to this file. Any existing content will be overwritten!
+ *
+ * @param input A reader pointing to the content that should be written.
+ * @return this
+ */
+ public abstract ApplicationFile writeFile(Reader input);
+
+ /**
+ * List the files under this directory. If this is file, an empty list is returned.
+ * Only immediate files/subdirectories are returned.
+ *
+ * @return a list of files in this directory.
+ */
+ public List<ApplicationFile> listFiles() {
+ return listFiles(defaultFilter);
+ }
+
+ /**
+ * List the files under this directory. If this is file, an empty list is returned.
+ * Only immediate files/subdirectories are returned.
+ *
+ * @param filter A filter functor for filtering path names
+ * @return a list of files in this directory.
+ */
+ public abstract List<ApplicationFile> listFiles(PathFilter filter);
+
+ /**
+ * List the files in this directory, optionally list files for subdirectories recursively as well.
+ *
+ * @param recurse Set to true if all files in the directory tree should be returned.
+ * @return a list of files in this directory.
+ */
+ public List<ApplicationFile> listFiles(boolean recurse) {
+ List<ApplicationFile> ret = new ArrayList<>();
+ List<ApplicationFile> files = listFiles();
+ ret.addAll(files);
+ if (recurse) {
+ for (ApplicationFile file : files) {
+ if (file.isDirectory()) {
+ ret.addAll(file.listFiles(recurse));
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Delete the file pointed to by this. If it is a non-empty directory, the operation will throw.
+ *
+ * @return this.
+ * @throws RuntimeException if the file is a directory and not empty.
+ */
+ public abstract ApplicationFile delete();
+
+ /**
+ * Get the path that this file represents.
+ *
+ * @return a Path
+ */
+ public Path getPath() {
+ return path;
+ }
+
+ @Override
+ public String toString() {
+ return path.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ApplicationFile) {
+ return path.equals(((ApplicationFile) other).path);
+ }
+ return false;
+ }
+
+ protected Path getMetaPath() {
+ if (path.toString().equals("")) {
+ return Path.fromString(metaDir).append(".root");
+ } else {
+ return path.getParentPath().append(metaDir).append(path.getName());
+ }
+ }
+
+ public abstract MetaData getMetaData();
+
+ public static class MetaData {
+ public String status = "unknown";
+ public String md5 = "";
+
+ public MetaData() { }
+
+ public MetaData(String status, String md5) {
+ this.status = status;
+ this.md5= md5;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public String getMd5() {
+ return md5;
+ }
+ }
+
+ public static interface PathFilter {
+ boolean accept(Path path);
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationMetaData.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationMetaData.java
new file mode 100644
index 00000000000..98d5fa92cac
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationMetaData.java
@@ -0,0 +1,149 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import com.yahoo.slime.*;
+
+import com.yahoo.text.Utf8;
+
+import java.io.*;
+
+/**
+ * Metadata about an application package.
+ *
+ * @author musum
+ * @since 5.0
+ */
+public class ApplicationMetaData {
+ private final String deployedByUser;
+ private final String deployedFromDir;
+ private final long deployTimestamp;
+ private final long generation;
+ private final long previousActiveGeneration;
+ private final String checkSum;
+ private final String appName;
+
+ public ApplicationMetaData(File appDir, String deployedByUser, String deployedFromDir, Long deployTimestamp,
+ String checkSum, Long generation, long previousActiveGeneration) {
+ this(deployedByUser, deployedFromDir, deployTimestamp, appDir.getName(), checkSum, generation, previousActiveGeneration);
+ }
+
+ public ApplicationMetaData(String deployedByUser, String deployedFromDir, Long deployTimestamp, String applicationName, String checkSum, Long generation, long previousActiveGeneration) {
+ this.appName = applicationName;
+ this.deployedByUser = deployedByUser;
+ this.deployedFromDir = deployedFromDir;
+ this.deployTimestamp = deployTimestamp;
+ this.checkSum = checkSum;
+ this.generation = generation;
+ this.previousActiveGeneration = previousActiveGeneration;
+ }
+
+ /**
+ * Gets the name of the application (name of the directory from which application was deployed.
+ * Will return null if a problem occurred while getting metadata
+ *
+ * @return application name
+ */
+ public String getApplicationName() {
+ return appName;
+ }
+
+ /**
+ * Gets the user who deployed the application.
+ * Will return null if a problem occurred while getting metadata
+ *
+ * @return user name for the user who ran "deploy-application"
+ */
+ public String getDeployedByUser() {
+ return deployedByUser;
+ }
+
+ /**
+ * Gets the directory where the application was deployed from.
+ * Will return null if a problem occurred while getting metadata
+ *
+ * @return path to raw deploy directory (for the original application)
+ */
+ public String getDeployPath() {
+ return deployedFromDir;
+ }
+
+ /**
+ * Gets the time the application was deployed
+ * Will return null if a problem occurred while getting metadata
+ *
+ * @return timestamp for when "deploy-application" was run. In ms.
+ */
+ public Long getDeployTimestamp() {
+ return deployTimestamp;
+ }
+
+ /**
+ * Gets the time the application was deployed
+ * Will return null if a problem occurred while getting metadata
+ *
+ * @return timestamp for when "deploy-application" was run. In ms.
+ */
+ public Long getGeneration() {
+ return generation;
+ }
+
+ /**
+ * Returns an md5 hash of the contents of the application package
+ * @return an md5sum of the application package
+ */
+ public String getCheckSum() {
+ return checkSum;
+ }
+
+ /**
+ * Returns the previously active generation at the point when this application was created.
+ * @return a generation.
+ */
+ public long getPreviousActiveGeneration() {
+ return previousActiveGeneration;
+ }
+
+ @Override
+ public String toString() {
+ return deployedByUser + ", " + deployedFromDir + ", " + deployTimestamp + ", " + generation + ", " + checkSum + ", " + previousActiveGeneration;
+ }
+
+ public static ApplicationMetaData fromJsonString(String jsonString) {
+ try {
+ Slime data = new Slime();
+ new JsonDecoder().decode(data, Utf8.toBytes(jsonString));
+ Inspector root = data.get();
+ Inspector deploy = root.field("deploy");
+ Inspector app = root.field("application");
+ return new ApplicationMetaData(deploy.field("user").asString(), deploy.field("from").asString(), deploy.field("timestamp").asLong(), app.field("name").asString(), app.field("checksum").asString(), app.field("generation").asLong(), app.field("previousActiveGeneration").asLong());
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Error parsing json metadata", e);
+ }
+ }
+
+ public Slime getSlime() {
+ Slime slime = new Slime();
+ Cursor meta = slime.setObject();
+ Cursor deploy = meta.setObject("deploy");
+ deploy.setString("user", deployedByUser);
+ deploy.setString("from", deployedFromDir);
+ deploy.setLong("timestamp", deployTimestamp);
+ Cursor app = meta.setObject("application");
+ app.setString("name", appName);
+ app.setString("checksum", checkSum);
+ app.setLong("generation", generation);
+ app.setLong("previousActiveGeneration", previousActiveGeneration);
+ return slime;
+ }
+
+ public String asJsonString() {
+ Slime slime = getSlime();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ new JsonFormat(false).encode(baos, slime);
+ return baos.toString("UTF-8");
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to encode metadata", e);
+ }
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java
new file mode 100644
index 00000000000..96f58bf140a
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java
@@ -0,0 +1,260 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import com.yahoo.config.provision.ProvisionInfo;
+import com.yahoo.config.provision.Version;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.path.Path;
+import com.yahoo.io.IOUtils;
+import com.yahoo.io.reader.NamedReader;
+import com.yahoo.text.XML;
+import com.yahoo.vespa.config.ConfigDefinitionKey;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.*;
+import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Represents an application package, that is, used as input when creating a VespaModel and as
+ * a general reference to all contents in an application.
+ *
+ * The class hides detail as to whether the source is local files or ZooKeeper
+ * data in config server.
+ *
+ * Anyone wanting to access application data should use this interface.
+ *
+ * @author vegardh
+ */
+public interface ApplicationPackage {
+
+ // Caution!! If you add something here it must probably also be added to ZooKeeperClient.feedZKAppPkg
+
+ String HOSTS = "hosts.xml";
+ String SERVICES = "services.xml";
+
+ Path SEARCH_DEFINITIONS_DIR = Path.fromString("searchdefinitions");
+ String COMPONENT_DIR = "components";
+ String TEMPLATES_DIR = "templates";
+ String FILES_DIR = "files";
+ String SEARCHCHAINS_DIR = "search/chains";
+ String DOCPROCCHAINS_DIR = "docproc/chains";
+ String PROCESSORCHAINS_DIR = "processor/chains";
+ String ROUTINGTABLES_DIR = "routing/tables";
+
+ // NOTE: this directory is created in serverdb during deploy, and should not exist in the original user application
+ /** Do not use */
+ String CONFIG_DEFINITIONS_DIR = "configdefinitions";
+
+ Path QUERY_PROFILES_DIR= Path.fromString("search/query-profiles");
+ Path QUERY_PROFILE_TYPES_DIR= Path.fromString("search/query-profiles/types");
+ Path PAGE_TEMPLATES_DIR= Path.fromString("page-templates");
+ Path RULES_DIR = Path.fromString("rules");
+
+ Path DEPLOYMENT_FILE = Path.fromString("deployment.xml");
+ Path VALIDATION_OVERRIDES = Path.fromString("validation-overrides.xml");
+
+ String SD_NAME_SUFFIX = ".sd";
+ String RANKEXPRESSION_NAME_SUFFIX = ".expression";
+ String RULES_NAME_SUFFIX = ".sr";
+ String EXT_DIR = "ext";
+
+ String PERMANENT_SERVICES = "permanent-services.xml";
+
+ /**
+ * The name of the application package
+ *
+ * @return the name of the application (i.e the directory where the application package was deployed from)
+ */
+ String getApplicationName();
+
+ /**
+ * Contents of services.xml. Caller must close reader after use.
+ * @return a Reader, or null if no services.xml/vespa-services.xml present
+ */
+ Reader getServices();
+
+ /**
+ * Contents of hosts.xml. Caller must close reader after use.
+ * @return a Reader, or null if no hosts.xml/vespa-hosts.xml present
+ */
+ Reader getHosts();
+
+ /**
+ * Returns the include dirs given by the user in the services.xml file.
+ */
+ default List<String> getUserIncludeDirs() {
+ throw new UnsupportedOperationException(
+ "This application package does not have special handling for user include dirs.");
+ }
+
+ default void validateIncludeDir(String dirName) {
+ throw new UnsupportedOperationException("" +
+ "This application package does not support validation of include dirs.");
+ }
+
+ /**
+ * Readers for all the search definition files for this.
+ * @return a list of readers for search definitions
+ */
+ Collection<NamedReader> searchDefinitionContents();
+
+ /**
+ * Subclass hook.
+ * Returns a mapping from def key to a file name that can be used for lookup.
+ * @return An mapping of all config definition combos available in this package.
+ */
+ Map<ConfigDefinitionKey, UnparsedConfigDefinition> getAllExistingConfigDefs();
+
+ /**
+ * Returns the files in a directory as readers. The readers <b>must</b>
+ * be closed by the caller.
+ *
+ *
+ * @param pathFromRoot the relative path string from the root of the application package
+ * @param suffix the suffix of files to return, or null to return all
+ * @param recurse return files in all subdirectories (recursively) as well
+ * @return a list of the files at this location, or an empty list (never null)
+ * if the directory does not exist or is empty. The list gets owned by the caller
+ * and can be modified freely.
+ */
+ List<NamedReader> getFiles(Path pathFromRoot, String suffix, boolean recurse);
+
+ /** Same as getFiles(pathFromRoot,suffix,false) */
+ default List<NamedReader> getFiles(Path pathFromRoot, String suffix) {
+ return getFiles(pathFromRoot,suffix,false);
+ }
+
+ /** Returns the major version this application is valid for, or empty if it is valid for all versions */
+ default Optional<Integer> getMajorVersion() {
+ Element servicesElement = XML.getDocument(getServices()).getDocumentElement();
+ if (servicesElement == null) return Optional.empty();
+ String majorVersionString = servicesElement.getAttribute("major-version");
+ if (majorVersionString == null || majorVersionString.isEmpty())
+ return Optional.empty();
+ try {
+ return Optional.of(Integer.parseInt(majorVersionString));
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("major-version must be an integer number, not '" + majorVersionString + "'");
+ }
+ }
+
+ /**
+ * Gets a file from the root of the application package
+ *
+ *
+ * @param relativePath The relative path of the file within this application package.
+ * @return reader for file
+ * @throws IllegalArgumentException if the given path does not exist
+ */
+ ApplicationFile getFile(Path relativePath);
+
+ /** Does {@link #getFiles} on the query profile directory and gets all xml files */
+ default List<NamedReader> getQueryProfileFiles() { return getFiles(QUERY_PROFILES_DIR,".xml"); }
+
+ /** Does {@link #getFiles} on the query profile directory and gets all xml files */
+ default List<NamedReader> getQueryProfileTypeFiles() { return getFiles(QUERY_PROFILE_TYPES_DIR,".xml"); }
+
+ /** Does {@link #getFiles} on the page template directory and gets all xml files */
+ default List<NamedReader> getPageTemplateFiles() { return getFiles(PAGE_TEMPLATES_DIR,".xml"); }
+
+ //For generating error messages
+ String getHostSource();
+ String getServicesSource();
+
+ Optional<Reader> getDeployment();
+ Optional<Reader> getValidationOverrides();
+
+ List<ComponentInfo> getComponentsInfo(Version vespaVersion);
+
+ /**
+ * Reads a ranking expression from file to a string and returns it.
+ *
+ * @param name the name of the file to return, relative to the search definition directory in the application package
+ * @return the content of a ranking expression file
+ * @throws IllegalArgumentException if the file was not found or could not be read
+ */
+ Reader getRankingExpression(String name);
+
+ /**
+ * Returns the name-payload pairs of any sd files under path/searchdefinitions/ in the given jar bundle
+ * @param bundle The jar file, which will be closed afterwards by this method.
+ * @param path For example 'complex/'
+ * @return map of the SD payloads
+ * @throws IOException if it is reading sd files fails
+ */
+ static Map<String, String> getBundleSdFiles(String path, JarFile bundle) throws IOException {
+ Map<String,String> ret = new LinkedHashMap<>();
+ for (Enumeration<JarEntry> e = bundle.entries(); e.hasMoreElements();) {
+ JarEntry je=e.nextElement();
+ if (je.getName().startsWith(path+SEARCH_DEFINITIONS_DIR+"/") && je.getName().endsWith(SD_NAME_SUFFIX)) {
+ String contents = IOUtils.readAll(new InputStreamReader(bundle.getInputStream(je)));
+ ret.put(getFileName(je), contents);
+ }
+ }
+ bundle.close();
+ return ret;
+ }
+
+ /**
+ * The name of an SD in a JarEntry
+ */
+ static String getFileName(JarEntry je) {
+ String name = je.getName();
+ name = name.replaceAll(".*/", "");
+ return name;
+ }
+
+ /**
+ * Gets the ApplicationMetaData instance for this application package.
+ * @return an ApplicationMetaData instance
+ */
+ default ApplicationMetaData getMetaData() { return null; }
+
+ default File getFileReference(Path pathRelativeToAppDir) {
+ throw new UnsupportedOperationException("This application package cannot return file references");
+ }
+
+ default void validateXML(DeployLogger logger) throws IOException {
+ throw new UnsupportedOperationException("This application package cannot validate XML");
+ }
+
+ default void validateXML(DeployLogger logger, Optional<Version> vespaVersion) throws IOException {
+ throw new UnsupportedOperationException("This application package cannot validate XML");
+ }
+
+ default void writeMetaData() throws IOException {
+ throw new UnsupportedOperationException("This application package cannot write its metadata");
+ }
+
+ default Map<Version, ProvisionInfo> getProvisionInfoMap() {
+ return Collections.emptyMap();
+ }
+
+ default Map<Version, FileRegistry> getFileRegistryMap() {
+ return Collections.emptyMap();
+ }
+
+ Collection<NamedReader> getSearchDefinitions();
+
+ /**
+ * Preprocess an application for a given zone and return a new application package pointing to the preprocessed
+ * application package. This is the entry point for the multi environment application package support. This method
+ * will not mutate the existing application package.
+ *
+ * @param zone A valid {@link Zone} instance, used to decide which parts of services to keep and remove
+ * @param ruleConfigDeriver ignored
+ * @param logger A {@link DeployLogger} to add output that will be returned to the user
+ *
+ * @return A new application package instance pointing to a new location
+ */
+ default ApplicationPackage preprocess(Zone zone, RuleConfigDeriver ruleConfigDeriver, DeployLogger logger) throws IOException, TransformerException, ParserConfigurationException, SAXException {
+ throw new UnsupportedOperationException("This application package does not support preprocessing");
+ }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ComponentInfo.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ComponentInfo.java
new file mode 100644
index 00000000000..42732ddfc47
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ComponentInfo.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+
+/**
+ * Describes a component residing in the components directory.
+ * <p>TODO: add support for component versions.</p>
+ * @author tonytv
+ */
+public class ComponentInfo {
+ final String pathRelativeToAppDir;
+
+ public ComponentInfo(String pathRelativeToAppDir) {
+ this.pathRelativeToAppDir = pathRelativeToAppDir;
+ }
+
+ //get path relative to app dir
+ public String getPathRelativeToAppDir() {
+ return pathRelativeToAppDir;
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeployLogger.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeployLogger.java
new file mode 100644
index 00000000000..3ba95fb6b2a
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeployLogger.java
@@ -0,0 +1,16 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import java.util.logging.Level;
+
+/**
+ * Used during application deployment to persist and propagate messages to end user
+ *
+ * @author lulf
+ * @since 5.1
+ */
+public interface DeployLogger {
+
+ void log(Level level, String message);
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
new file mode 100644
index 00000000000..e758e332901
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java
@@ -0,0 +1,182 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.text.XML;
+import org.w3c.dom.Element;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Specifies the environments and regions to which an application should be deployed.
+ * This may be used both for inspection as part of an application model and to answer
+ * queries about deployment from the command line. A main method is included for the latter usage.
+ *
+ * @author bratseth
+ */
+public class DeploymentSpec {
+
+ private final Optional<String> globalServiceId;
+ private final List<DeclaredZone> zones;
+
+ public DeploymentSpec(List<DeclaredZone> zones, Optional<String> globalServiceId) {
+ this.zones = Collections.unmodifiableList(new ArrayList<>(zones));
+ this.globalServiceId = globalServiceId;
+ }
+
+ /** Returns the zones this declares as a read-only list. */
+ public List<DeclaredZone> zones() { return zones; }
+
+ /** Returns whether this deployment spec specifies the given zone, either implicitly or explicitly */
+ public boolean includes(Environment environment, Optional<RegionName> region) {
+ for (DeclaredZone declaredZone : zones)
+ if (declaredZone.matches(environment, region)) return true;
+ return false;
+ }
+
+ /** Returns the ID of the service to expose through global routing, if present */
+ public Optional<String> globalServiceId() {
+ return globalServiceId;
+ }
+
+ /**
+ * Creates a deployment spec from XML.
+ *
+ * @throws IllegalArgumentException if the XML is invalid
+ */
+ public static DeploymentSpec fromXml(Reader reader) {
+ List<DeclaredZone> zones = new ArrayList<>();
+ Element root = XML.getDocument(reader).getDocumentElement();
+ Optional<String> globalServiceId = Optional.empty();
+ for (Element environmentTag : XML.getChildren(root)) {
+ Environment environment = Environment.from(environmentTag.getTagName());
+ List<Element> regionTags = XML.getChildren(environmentTag, "region");
+ if (regionTags.isEmpty()) {
+ zones.add(new DeclaredZone(environment, Optional.empty(), false));
+ }
+ else {
+ for (Element regionTag : regionTags) {
+ RegionName region = RegionName.from(XML.getValue(regionTag).trim());
+ boolean active = environment == Environment.prod && readActive(regionTag);
+ zones.add(new DeclaredZone(environment, Optional.of(region), active));
+ }
+ }
+
+ if (Environment.prod.equals(environment)) {
+ globalServiceId = readGlobalServiceId(environmentTag);
+ } else if (readGlobalServiceId(environmentTag).isPresent()) {
+ throw new IllegalArgumentException("Attribute 'global-service-id' is only valid on 'prod' tag.");
+ }
+ }
+ return new DeploymentSpec(zones, globalServiceId);
+ }
+
+ private static Optional<String> readGlobalServiceId(Element environmentTag) {
+ String globalServiceId = environmentTag.getAttribute("global-service-id");
+ if (globalServiceId == null || globalServiceId.isEmpty()) {
+ return Optional.empty();
+ }
+ else {
+ return Optional.of(globalServiceId);
+ }
+ }
+
+ private static boolean readActive(Element regionTag) {
+ String activeValue = regionTag.getAttribute("active");
+ if ("true".equals(activeValue)) return true;
+ if ("false".equals(activeValue)) return false;
+ throw new IllegalArgumentException("Region tags must have an 'active' attribute set to 'true' or 'false' " +
+ "to control whether the region should receive production traffic");
+ }
+
+ public static String toMessageString(Throwable t) {
+ StringBuilder b = new StringBuilder();
+ String lastMessage = null;
+ String message;
+ for (; t != null; t = t.getCause()) {
+ message = t.getMessage();
+ if (message == null) continue;
+ if (message.equals(lastMessage)) continue;
+ if (b.length() > 0) {
+ b.append(": ");
+ }
+ b.append(message);
+ lastMessage = message;
+ }
+ return b.toString();
+ }
+
+ /** This may be invoked by a continuous build */
+ public static void main (String[] args) {
+ if (args.length != 2 && args.length != 3) {
+ System.err.println("Usage: DeploymentSpec [file] [environment] [region]?" +
+ "Returns 0 if the specified zone matches the deployment spec, 1 otherwise");
+ System.exit(1);
+ }
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(args[0]))) {
+ DeploymentSpec spec = DeploymentSpec.fromXml(reader);
+ Environment environment = Environment.from(args[1]);
+ Optional<RegionName> region = args.length == 3 ? Optional.of(RegionName.from(args[2])) : Optional.empty();
+ if (spec.includes(environment, region))
+ System.exit(0);
+ else
+ System.exit(1);
+ }
+ catch (Exception e) {
+ System.err.println("Exception checking deployment spec: " + toMessageString(e));
+ System.exit(1);
+ }
+ }
+
+ public static class DeclaredZone {
+
+ private final Environment environment;
+
+ private Optional<RegionName> region;
+
+ private final boolean active;
+
+ public DeclaredZone(Environment environment, Optional<RegionName> region, boolean active) {
+ this.environment = environment;
+ this.region = region;
+ this.active = active;
+ }
+
+ public Environment environment() { return environment; }
+
+ /** The region name, or empty if not declared */
+ public Optional<RegionName> region() { return region; }
+
+ /** Returns whether this zone should receive production traffic */
+ public boolean active() { return active; }
+
+ public boolean matches(Environment environment, Optional<RegionName> region) {
+ if (environment.equals(this.environment) && region.equals(this.region)) return true;
+ if ( ! region.isPresent() && prerequisite(environment)) return true;
+ return false;
+ }
+
+ /**
+ * Returns whether deployment in the given environment is a prerequisite of deployment in this environment
+ *
+ * The required progression leading to prerequisites is test, staging, prod.
+ */
+ private boolean prerequisite(Environment environment) {
+ if (this.environment == Environment.prod)
+ return environment == Environment.staging || environment == Environment.test;
+ if (this.environment == Environment.staging)
+ return environment == Environment.test;
+ return false;
+ }
+
+ }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/FileRegistry.java b/config-model-api/src/main/java/com/yahoo/config/application/api/FileRegistry.java
new file mode 100644
index 00000000000..fe4aab72cb0
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/FileRegistry.java
@@ -0,0 +1,35 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import java.util.List;
+import java.util.Set;
+
+import com.yahoo.config.FileReference;
+
+/**
+ * @author tonytv
+ */
+public interface FileRegistry {
+
+ FileReference addFile(String relativePath);
+
+ /**
+ * Returns the name of the host which is the source of the files
+ */
+ String fileSourceHost();
+
+ Set<String> allRelativePaths();
+
+ List<Entry> export();
+
+ class Entry {
+ public final String relativePath;
+ public final FileReference reference;
+
+ public Entry(String relativePath, FileReference reference) {
+ this.relativePath = relativePath;
+ this.reference = reference;
+ }
+ }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/RuleConfigDeriver.java b/config-model-api/src/main/java/com/yahoo/config/application/api/RuleConfigDeriver.java
new file mode 100644
index 00000000000..770d8c450ee
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/RuleConfigDeriver.java
@@ -0,0 +1,14 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+/**
+ * Interface to hide dependency on prelude from application package module due to semantic rules
+ * rewriting.
+ *
+ * @author lulf
+ * @since 5.22
+ */
+// TODO: This is not used any more. Do a phased removal while keeping config model compatibility
+public interface RuleConfigDeriver {
+ void derive(String ruleBaseDir, String outputDir) throws Exception;
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/UnparsedConfigDefinition.java b/config-model-api/src/main/java/com/yahoo/config/application/api/UnparsedConfigDefinition.java
new file mode 100644
index 00000000000..5954047c564
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/UnparsedConfigDefinition.java
@@ -0,0 +1,14 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.application.api;
+
+import com.yahoo.vespa.config.ConfigDefinition;
+
+/**
+ * Represents a config definition that has not been parsed.
+ * @author lulf
+ * @since 5.20
+*/
+public interface UnparsedConfigDefinition {
+ public ConfigDefinition parse();
+ public String getUnparsedContent();
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/package-info.java b/config-model-api/src/main/java/com/yahoo/config/application/api/package-info.java
new file mode 100644
index 00000000000..ed696f98d2a
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/package-info.java
@@ -0,0 +1,7 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+@PublicApi
+package com.yahoo.config.application.api;
+
+import com.yahoo.api.annotations.PublicApi;
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java
new file mode 100644
index 00000000000..30e2df9acf9
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java
@@ -0,0 +1,42 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import java.util.List;
+
+/**
+ * Contains the action to be performed on the given services to handle a config change
+ * between the current active model and the next model to prepare.
+ *
+ * @author geirst
+ * @since 5.40
+ */
+public interface ConfigChangeAction {
+
+ enum Type {
+ RESTART("restart"), REFEED("refeed");
+
+ private final String type;
+
+ Type(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return type;
+ }
+ }
+
+ /** Returns what type of action is required to handle this config change */
+ Type getType();
+
+ /** Returns a message describing the config change in detail */
+ String getMessage();
+
+ /** Returns the list of services where the action must be performed */
+ List<ServiceInfo> getServices();
+
+ /** Returns whether this change should be allowed */
+ boolean allowed();
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java
new file mode 100644
index 00000000000..7f70733fb8c
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java
@@ -0,0 +1,22 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+/**
+ * Represents an action to re-feed a document type in order to handle a config change.
+ *
+ * @author geirst
+ * @since 5.43
+ */
+public interface ConfigChangeRefeedAction extends ConfigChangeAction {
+
+ @Override
+ default Type getType() { return Type.REFEED; }
+
+ /** Returns the name identifying this kind of change, used to identify names which should be allowed */
+ // Remove this default implementation when model versions earlier than 5.125 are gone
+ default String name() { return ""; }
+
+ /** Returns the name of the document type that one must re-feed to handle this config change */
+ String getDocumentType();
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java
new file mode 100644
index 00000000000..3add3ef1519
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+/**
+ * Represents an action to restart services in order to handle a config change.
+ *
+ * @author geirst
+ * @since 5.43
+ */
+public interface ConfigChangeRestartAction extends ConfigChangeAction {
+
+ @Override
+ default Type getType() { return Type.RESTART; }
+
+ /** Restarts are handled automatically so they are allowed */
+ @Override
+ default boolean allowed() { return true; }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java
new file mode 100644
index 00000000000..69dc3f08d64
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java
@@ -0,0 +1,23 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.codegen.InnerCNode;
+import com.yahoo.vespa.config.ConfigDefinitionKey;
+import com.yahoo.vespa.config.buildergen.ConfigDefinition;
+
+import java.util.Map;
+
+/**
+ * Represents a repository of config definitions.
+ *
+ * @author lulf
+ * @since 5.10
+ */
+public interface ConfigDefinitionRepo {
+
+ /**
+ * Retrieve a map with all configdefinitions in this repo.
+ */
+ Map<ConfigDefinitionKey, ConfigDefinition> getConfigDefinitions();
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java
new file mode 100644
index 00000000000..ca2064ed363
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java
@@ -0,0 +1,13 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.vespa.config.ConfigDefinition;
+import com.yahoo.vespa.config.ConfigDefinitionKey;
+
+/**
+ * @author lulf
+ * @since 5.1
+ */
+public interface ConfigDefinitionStore {
+ ConfigDefinition getConfigDefinition(ConfigDefinitionKey defKey);
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java
new file mode 100644
index 00000000000..3cebcb6e71b
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java
@@ -0,0 +1,10 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+/**
+ * Interface of config model plugins.
+ *
+ * @author lulf
+ */
+public interface ConfigModelPlugin {
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java
new file mode 100644
index 00000000000..0a43f190675
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java
@@ -0,0 +1,14 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+/**
+ * Provides information about a configserver instance.
+ *
+ * @author tonytv
+ */
+public interface ConfigServerSpec {
+ public String getHostName();
+ public int getConfigServerPort();
+ public int getHttpPort();
+ public int getZooKeeperPort();
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java b/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java
new file mode 100644
index 00000000000..604a9edf003
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java
@@ -0,0 +1,28 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.vespa.defaults.Defaults;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Interface for models towards filedistribution.
+ *
+ * @author lulf
+ * @since 5.1
+ */
+public interface FileDistribution {
+
+ void sendDeployedFiles(String hostName, Set<FileReference> fileReferences);
+ void reloadDeployFileDistributor();
+ void limitSendingOfDeployedFilesTo(Collection<String> hostNames);
+ void removeDeploymentsThatHaveDifferentApplicationId(Collection<String> targetHostnames);
+
+ static File getDefaultFileDBPath() {
+ return new File(Defaults.getDefaults().vespaHome() + "var/db/vespa/filedistribution");
+ }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java
new file mode 100644
index 00000000000..dbb2a1a07a9
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java
@@ -0,0 +1,48 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import java.util.Collection;
+
+/*
+ * Contains information about a host and what services are running on it.
+ *
+ * @author lulf
+ * @since 5.37
+ */
+public class HostInfo {
+ private final String hostname;
+ private final Collection<ServiceInfo> services;
+
+ public HostInfo(String hostName, Collection<ServiceInfo> services) {
+ this.hostname = hostName;
+ this.services = services;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public Collection<ServiceInfo> getServices() {
+ return services;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ HostInfo hostInfo = (HostInfo) o;
+
+ if (!hostname.equals(hostInfo.hostname)) return false;
+ if (services != null ? !services.equals(hostInfo.services) : hostInfo.services != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = hostname.hashCode();
+ result = 31 * result + (services != null ? services.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java
new file mode 100644
index 00000000000..3e14485dd5a
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java
@@ -0,0 +1,33 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.provision.*;
+
+import java.util.List;
+import java.util.logging.Level;
+
+/**
+ * Interface towards the host provisioner used to build a {@link Model}. The difference between this provisioner
+ * and {@link com.yahoo.config.provision.Provisioner}, is that this interface only exposes methods needed
+ * to build the model.
+ *
+ * @author lulf
+ */
+public interface HostProvisioner {
+
+ /** Allocates a single host for a service */
+ // TODO: Remove
+ HostSpec allocateHost(String alias);
+
+ /**
+ * Prepares allocation of a set of hosts with a given type, common id and the amount.
+ *
+ * @param cluster the cluster to allocate nodes to
+ * @param capacity the capacity describing the capacity requested
+ * @param groups the number of groups to divide the nodes into
+ * @param logger a logger to which messages to the deployer may be written
+ * @return the specification of the allocated hosts
+ */
+ List<HostSpec> prepare(ClusterSpec cluster, Capacity capacity, int groups, ProvisionLogger logger);
+
+} \ No newline at end of file
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java
new file mode 100644
index 00000000000..998ca6cb53c
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java
@@ -0,0 +1,99 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.codegen.InnerCNode;
+import com.yahoo.config.provision.ProvisionInfo;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.config.ConfigPayload;
+import com.yahoo.vespa.config.buildergen.ConfigDefinition;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Collection;
+
+/**
+ * A {@link Model} represents the interface towards the model of an entire tenant, and defines methods
+ * for querying this model.
+ *
+ * @author lulf
+ * @since 5.1
+ */
+public interface Model {
+
+ /**
+ * Resolves a config using a given def file, apply overrides and returns it.
+ *
+ * @param configKey The key of the config to retrieve.
+ * @param targetDef The config definition to use for applying defaults.
+ * @return override The global override to apply to the generated config.
+ */
+ ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef, ConfigPayload override) throws IOException;
+
+ /**
+ * TODO: Remove this method once no fat bundles implementing it anymore.
+ * Use {@link Model#getConfig(ConfigKey, ConfigDefinition, ConfigPayload)} instead.
+ *
+ * Resolves a config using a given def file, apply overrides and returns it.
+ *
+ * @param configKey The key of the config to retrieve.
+ * @param targetDef The config definition to use for applying defaults.
+ * @return override The global override to apply to the generated config.
+ */
+ ConfigPayload getConfig(ConfigKey<?> configKey, InnerCNode targetDef, ConfigPayload override) throws IOException;
+
+ /**
+ * Produces a set of the valid config keys for this model.
+ */
+ Set<ConfigKey<?>> allConfigsProduced();
+
+ /**
+ * Returns information about all hosts used in this model.
+ */
+ Collection<HostInfo> getHosts();
+
+ /**
+ * Returns all the config ids available for this model.
+ */
+ Set<String> allConfigIds();
+
+ /**
+ * Asks the {@link Model} instance to distribute files using provided filedistribution instance.
+ * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance that can be called to distribute files.
+ */
+ void distributeFiles(FileDistribution fileDistribution);
+
+
+ /**
+ * Tells file distributor to rescan all files. At the moment this is a very expensive operation, so should only be done
+ * once per deployment.
+ * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance.
+ */
+ default void reloadDeployFileDistributor(FileDistribution fileDistribution) { }
+
+ /**
+ * Get the provisioning info for this model.
+ * @return {@link ProvisionInfo} instance, if available.
+ */
+ Optional<ProvisionInfo> getProvisionInfo();
+
+ /**
+ * Returns whether this application allows serving config request for a different version.
+ * This is a validation override which is useful when we skip loading old config models
+ * due to some problem, or when we need to try a newer version of the platform on some node.
+ */
+ default boolean allowModelVersionMismatch() { return false; }
+
+ /**
+ * Returns whether old config models should be loaded (default) or not.
+ * Skipping old config models is a validation override which is useful when the old model
+ * version is known to contain some incompatibility with the application package
+ * and it is believed that the latest model version will deliver usable config for old versions
+ * requesting config.
+ * <p>
+ * If a model returns true to this it should also return true to {@link #allowModelVersionMismatch}
+ * or clients requesting config for those old models will not get config at all.
+ */
+ default boolean skipOldConfigModels() { return false; }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
new file mode 100644
index 00000000000..9226e3bbe11
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -0,0 +1,43 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.application.api.ApplicationPackage;
+import com.yahoo.config.application.api.DeployLogger;
+import com.yahoo.config.application.api.FileRegistry;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Rotation;
+import com.yahoo.config.provision.Version;
+import com.yahoo.config.provision.Zone;
+
+import java.io.File;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Model context containing state provided to model factories.
+ *
+ * @author lulf
+ */
+public interface ModelContext {
+
+ ApplicationPackage applicationPackage();
+ Optional<Model> previousModel();
+ Optional<ApplicationPackage> permanentApplicationPackage();
+ Optional<HostProvisioner> hostProvisioner();
+ DeployLogger deployLogger();
+ ConfigDefinitionRepo configDefinitionRepo();
+ FileRegistry getFileRegistry();
+ Properties properties();
+ default Optional<File> appDir() { return Optional.empty();}
+ default Optional<Version> vespaVersion() { return Optional.empty(); }
+
+ interface Properties {
+ boolean multitenant();
+ ApplicationId applicationId();
+ List<ConfigServerSpec> configServerSpecs();
+ boolean hostedVespa();
+ Zone zone();
+ Set<Rotation> rotations();
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java
new file mode 100644
index 00000000000..10738653129
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java
@@ -0,0 +1,28 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import java.util.List;
+
+/**
+ * The result after creating and validating a Model.
+ *
+ * @author geirst
+ * @since 5.39
+ */
+public class ModelCreateResult {
+
+ private final Model model;
+ private final List<ConfigChangeAction> configChangeActions;
+
+ public ModelCreateResult(Model model, List<ConfigChangeAction> configChangeActions) {
+ this.model = model;
+ this.configChangeActions = configChangeActions;
+ }
+
+ /** The model these changes apply to */
+ public Model getModel() { return model; }
+
+ /** Returns the actions that needs to be done to successfully start using the new model */
+ public List<ConfigChangeAction> getConfigChangeActions() { return configChangeActions; }
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java
new file mode 100644
index 00000000000..a6f7b8096ea
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java
@@ -0,0 +1,39 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import com.yahoo.config.provision.Version;
+
+/**
+ * Factory for config models.
+ */
+public interface ModelFactory {
+
+ /**
+ * Gets version of this {@link ModelFactory}. The version will be used to dispatch deployments to the correct
+ * {@link ModelFactory}.
+ *
+ * @return The version of a {@link Model} instance that this factory can create.
+ */
+ Version getVersion();
+
+ /**
+ * Creates an instance of a {@link Model}. The resulting instance will be used to serve config. No model
+ * validation will be done, calling this method presupposes that {@link #createAndValidateModel} has already
+ * been called.
+ *
+ * @param modelContext An instance of {@link ModelContext}, containing dependencies for creating a {@link Model}.
+ * @return a {@link Model} instance.
+ */
+ Model createModel(ModelContext modelContext);
+
+ /**
+ * Creates an instance of a {@link Model}. The resulting instance will be used to serve config. Any validation
+ * of a {@link Model} and the {@link ModelContext} can be done in this method.
+ *
+ * @param modelContext An instance of {@link ModelContext}, containing dependencies for creating a {@link Model}.
+ * @param ignoreValidationErrors true if validation errors should not trigger exceptions.
+ * @return a {@link ModelCreateResult} instance.
+ */
+ ModelCreateResult createAndValidateModel(ModelContext modelContext, boolean ignoreValidationErrors);
+
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java
new file mode 100644
index 00000000000..236f951e4d3
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java
@@ -0,0 +1,9 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+/**
+ * @author lulf
+ */
+public interface ModelState {
+ Model getModel();
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java
new file mode 100644
index 00000000000..99f6ae469f3
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java
@@ -0,0 +1,46 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import java.util.Collection;
+
+/**
+ * Contains information about a port (port number and a collection of tags).
+ *
+ */
+public class PortInfo {
+ private final int port;
+ private final Collection<String> tags;
+
+ public PortInfo(int port, Collection<String> tags) {
+ this.port = port;
+ this.tags = tags;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public Collection<String> getTags() {
+ return tags;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PortInfo portInfo = (PortInfo) o;
+
+ if (port != portInfo.port) return false;
+ if (tags != null ? !tags.equals(portInfo.tags) : portInfo.tags != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = port;
+ result = 31 * result + (tags != null ? tags.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java
new file mode 100644
index 00000000000..6d72da7df6f
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java
@@ -0,0 +1,87 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.api;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Collection;
+
+/**
+ * Contains information about a service.
+ *
+ * @author lulf
+ * @since 5.37
+ */
+public class ServiceInfo {
+ private final String serviceName;
+ private final String serviceType;
+ private final Collection<PortInfo> ports;
+ private final Map<String, String> properties;
+ private final String configId;
+ private final String hostName;
+
+ public ServiceInfo(String serviceName, String serviceType, Collection<PortInfo> ports, Map<String, String> properties,
+ String configId, String hostName) {
+
+ Objects.requireNonNull(configId);
+
+ this.serviceName = serviceName;
+ this.serviceType = serviceType;
+ this.ports = ports;
+ this.properties = properties;
+ this.configId = configId;
+ this.hostName = hostName;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getConfigId() {
+ return configId;
+ }
+
+ public String getServiceType() {
+ return serviceType;
+ }
+
+ public Optional<String> getProperty(String propertyName) {
+ return Optional.ofNullable(properties.get(propertyName));
+ }
+
+ public Collection<PortInfo> getPorts() {
+ return ports;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ServiceInfo that = (ServiceInfo) o;
+
+ if (ports != null ? !ports.equals(that.ports) : that.ports != null) return false;
+ if (properties != null ? !properties.equals(that.properties) : that.properties != null) return false;
+ if (!serviceName.equals(that.serviceName)) return false;
+ if (!serviceType.equals(that.serviceType)) return false;
+ if (!configId.equals(that.configId)) return false;
+ if (!hostName.equals(that.hostName)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = serviceName.hashCode();
+ result = 31 * result + serviceType.hashCode();
+ result = 31 * result + (ports != null ? ports.hashCode() : 0);
+ result = 31 * result + (properties != null ? properties.hashCode() : 0);
+ result = 31 * result + configId.hashCode();
+ result = 31 * result + hostName.hashCode();
+ return result;
+ }
+}
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java b/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java
new file mode 100644
index 00000000000..730d23f5086
--- /dev/null
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java
@@ -0,0 +1,5 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+package com.yahoo.config.model.api;
+
+import com.yahoo.osgi.annotation.ExportPackage;