I think it'd be worth thinking about separating the Deployment (and DeploymentId) abstraction into separate abstractions for Cluster and NodeType (or role), making both of these ideas first-class citizens in the YAMS model.
Within a cluster, we sometimes want to designate different node types, installing different collections of services and apps on each type of node. But we also want to make sure we don't mix up deployments to different clusters/environments, keeping their definitions completely separate. I don't ever want one role in a cluster to affect software configuration on other clusters (accidentally or intentionally). If a second cluster has nodes with the same roles as nodes in another environment, it should be considered separate when any changes are rolled out. Running a tool to update cluster configurations should only affect components on one cluster at a time.
When fetching deployment configuration, a node would say "I belong to cluster x, and I'm node type y", and would then receive the appropriate deployment configuration object.
It's easy enough to fake this now, with the current state of YAMS, creating a single DeploymentId out of two parts like: "QAT-StorageNode", "QAT-ComputeNode", "Prod-StorageNode", "Prod-ComputeNode", etc. But it'd be nice for YAMS to recognize this reality with first-class recognition of both concepts, which are currently combined into a single "deployment" concept.
A current YAMS "deployment" would in this new model consist of all the AppPackageInstalls within a specified NodeType.
When I put my IT admin hat on, I want to see all the clusters, which node types are configured for each environment, and which packages are configured to run on each type of node.
With the right storage abstractions, that becomes much easier. A GUI tool with a TreeView could break down these three levels, let users expand a cluster environment node to see node types, expand those to see packages, drag packages into a node type for a particular cluster to add a reference to the package, etc.
I also imagine AppPackageInstalls having columns for ConfigFilesPackage, which would be just another .zip file (in our implementation) whose contents are unzipped into the app version directory with the rest of the app binaries. This would decouple file-based config (which is still very common and sometimes not within our control) from application binaries deployment, which is great because currently we'd need to publish a different "version" of the app package for it to be recognized with its updated config file. This is a waste of app packages (and deployment storage / disk space), which otherwise could have their versioned packages reused across several/many cluster environments, each with their own dynamic config.
Going along with ConfigFilesPackage, I want to add another property/column for CommandLineArguments (or ExecutionArguments), which would be a string of constant values and token expressions, to be replaced with values by YAMS when it executes the app/service.
Both would be optional.
@nehmebilal mentioned using some kind of extended properties dictionary or property bag to store things like ExecutionArguments, or other platform- or solution-specific parameters.
With this design, both cluster/node configurations and app/service packages could still be immutable. But in separating binaries from config, or providing an optional "config overlay of files", the packages of binaries can be reused across cluster environments, each with their own config files and/or command-line arguments.
Changes to IDeploymentRepository:
Task<ClusterConfig> FetchClusterConfig(string clusterId)
Task<NodeTypeConfig> FetchNodeTypeConfig(string clusterId, string nodeTypeId)
Task PublishClusterConfig(ClusterConfig clusterConfig)
Task PublishNodeTypeConfig(NodeTypeConfig nodeTypeConfig)
Task<bool> HasApplicationConfigFiles(AppIdentity appIdentity)
Downloading of application config files, if any exist, can be done within the implementation of IDeploymentRepository.DownloadApplicationBinaries
, and a HasApplicationConfigFiles
function isn't needed if that data is returned from within NodeTypeConfig.
ClusterConfig would be the ID plus a collection of NodeTypeConfig objects.
I think what I'm proposing is pretty generic. If many YAMS clusters out there will have only a single node type, that's fine. It can by default have a single node type, and all config actions naturally go against that. Once a second node type has been defined/created for a cluster, commands can be more specific about which node type they're assigning app packages to.
A NodeType is simply: a collection of versioned software packages to be installed on the same machine (virtual or otherwise).
AppInstallSetForNode would be a more descriptive name than NodeType, but is otherwise completely awful.
Thoughts?