in src/ccf/caci-ccf-provider/CAciNodeProvider.cs [41:174]
public async Task<NodeEndpoint> CreateStartNode(
string nodeName,
string networkName,
List<InitialMember> initialMembers,
string? nodeLogLevel,
SecurityPolicyConfiguration policyOption,
NodeData nodeData,
List<string> san,
JsonObject? providerConfig)
{
this.ValidateCreateInput(providerConfig);
string containerGroupName = nodeName;
ContainerGroupData? cgData =
await AciUtils.TryGetContainerGroupData(containerGroupName, providerConfig!);
if (cgData != null)
{
this.logger.LogWarning($"Found existing {containerGroupName} instance." +
$" Not re-creating start node.");
return AciUtils.ToNodeEndpoint(cgData);
}
// Pack the start_config, members info and constitution files in a tar gz, base64 encode it
// and set that as an environment variable on the ACI instance. Then have a bootstrap
// script that unpacks the tar gz file and then launches the cchost instance.
string configDataDir = WorkspaceDirectories.GetConfigurationDirectory(
nodeName,
networkName,
this.InfraType);
Directory.CreateDirectory(configDataDir);
CCHostConfig cchostConfig = await CCHostConfig.InitConfig(
"templates/snp/start-config.json",
outDir: configDataDir);
// Set networking configuration.
string location = providerConfig!["location"]!.ToString();
string dnsNameLabel = this.GenerateDnsName(nodeName, networkName, providerConfig);
var fqdn = $"{dnsNameLabel}.{location}.azurecontainer.io";
string instanceId = Guid.NewGuid().ToString();
this.AddInfraProviderData(nodeData, instanceId);
cchostConfig.SetPublishedAddress(fqdn);
cchostConfig.SetNodeLogLevel(nodeLogLevel);
await cchostConfig.SetNodeData(nodeData);
var altNames = fqdn.NodeSanFormat();
altNames.AddRange(san);
cchostConfig.SetSubjectAltNames(altNames);
await cchostConfig.SetStartConfiguration(initialMembers, "constitution");
// Prepare node storage.
var nodeStorageProvider = NodeStorageProviderFactory.Create(
networkName,
providerConfig,
this.InfraType,
this.logger);
if (await nodeStorageProvider.NodeStorageDirectoryExists(nodeName))
{
// If no start node container exists but the storage folder from a previous run for
// this start node exists then delete that or else cchost startup will fail saying
// that ledger directory already exists.
this.logger.LogWarning($"Removing {nodeName} node storage folder from a previous " +
$"run before creating the start node container.");
await nodeStorageProvider.DeleteNodeStorageDirectory(nodeName);
}
await nodeStorageProvider.CreateNodeStorageDirectory(nodeName);
(var rwLedgerDir, var rwSnapshotsDir, var logsDir) =
await nodeStorageProvider.GetReadWriteLedgerSnapshotsDir(nodeName);
cchostConfig.SetLedgerSnapshotsDirectory(rwLedgerDir.MountPath, rwSnapshotsDir.MountPath);
// Write out the config file.
await cchostConfig.SaveConfig();
// Add any configuration files that the node storage provider needs during container start.
await nodeStorageProvider.AddNodeStorageProviderConfiguration(
configDataDir,
rwLedgerDir,
rwSnapshotsDir,
roLedgerDirs: null,
roSnapshotsDir: null);
// Pack the contents of the directory into base64 encoded tar gzip string which then
// gets uncompressed and expanded in the container.
string tgzConfigData = await Utils.PackDirectory(configDataDir);
var securityPolicy =
await this.GetContainerGroupSecurityPolicy(policyOption);
ContainerGroupData inputData = this.CreateContainerGroupData(
location,
networkName,
nodeName,
dnsNameLabel,
tgzConfigData,
instanceId,
securityPolicy);
await nodeStorageProvider.UpdateCreateContainerGroupParams(
rwLedgerDir,
rwSnapshotsDir,
roLedgerDirs: null,
roSnapshotsDir: null,
inputData);
if (providerConfig.StartNodeSleep())
{
inputData.Containers.Single(
c => c.Name == AciConstants.ContainerName.CcHost).EnvironmentVariables.Add(
new ContainerEnvironmentVariable("TAIL_DEV_NULL")
{
Value = "true"
});
}
if (logsDir != null)
{
inputData.Containers.Single(
c => c.Name == AciConstants.ContainerName.CcHost).EnvironmentVariables.Add(
new ContainerEnvironmentVariable("LOGS_DIR")
{
Value = logsDir.MountPath
});
}
ContainerGroupData resourceData = await this.CreateContainerGroup(
containerGroupName,
inputData,
providerConfig);
return AciUtils.ToNodeEndpoint(resourceData);
}