This repository has been archived by the owner on Jan 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 558
initial outline of the acs template generator #3
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
759e6e9
initial outline of the acs template generator
anhowe 8404b84
added master template generation for dcos 1.8.4, 1.7.3, and swarm
anhowe 951e899
added dcos 1.8.4 agents
anhowe 2dfdfc2
add swarm agents, pretty print the template output
anhowe 2c13040
add custom VNET
anhowe 15ea4a5
add stateful pool support to dcos
anhowe f83eeec
made fixes based on CR feedback
anhowe 1ccb408
fixed bug in swarm generation
anhowe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# ACSTGEN - Template generator | ||
|
||
Template generator builds a custom template based on user requirements. Examples exist under clusterdefinitions folder. | ||
|
||
To build type ```go build```, and running at commandline provides the usage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"strings" | ||
|
||
"./api/vlabs" | ||
"./clustertemplate" | ||
) | ||
|
||
// loadAcsCluster loads an ACS Cluster API Model from a JSON file | ||
func loadAcsCluster(jsonFile string) (*vlabs.AcsCluster, error) { | ||
contents, e := ioutil.ReadFile(jsonFile) | ||
if e != nil { | ||
return nil, fmt.Errorf("error reading file %s: %s", jsonFile, e.Error()) | ||
} | ||
|
||
acsCluster := &vlabs.AcsCluster{} | ||
if e := json.Unmarshal(contents, &acsCluster); e != nil { | ||
return nil, fmt.Errorf("error unmarshalling file %s: %s", jsonFile, e.Error()) | ||
} | ||
acsCluster.SetDefaults() | ||
if e := acsCluster.Validate(); e != nil { | ||
return nil, fmt.Errorf("error validating acs cluster from file %s: %s", jsonFile, e.Error()) | ||
} | ||
|
||
return acsCluster, nil | ||
} | ||
|
||
func translateJSON(content string, translateParams [][]string, reverseTranslate bool) string { | ||
for _, tuple := range translateParams { | ||
if len(tuple) != 2 { | ||
panic("string tuples must be of size 2") | ||
} | ||
a := tuple[0] | ||
b := tuple[1] | ||
if reverseTranslate { | ||
content = strings.Replace(content, b, a, -1) | ||
} else { | ||
content = strings.Replace(content, a, b, -1) | ||
} | ||
} | ||
return content | ||
} | ||
|
||
func prettyPrintJSON(content string) (string, error) { | ||
var data map[string]interface{} | ||
if err := json.Unmarshal([]byte(content), &data); err != nil { | ||
return "", err | ||
} | ||
prettyprint, err := json.MarshalIndent(data, "", " ") | ||
if err != nil { | ||
return "", err | ||
} | ||
return string(prettyprint), nil | ||
} | ||
|
||
func prettyPrintArmTemplate(template string) (string, error) { | ||
translateParams := [][]string{ | ||
{"parameters", "dparameters"}, | ||
{"variables", "evariables"}, | ||
{"resources", "fresources"}, | ||
{"outputs", "zoutputs"}, | ||
} | ||
|
||
template = translateJSON(template, translateParams, false) | ||
var err error | ||
if template, err = prettyPrintJSON(template); err != nil { | ||
return "", err | ||
} | ||
template = translateJSON(template, translateParams, true) | ||
|
||
return template, nil | ||
} | ||
|
||
func usage(errs ...error) { | ||
for _, err := range errs { | ||
fmt.Fprintf(os.Stderr, "error: %s\n\n", err.Error()) | ||
} | ||
fmt.Fprintf(os.Stderr, "usage: %s ClusterDefinitionFile\n", os.Args[0]) | ||
fmt.Fprintf(os.Stderr, " read the ClusterDefinitionFile and output an arm template") | ||
fmt.Fprintf(os.Stderr, "\n") | ||
fmt.Fprintf(os.Stderr, "options:\n") | ||
flag.PrintDefaults() | ||
} | ||
|
||
var templateDirectory = flag.String("templateDirectory", "./parts", "directory containing base template files") | ||
var noPrettyPrint = flag.Bool("noPrettyPrint", false, "do not pretty print output") | ||
|
||
func main() { | ||
var acsCluster *vlabs.AcsCluster | ||
var template string | ||
var err error | ||
|
||
flag.Parse() | ||
|
||
if argCount := len(flag.Args()); argCount == 0 { | ||
usage() | ||
os.Exit(1) | ||
} | ||
|
||
jsonFile := flag.Arg(0) | ||
if _, err = os.Stat(jsonFile); os.IsNotExist(err) { | ||
usage(fmt.Errorf("file %s does not exist", jsonFile)) | ||
os.Exit(1) | ||
} | ||
|
||
if _, err = os.Stat(*templateDirectory); os.IsNotExist(err) { | ||
usage(fmt.Errorf("base templates directory %s does not exist", jsonFile)) | ||
os.Exit(1) | ||
} | ||
|
||
if err = clustertemplate.VerifyFiles(*templateDirectory); err != nil { | ||
fmt.Fprintf(os.Stderr, "verification failed: %s\n", err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
if acsCluster, err = loadAcsCluster(jsonFile); err != nil { | ||
fmt.Fprintf(os.Stderr, "error while loading %s: %s", jsonFile, err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
if template, err = clustertemplate.GenerateTemplate(acsCluster, *templateDirectory); err != nil { | ||
fmt.Fprintf(os.Stderr, "error generating template %s: %s", jsonFile, err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
if !*noPrettyPrint { | ||
if template, err = prettyPrintArmTemplate(template); err != nil { | ||
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
fmt.Print(template) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package vlabs | ||
|
||
const ( | ||
// DCOS is the string constant for DCOS orchestrator type and defaults to DCOS184 | ||
DCOS = "DCOS" | ||
// DCOS184 is the string constant for DCOS 1.8.4 orchestrator type | ||
DCOS184 = "DCOS184" | ||
// DCOS173 is the string constant for DCOS 1.7.3 orchestrator type | ||
DCOS173 = "DCOS173" | ||
// Swarm is the string constant for the Swarm orchestrator type | ||
Swarm = "Swarm" | ||
// MinAgentCount are the minimum number of agents | ||
MinAgentCount = 1 | ||
// MaxAgentCount are the maximum number of agents | ||
MaxAgentCount = 100 | ||
// MinPort specifies the minimum tcp port to open | ||
MinPort = 1 | ||
// MaxPort specifies the maximum tcp port to open | ||
MaxPort = 65535 | ||
// BaseLBPriority specifies the base lb priority. | ||
BaseLBPriority = 200 | ||
// DefaultMasterSubnet specifies the default master subnet | ||
DefaultMasterSubnet = "172.16.0.0/24" | ||
// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0 | ||
DefaultFirstConsecutiveStaticIP = "172.16.0.5" | ||
// DefaultAgentSubnetTemplate specifies a default agent subnet | ||
DefaultAgentSubnetTemplate = "10.%d.0.0/24" | ||
// MaxDisks specifies the maximum attached disks to add to the cluster | ||
MaxDisks = 4 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package vlabs | ||
|
||
import "fmt" | ||
|
||
// SetDefaults implements APIObject | ||
func (o *OrchestratorProfile) SetDefaults() { | ||
} | ||
|
||
// SetDefaults implements APIObject | ||
func (m *MasterProfile) SetDefaults() { | ||
if !m.IsCustomVNET() { | ||
m.subnet = DefaultMasterSubnet | ||
m.FirstConsecutiveStaticIP = DefaultFirstConsecutiveStaticIP | ||
} | ||
} | ||
|
||
// SetDefaults implements APIObject | ||
func (a *AgentPoolProfile) SetDefaults() { | ||
} | ||
|
||
// SetDefaults implements APIObject | ||
func (l *LinuxProfile) SetDefaults() { | ||
} | ||
|
||
// SetDefaults implements APIObject | ||
func (a *AcsCluster) SetDefaults() { | ||
a.OrchestratorProfile.SetDefaults() | ||
a.MasterProfile.SetDefaults() | ||
|
||
// assign subnets if VNET not specified | ||
subnetCounter := 0 | ||
for i := range a.AgentPoolProfiles { | ||
profile := &a.AgentPoolProfiles[i] | ||
profile.SetDefaults() | ||
if !profile.IsCustomVNET() { | ||
profile.subnet = fmt.Sprintf(DefaultAgentSubnetTemplate, subnetCounter) | ||
subnetCounter++ | ||
} | ||
} | ||
a.LinuxProfile.SetDefaults() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package vlabs stores an experimental api model for acs | ||
package vlabs // import "./api/vlabs" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package vlabs | ||
|
||
// AcsCluster represents the ACS cluster definition | ||
type AcsCluster struct { | ||
OrchestratorProfile OrchestratorProfile `json:"orchestratorProfile"` | ||
MasterProfile MasterProfile `json:"masterProfile"` | ||
AgentPoolProfiles []AgentPoolProfile `json:"agentPoolProfiles"` | ||
LinuxProfile LinuxProfile `json:"linuxProfile"` | ||
} | ||
|
||
// OrchestratorProfile represents the type of orchestrator | ||
type OrchestratorProfile struct { | ||
OrchestratorType string `json:"orchestratorType"` | ||
} | ||
|
||
// MasterProfile represents the definition of the master cluster | ||
type MasterProfile struct { | ||
Count int `json:"count"` | ||
DNSPrefix string `json:"dnsPrefix"` | ||
VMSize string `json:"vmSize"` | ||
VnetSubnetID string `json:"vnetSubnetID,omitempty"` | ||
FirstConsecutiveStaticIP string `json:"firstConsecutiveStaticIP,omitempty"` | ||
// subnet is internal | ||
subnet string | ||
} | ||
|
||
// AgentPoolProfile represents an agent pool definition | ||
type AgentPoolProfile struct { | ||
Name string `json:"name"` | ||
Count int `json:"count"` | ||
VMSize string `json:"vmSize"` | ||
DNSPrefix string `json:"dnsPrefix,omitempty"` | ||
Ports []int `json:"ports,omitempty"` | ||
IsStateful bool `json:"isStateful,omitempty"` | ||
DiskSizesGB []int `json:"diskSizesGB,omitempty"` | ||
VnetSubnetID string `json:"vnetSubnetID,omitempty"` | ||
// subnet is internal | ||
subnet string | ||
} | ||
|
||
// LinuxProfile represents the linux parameters passed to the cluster | ||
type LinuxProfile struct { | ||
AdminUsername string `json:"adminUsername"` | ||
SSH struct { | ||
PublicKeys []struct { | ||
KeyData string `json:"keyData"` | ||
} `json:"publicKeys"` | ||
} `json:"ssh"` | ||
} | ||
|
||
// APIObject defines the required functionality of an api object | ||
type APIObject interface { | ||
SetDefaults() | ||
Validate() error | ||
} | ||
|
||
// IsCustomVNET returns true if the customer brought their own VNET | ||
func (m *MasterProfile) IsCustomVNET() bool { | ||
return len(m.VnetSubnetID) > 0 | ||
} | ||
|
||
// GetSubnet returns the read-only subnet for the master | ||
func (m *MasterProfile) GetSubnet() string { | ||
return m.subnet | ||
} | ||
|
||
// IsCustomVNET returns true if the customer brought their own VNET | ||
func (a *AgentPoolProfile) IsCustomVNET() bool { | ||
return len(a.VnetSubnetID) > 0 | ||
} | ||
|
||
// HasDisks returns true if the customer specified disks | ||
func (a *AgentPoolProfile) HasDisks() bool { | ||
return len(a.DiskSizesGB) > 0 | ||
} | ||
|
||
// GetSubnet returns the read-only subnet for the agent pool | ||
func (a *AgentPoolProfile) GetSubnet() string { | ||
return a.subnet | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like a bug waiting to happen where a client names something verbedparameterstore, or something of the sort and we rename things to verbeparameterstore. Is there a way we can introduce path to the values we are changing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I shared this offline and anhowe fixed it by adding the quotes. Still possible, but Much less likely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed