зеркало из https://github.com/Azure/aks-engine.git
1. fixed many CR comments
2. output to files instead of stdout 3. writing out kubeconfig files now 4. templates are now split into a parameters file and a template file
This commit is contained in:
Родитель
1a9333629f
Коммит
d7d160ab1c
|
@ -0,0 +1,5 @@
|
|||
*.anthony.json
|
||||
deployVM0.ps1
|
||||
noparams.json
|
||||
output*
|
||||
acstgen.exe
|
|
@ -10,7 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"./api/vlabs"
|
||||
tgen "./templategenerator"
|
||||
"./tgen"
|
||||
)
|
||||
|
||||
// loadAcsCluster loads an ACS Cluster API Model from a JSON file
|
||||
|
@ -62,10 +62,13 @@ func prettyPrintJSON(content string) (string, error) {
|
|||
|
||||
func prettyPrintArmTemplate(template string) (string, error) {
|
||||
translateParams := [][]string{
|
||||
{"parameters", "dparameters"},
|
||||
{"variables", "evariables"},
|
||||
{"resources", "fresources"},
|
||||
{"outputs", "zoutputs"},
|
||||
{"\"parameters\"", "\"dparameters\""},
|
||||
{"\"variables\"", "\"evariables\""},
|
||||
{"\"resources\"", "\"fresources\""},
|
||||
{"\"outputs\"", "\"zoutputs\""},
|
||||
// there is a bug in ARM where it doesn't correctly translate back '\u003e' (>)
|
||||
{">", "GREATERTHAN"},
|
||||
{"<", "LESSTHAN"},
|
||||
}
|
||||
|
||||
template = translateJSON(template, translateParams, false)
|
||||
|
@ -78,12 +81,12 @@ func prettyPrintArmTemplate(template string) (string, error) {
|
|||
return template, nil
|
||||
}
|
||||
|
||||
func writeArtifacts(acsCluster *vlabs.AcsCluster, artifactsDir string) error {
|
||||
func writeArtifacts(acsCluster *vlabs.AcsCluster, template string, parameters, artifactsDir string, templateDirectory string, certsGenerated bool) error {
|
||||
if len(artifactsDir) == 0 {
|
||||
artifactsDir = fmt.Sprintf("k8s-%s", acsCluster.OrchestratorProfile.ClusterID)
|
||||
artifactsDir = fmt.Sprintf("%s-%s", acsCluster.OrchestratorProfile.OrchestratorType, tgen.GenerateClusterID(acsCluster))
|
||||
artifactsDir = path.Join("output", artifactsDir)
|
||||
}
|
||||
|
||||
//b, err := json.Marshal(acsCluster)
|
||||
b, err := json.MarshalIndent(acsCluster, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -92,23 +95,53 @@ func writeArtifacts(acsCluster *vlabs.AcsCluster, artifactsDir string) error {
|
|||
if e := saveFile(artifactsDir, "apimodel.json", b); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "ca.key", acsCluster.OrchestratorProfile.GetCAPrivateKey()); e != nil {
|
||||
|
||||
if e := saveFileString(artifactsDir, "azuredeploy.json", template); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "ca.crt", acsCluster.OrchestratorProfile.CaCertificate); e != nil {
|
||||
|
||||
if e := saveFileString(artifactsDir, "azuredeploy.parameters.json", parameters); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.key", acsCluster.OrchestratorProfile.ApiServerPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.crt", acsCluster.OrchestratorProfile.ApiServerCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.key", acsCluster.OrchestratorProfile.ClientPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.crt", acsCluster.OrchestratorProfile.ClientCertificate); e != nil {
|
||||
return e
|
||||
|
||||
if certsGenerated {
|
||||
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
directory := path.Join(artifactsDir, "kubeconfig")
|
||||
for _, location := range tgen.AzureLocations {
|
||||
b, gkcerr := tgen.GenerateKubeConfig(acsCluster, templateDirectory, location)
|
||||
if gkcerr != nil {
|
||||
return gkcerr
|
||||
}
|
||||
if e := saveFileString(directory, fmt.Sprintf("kubeconfig.%s.json", location), b); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e := saveFileString(artifactsDir, "ca.key", acsCluster.CertificateProfile.GetCAPrivateKey()); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "ca.crt", acsCluster.CertificateProfile.CaCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.key", acsCluster.CertificateProfile.APIServerPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "apiserver.crt", acsCluster.CertificateProfile.APIServerCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.key", acsCluster.CertificateProfile.ClientPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "client.crt", acsCluster.CertificateProfile.ClientCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "kubectlClient.key", acsCluster.CertificateProfile.KubeConfigPrivateKey); e != nil {
|
||||
return e
|
||||
}
|
||||
if e := saveFileString(artifactsDir, "kubectlClient.crt", acsCluster.CertificateProfile.KubeConfigCertificate); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -139,7 +172,7 @@ 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, "usage: %s [OPTIONS] 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")
|
||||
|
@ -148,12 +181,12 @@ func usage(errs ...error) {
|
|||
|
||||
var templateDirectory = flag.String("templateDirectory", "./parts", "directory containing base template files")
|
||||
var noPrettyPrint = flag.Bool("noPrettyPrint", false, "do not pretty print output")
|
||||
var noArtifacts = flag.Bool("noArtifacts", false, "does not generate artifacts (api model, json, cert files)")
|
||||
var artifactsDir = flag.String("artifacts", "", "directory where artifacts will be written")
|
||||
|
||||
func main() {
|
||||
var acsCluster *vlabs.AcsCluster
|
||||
var template string
|
||||
var parameters string
|
||||
var err error
|
||||
|
||||
flag.Parse()
|
||||
|
@ -190,23 +223,24 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
if template, err = tgen.GenerateTemplate(acsCluster, *templateDirectory); err != nil {
|
||||
if template, parameters, err = tgen.GenerateTemplate(acsCluster, *templateDirectory); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error generating template %s: %s", jsonFile, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if certsGenerated && !*noArtifacts {
|
||||
if err = writeArtifacts(acsCluster, *artifactsDir); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error writing artifacts %s", 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)
|
||||
}
|
||||
if parameters, err = prettyPrintArmTemplate(parameters); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if err = writeArtifacts(acsCluster, template, parameters, *artifactsDir, *templateDirectory, certsGenerated); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error writing artifacts %s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Print(template)
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// Package vlabs stores an experimental api model for acs
|
||||
package vlabs // import "./api/vlabs"
|
||||
package vlabs
|
||||
|
|
|
@ -2,23 +2,41 @@ 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 OrchestratorProfile `json:"orchestratorProfile"`
|
||||
MasterProfile MasterProfile `json:"masterProfile"`
|
||||
AgentPoolProfiles []AgentPoolProfile `json:"agentPoolProfiles"`
|
||||
LinuxProfile LinuxProfile `json:"linuxProfile"`
|
||||
ServicePrincipalProfile ServicePrincipalProfile `json:"servicePrincipalProfile"`
|
||||
CertificateProfile CertificateProfile `json:"certificateProfile"`
|
||||
}
|
||||
|
||||
// OrchestratorProfile represents the type of orchestrator
|
||||
type OrchestratorProfile struct {
|
||||
OrchestratorType string `json:"orchestratorType"`
|
||||
ServicePrincipalClientID string `json:"servicePrincipalClientID,omitempty"`
|
||||
ServicePrincipalClientSecret string `json:"servicePrincipalClientSecret,omitempty"`
|
||||
ApiServerCertificate string `json:"apiServerCertificate,omitempty"`
|
||||
ApiServerPrivateKey string `json:"apiServerPrivateKey,omitempty"`
|
||||
CaCertificate string `json:"caCertificate,omitempty"`
|
||||
ClientCertificate string `json:"clientCertificate,omitempty"`
|
||||
ClientPrivateKey string `json:"clientPrivateKey,omitempty"`
|
||||
ClusterID string `json:"clusterid,omitempty"`
|
||||
OrchestratorType string `json:"orchestratorType"`
|
||||
}
|
||||
|
||||
// ServicePrincipalProfile contains the client and secret used by the cluster for Azure Resource CRUD
|
||||
type ServicePrincipalProfile struct {
|
||||
ClientID string `json:"servicePrincipalClientID,omitempty"`
|
||||
Secret string `json:"servicePrincipalClientSecret,omitempty"`
|
||||
}
|
||||
|
||||
// CertificateProfile represents the definition of the master cluster
|
||||
type CertificateProfile struct {
|
||||
// CaCertificate is the certificate authority certificate.
|
||||
CaCertificate string `json:"caCertificate,omitempty"`
|
||||
// ApiServerCertificate is the rest api server certificate, and signed by the CA
|
||||
APIServerCertificate string `json:"apiServerCertificate,omitempty"`
|
||||
// ApiServerPrivateKey is the rest api server private key, and signed by the CA
|
||||
APIServerPrivateKey string `json:"apiServerPrivateKey,omitempty"`
|
||||
// ClientCertificate is the certificate used by the client kubelet services and signed by the CA
|
||||
ClientCertificate string `json:"clientCertificate,omitempty"`
|
||||
// ClientPrivateKey is the private key used by the client kubelet services and signed by the CA
|
||||
ClientPrivateKey string `json:"clientPrivateKey,omitempty"`
|
||||
// KubeConfigCertificate is the client certificate used for kubectl cli and signed by the CA
|
||||
KubeConfigCertificate string `json:"kubeConfigCertificate,omitempty"`
|
||||
// KubeConfigPrivateKey is the client private key used for kubectl cli and signed by the CA
|
||||
KubeConfigPrivateKey string `json:"kubeConfigPrivateKey,omitempty"`
|
||||
// caPrivateKey is an internal field only set if generation required
|
||||
caPrivateKey string
|
||||
}
|
||||
|
@ -64,13 +82,13 @@ type APIObject interface {
|
|||
}
|
||||
|
||||
// GetCAPrivateKey returns the ca private key
|
||||
func (o *OrchestratorProfile) GetCAPrivateKey() string {
|
||||
return o.caPrivateKey
|
||||
func (c *CertificateProfile) GetCAPrivateKey() string {
|
||||
return c.caPrivateKey
|
||||
}
|
||||
|
||||
// SetCAPrivateKey returns the ca private key
|
||||
func (o *OrchestratorProfile) SetCAPrivateKey(caPrivateKey string) {
|
||||
o.caPrivateKey = caPrivateKey
|
||||
// SetCAPrivateKey sets the ca private key
|
||||
func (c *CertificateProfile) SetCAPrivateKey(caPrivateKey string) {
|
||||
c.caPrivateKey = caPrivateKey
|
||||
}
|
||||
|
||||
// IsCustomVNET returns true if the customer brought their own VNET
|
||||
|
|
|
@ -19,18 +19,6 @@ func (o *OrchestratorProfile) Validate() error {
|
|||
return fmt.Errorf("OrchestratorProfile has unknown orchestrator: %s", o.OrchestratorType)
|
||||
}
|
||||
|
||||
if o.OrchestratorType == Kubernetes && len(o.ServicePrincipalClientID) == 0 {
|
||||
return fmt.Errorf("the service principal client ID must be specified with Orchestrator %s", o.OrchestratorType)
|
||||
}
|
||||
|
||||
if o.OrchestratorType == Kubernetes && len(o.ServicePrincipalClientSecret) == 0 {
|
||||
return fmt.Errorf("the service principal client secrect must be specified with Orchestrator %s", o.OrchestratorType)
|
||||
}
|
||||
|
||||
if o.OrchestratorType != Kubernetes && (len(o.ServicePrincipalClientID) > 0 || len(o.ServicePrincipalClientSecret) > 0) {
|
||||
return fmt.Errorf("Service principal and secret is not required for orchestrator %s", o.OrchestratorType)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -118,6 +106,14 @@ func (a *AcsCluster) Validate() error {
|
|||
if e := validateUniqueProfileNames(a.AgentPoolProfiles); e != nil {
|
||||
return e
|
||||
}
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && len(a.ServicePrincipalProfile.ClientID) == 0 {
|
||||
return fmt.Errorf("the service principal client ID must be specified with Orchestrator %s", a.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
if a.OrchestratorProfile.OrchestratorType == Kubernetes && len(a.ServicePrincipalProfile.Secret) == 0 {
|
||||
return fmt.Errorf("the service principal client secrect must be specified with Orchestrator %s", a.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
for _, agentPoolProfile := range a.AgentPoolProfiles {
|
||||
if e := agentPoolProfile.Validate(); e != nil {
|
||||
return e
|
||||
|
@ -226,7 +222,7 @@ func validateVNET(a *AcsCluster) error {
|
|||
}
|
||||
|
||||
masterFirstIP := net.ParseIP(a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
if masterFirstIP != nil {
|
||||
if masterFirstIP == nil {
|
||||
return fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP (with VNET Subnet specification) '%s' is an invalid IP address", a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Kubernetes",
|
||||
"servicePrincipalClientID": "REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
"orchestratorType": "Kubernetes"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
|
@ -32,5 +30,9 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"servicePrincipalProfile": {
|
||||
"servicePrincipalClientID": "REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
}
|
||||
}
|
|
@ -101,7 +101,6 @@
|
|||
99,
|
||||
100
|
||||
],
|
||||
"defaultValue": {{.Count}},
|
||||
"metadata": {
|
||||
"description": "The number of Mesos agents for the cluster. This value can be from 1 to 100"
|
||||
},
|
||||
|
@ -109,7 +108,6 @@
|
|||
},
|
||||
"{{.Name}}VMSize": {
|
||||
{{GetAgentAllowedSizes}}
|
||||
"defaultValue": "{{.VMSize}}",
|
||||
"metadata": {
|
||||
"description": "The size of the Virtual Machine."
|
||||
},
|
||||
|
@ -117,7 +115,6 @@
|
|||
},
|
||||
{{if .IsCustomVNET}}
|
||||
"{{.Name}}VnetSubnetID": {
|
||||
"defaultValue": "{{.VnetSubnetID}}",
|
||||
"metadata": {
|
||||
"description": "Sets the vnet subnet of agent pool '{{.Name}}'."
|
||||
},
|
||||
|
@ -125,7 +122,6 @@
|
|||
}
|
||||
{{else}}
|
||||
"{{.Name}}Subnet": {
|
||||
"defaultValue": "{{.GetSubnet}}",
|
||||
"metadata": {
|
||||
"description": "Sets the subnet of agent pool '{{.Name}}'."
|
||||
},
|
||||
|
@ -134,7 +130,6 @@
|
|||
{{end}}
|
||||
{{if IsPublic .Ports}}
|
||||
,"{{.Name}}EndpointDNSNamePrefix": {
|
||||
"defaultValue": "{{.DNSPrefix}}",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the agent pool IP Address. The concatenation of the domain name label and the regional DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
{
|
||||
"name": "{{{resourceGroup}}}-admin",
|
||||
"user": {
|
||||
"client-certificate-data": "<<<variables('clientCertificate')>>>",
|
||||
"client-key-data": "<<<variables('clientPrivateKey')>>>"
|
||||
"client-certificate-data": "<<<variables('kubeConfigCertificate')>>>",
|
||||
"client-key-data": "<<<variables('kubeConfigPrivateKey')>>>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"orchestratorProfile": {
|
||||
"orchestratorType": "Kubernetes",
|
||||
"servicePrincipalClientID": "REPLACE-WITH-ServicePrincipalClientID",
|
||||
"servicePrincipalClientSecret": "REPLACE-WITH-myServicePrincipalClientSecret"
|
||||
},
|
||||
"masterProfile": {
|
||||
"count": 1,
|
||||
"dnsPrefix": "mgmtanhowe1004f",
|
||||
"vmSize": "Standard_D2_v2"
|
||||
},
|
||||
"agentPoolProfiles": [
|
||||
{
|
||||
"name": "agentpool1",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
},
|
||||
{
|
||||
"name": "agentpool2",
|
||||
"count": 3,
|
||||
"vmSize": "Standard_D2_v2",
|
||||
"isStateful": true
|
||||
}
|
||||
],
|
||||
"linuxProfile": {
|
||||
"adminUsername": "azureuser",
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8fhkh3jpHUQsrUIezFB5k4Rq9giJM8G1Cr0u2IRMiqG++nat5hbOr3gODpTA0h11q9bzb6nJtK7NtDzIHx+w3YNIVpcTGLiUEsfUbY53IHg7Nl/p3/gkST3g0R6BSL7Hg45SfyvpH7kwY30MoVHG/6P3go4SKlYoHXlgaaNr3fMwUTIeE9ofvyS3fcr6xxlsoB6luKuEs50h0NGsE4QEnbfSY4Yd/C1ucc3mEw+QFXBIsENHfHfZYrLNHm2L8MXYVmAH8k//5sFs4Migln9GiUgEQUT6uOjowsZyXBbXwfT11og+syPkAq4eqjiC76r0w6faVihdBYVoc/UcyupgH azureuser@linuxvm"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,9 @@
|
|||
"variables": {
|
||||
{{range $index, $agent := .AgentPoolProfiles}}
|
||||
{{template "kubernetesagentvars.t" .}}
|
||||
{{if .HasDisks}}
|
||||
"{{.Name}}DataAccountName": "[concat(variables('storageAccountBaseName'), 'data{{$index}}')]",
|
||||
{{end}}
|
||||
"{{.Name}}Index": {{$index}},
|
||||
"{{.Name}}AccountName": "[concat(variables('storageAccountBaseName'), 'agnt{{$index}}')]",
|
||||
{{end}}
|
||||
|
|
|
@ -8,7 +8,7 @@ packages:
|
|||
- traceroute
|
||||
|
||||
runcmd:
|
||||
- /bin/bash -c "/bin/echo DAEMON_ARGS=--advertise-client-urls {{{singleQuote}}}http://127.0.0.1:2379,http://{{{masterPrivateIp}}}:2379{{{singleQuote}}} --listen-client-urls {{{singleQuote}}}http://0.0.0.0:2379,http://0.0.0.0:4001{{{singleQuote}}} | tee -a /etc/default/etcd"
|
||||
- /bin/bash -c "/bin/echo DAEMON_ARGS=--advertise-client-urls ""http://127.0.0.1:2379,http://{{{masterPrivateIp}}}:2379"" --listen-client-urls ""http://0.0.0.0:2379,http://0.0.0.0:4001"" | tee -a /etc/default/etcd"
|
||||
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://get.docker.com/ > /tmp/install-docker
|
||||
- /bin/bash -c "/bin/bash /tmp/install-docker"
|
||||
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://storage.googleapis.com/kubernetes-release/release/v1.3.8/bin/linux/amd64/kubectl > /usr/local/bin/kubectl
|
||||
|
@ -128,7 +128,7 @@ write_files:
|
|||
command:
|
||||
- "/hyperkube"
|
||||
- "apiserver"
|
||||
- "--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,PersistentVolumeLabel,ResourceQuota"
|
||||
- "--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota"
|
||||
- "--address=0.0.0.0"
|
||||
- "--allow-privileged"
|
||||
- "--insecure-port=8080"
|
||||
|
|
|
@ -6,11 +6,15 @@
|
|||
"caCertificate": "[parameters('caCertificate')]",
|
||||
"clientCertificate": "[parameters('clientCertificate')]",
|
||||
"clientPrivateKey": "[parameters('clientPrivateKey')]",
|
||||
"kubeConfigCertificate": "[parameters('kubeConfigCertificate')]",
|
||||
"kubeConfigPrivateKey": "[parameters('kubeConfigPrivateKey')]",
|
||||
"kubernetesHyperkubeSpec": "[parameters('kubernetesHyperkubeSpec')]",
|
||||
"servicePrincipalClientId": "[parameters('servicePrincipalClientId')]",
|
||||
"servicePrincipalClientSecret": "[parameters('servicePrincipalClientSecret')]",
|
||||
"username": "[parameters('linuxAdminUsername')]",
|
||||
{{if AnyAgentHasDisks}}
|
||||
"dataStorageAccountPrefixSeed": 97,
|
||||
{{end}}
|
||||
"masterFqdnPrefix": "[parameters('masterEndpointDNSNamePrefix')]",
|
||||
"masterPrivateIp": "[parameters('firstConsecutiveStaticIP')]",
|
||||
"masterVMSize": "[parameters('masterVMSize')]",
|
||||
|
@ -18,8 +22,8 @@
|
|||
"masterCount": {{.MasterProfile.Count}},
|
||||
"apiVersionDefault": "2016-03-30",
|
||||
"apiVersionStorage": "2015-06-15",
|
||||
"kubeDnsServiceIp": "10.3.0.10",
|
||||
"kubeServiceCidr": "10.3.0.0/16",
|
||||
"kubeDnsServiceIp": "10.0.0.10",
|
||||
"kubeServiceCidr": "10.0.0.0/16",
|
||||
"location": "[resourceGroup().location]",
|
||||
"masterAvailabilitySet": "master-availabilityset",
|
||||
"nsgName": "[concat(variables('masterVMNamePrefix'), 'nsg')]",
|
||||
|
@ -35,10 +39,9 @@
|
|||
"osImageVersion": "16.04.201606270",
|
||||
"resourceGroup": "[resourceGroup().name]",
|
||||
"routeTableName": "[concat(variables('masterVMNamePrefix'),'-routetable')]",
|
||||
"singleQuote": "'",
|
||||
"sshNatPorts": [22,2201,2202,2203,2204],
|
||||
"sshKeyPath": "[concat('/home/',variables('username'),'/.ssh/authorized_keys')]",
|
||||
"storageAccountBaseName": "[concat(uniqueString(concat(variables('masterFqdnPrefix'),resourceGroup().location)))]",
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterFqdnPrefix'),resourceGroup().location))]",
|
||||
"storageAccountPrefixes": [
|
||||
"0",
|
||||
"6",
|
||||
|
@ -94,6 +97,7 @@
|
|||
"masterLbIPConfigName": "[concat(variables('orchestratorName'), '-master-lbFrontEnd-', variables('nameSuffix'))]",
|
||||
"masterLbName": "[concat(variables('orchestratorName'), '-master-lb-', variables('nameSuffix'))]",
|
||||
"masterLbBackendPoolName": "[concat(variables('orchestratorName'), '-master-pool-', variables('nameSuffix'))]",
|
||||
"masterFirstAddrComment": "these MasterFirstAddrComment are used to place multiple masters consecutively in the address space",
|
||||
"masterFirstAddrOctets": "[split(parameters('firstConsecutiveStaticIP'),'.')]",
|
||||
"masterFirstAddrOctet4": "[variables('masterFirstAddrOctets')[3]]",
|
||||
"masterFirstAddrPrefix": "[concat(variables('masterFirstAddrOctets')[0],'.',variables('masterFirstAddrOctets')[1],'.',variables('masterFirstAddrOctets')[2],'.')]",
|
||||
|
|
|
@ -1,54 +1,58 @@
|
|||
"apiServerCertificate": {
|
||||
"defaultValue": "{{Base64 .OrchestratorProfile.ApiServerCertificate}}",
|
||||
"metadata": {
|
||||
"description": "The AD Tenant Id"
|
||||
"description": "The base 64 server certificate used on the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"apiServerPrivateKey": {
|
||||
"defaultValue": "{{Base64 .OrchestratorProfile.ApiServerPrivateKey}}",
|
||||
"metadata": {
|
||||
"description": "User name for the Linux Virtual Machines (SSH or Password)."
|
||||
"description": "The base 64 server private key used on the master."
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"caCertificate": {
|
||||
"defaultValue": "{{Base64 .OrchestratorProfile.CaCertificate}}",
|
||||
"metadata": {
|
||||
"description": "The certificate authority certificate"
|
||||
"description": "The base 64 certificate authority certificate"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"clientCertificate": {
|
||||
"defaultValue": "{{Base64 .OrchestratorProfile.ClientCertificate}}",
|
||||
"metadata": {
|
||||
"description": "The client certificate used to communicate with the master"
|
||||
"description": "The base 64 client certificate used to communicate with the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"clientPrivateKey": {
|
||||
"defaultValue": "{{Base64 .OrchestratorProfile.ClientPrivateKey}}",
|
||||
"metadata": {
|
||||
"description": "The client private key used to communicate with the master"
|
||||
"description": "The base 64 client private key used to communicate with the master"
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"kubeConfigCertificate": {
|
||||
"metadata": {
|
||||
"description": "The base 64 certificate used by cli to communicate with the master"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"kubeConfigPrivateKey": {
|
||||
"metadata": {
|
||||
"description": "The base 64 private key used by cli to communicate with the master"
|
||||
},
|
||||
"type": "securestring"
|
||||
},
|
||||
"kubernetesHyperkubeSpec": {
|
||||
"defaultValue": "gcr.io/google_containers/hyperkube-amd64:v1.4.0-beta.10",
|
||||
"metadata": {
|
||||
"description": "The container spec for hyperkube."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"servicePrincipalClientId": {
|
||||
"defaultValue": "{{.OrchestratorProfile.ServicePrincipalClientID}}",
|
||||
"metadata": {
|
||||
"description": "Client ID (used by cloudprovider)"
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"servicePrincipalClientSecret": {
|
||||
"defaultValue": "{{.OrchestratorProfile.ServicePrincipalClientSecret}}",
|
||||
"metadata": {
|
||||
"description": "The Service Principal Client Secret."
|
||||
},
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
"linuxAdminUsername": {
|
||||
"defaultValue": "{{.LinuxProfile.AdminUsername}}",
|
||||
"metadata": {
|
||||
"description": "User name for the Linux Virtual Machines (SSH or Password)."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"masterEndpointDNSNamePrefix": {
|
||||
"defaultValue": "{{.MasterProfile.DNSPrefix}}",
|
||||
"metadata": {
|
||||
"description": "Sets the Domain name label for the master IP Address. The concatenation of the domain name label and the regional DNS zone make up the fully qualified domain name associated with the public IP address."
|
||||
},
|
||||
|
@ -14,7 +12,6 @@
|
|||
},
|
||||
{{if .MasterProfile.IsCustomVNET}}
|
||||
"masterVnetSubnetID": {
|
||||
"defaultValue": "{{.MasterProfile.VnetSubnetID}}",
|
||||
"metadata": {
|
||||
"description": "Sets the vnet subnet of the master."
|
||||
},
|
||||
|
@ -22,7 +19,6 @@
|
|||
},
|
||||
{{else}}
|
||||
"masterSubnet": {
|
||||
"defaultValue": "{{.MasterProfile.GetSubnet}}",
|
||||
"metadata": {
|
||||
"description": "Sets the subnet of the master node(s)."
|
||||
},
|
||||
|
@ -30,7 +26,6 @@
|
|||
},
|
||||
{{end}}
|
||||
"firstConsecutiveStaticIP": {
|
||||
"defaultValue": "{{.MasterProfile.FirstConsecutiveStaticIP}}",
|
||||
"metadata": {
|
||||
"description": "Sets the static IP of the first master"
|
||||
},
|
||||
|
@ -38,14 +33,12 @@
|
|||
},
|
||||
"masterVMSize": {
|
||||
{{GetMasterAllowedSizes}}
|
||||
"defaultValue": "{{.MasterProfile.VMSize}}",
|
||||
"metadata": {
|
||||
"description": "The size of the Virtual Machine."
|
||||
},
|
||||
"type": "string"
|
||||
},
|
||||
"sshRSAPublicKey": {
|
||||
"defaultValue": "{{GetLinuxProfileFirstSSHPublicKey}}",
|
||||
"metadata": {
|
||||
"description": "SSH public key used for auth to all Linux machines. Not Required. If not set, you must provide a password key."
|
||||
},
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"postInstallScriptURI": "disabled",
|
||||
"sshKeyPath": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
|
||||
"sshRSAPublicKey": "[parameters('sshRSAPublicKey')]",
|
||||
"storageAccountBaseName": "[concat(uniqueString(concat(variables('masterEndpointDNSNamePrefix'),resourceGroup().location)))]",
|
||||
"storageAccountBaseName": "[uniqueString(concat(variables('masterEndpointDNSNamePrefix'),resourceGroup().location))]",
|
||||
"storageAccountPrefixes": [
|
||||
"0",
|
||||
"6",
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
package templategenerator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
||||
"./../api/vlabs"
|
||||
"./../util"
|
||||
)
|
||||
|
||||
// SetAcsClusterDefaults for an AcsCluster, returns true if certs are generated
|
||||
func SetAcsClusterDefaults(a *vlabs.AcsCluster) (bool, error) {
|
||||
|
||||
if len(a.OrchestratorProfile.ClusterID) == 0 {
|
||||
a.OrchestratorProfile.ClusterID = generateClusterID(a)
|
||||
}
|
||||
|
||||
setMasterNetworkDefaults(a)
|
||||
|
||||
setAgentNetworkDefaults(a)
|
||||
|
||||
certsGenerated, e := setDefaultCerts(&a.OrchestratorProfile, &a.MasterProfile)
|
||||
if e != nil {
|
||||
return false, e
|
||||
}
|
||||
return certsGenerated, nil
|
||||
}
|
||||
|
||||
// generateClusterID creates a unique 8 string cluster ID
|
||||
func generateClusterID(acsCluster *vlabs.AcsCluster) string {
|
||||
uniqueNameSuffixSize := 8
|
||||
// the name suffix uniquely identifies the cluster and is generated off a hash
|
||||
// from the master dns name
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
|
||||
rand.Seed(int64(h.Sum64()))
|
||||
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
|
||||
}
|
||||
|
||||
// SetMasterNetworkDefaults for masters
|
||||
func setMasterNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
a.MasterProfile.SetSubnet(DefaultKubernetesMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveKubernetesStaticIP
|
||||
} else {
|
||||
a.MasterProfile.SetSubnet(DefaultMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveStaticIP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAgentNetworkDefaults for agents
|
||||
func setAgentNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
// configure the subnets if not in custom VNET
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
subnetCounter := 0
|
||||
for i := range a.AgentPoolProfiles {
|
||||
profile := &a.AgentPoolProfiles[i]
|
||||
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
profile.SetSubnet(a.MasterProfile.GetSubnet())
|
||||
} else {
|
||||
profile.SetSubnet(fmt.Sprintf(DefaultAgentSubnetTemplate, subnetCounter))
|
||||
}
|
||||
|
||||
subnetCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setDefaultCerts(o *vlabs.OrchestratorProfile, m *vlabs.MasterProfile) (bool, error) {
|
||||
certsGenerated := false
|
||||
// auto generate certs if none of them have been set by customer
|
||||
if len(o.ApiServerCertificate) > 0 || len(o.ApiServerPrivateKey) > 0 ||
|
||||
len(o.CaCertificate) > 0 ||
|
||||
len(o.ClientCertificate) > 0 || len(o.ClientPrivateKey) > 0 {
|
||||
return certsGenerated, nil
|
||||
}
|
||||
masterWildCardFQDN := FormatAzureProdFQDN(m.DNSPrefix, "*")
|
||||
masterExtraFQDNs := FormatAzureProdFQDNs(m.DNSPrefix)
|
||||
firstMasterIP := net.ParseIP(m.FirstConsecutiveStaticIP)
|
||||
|
||||
if firstMasterIP == nil {
|
||||
return false, fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP '%s' is an invalid IP address", m.FirstConsecutiveStaticIP)
|
||||
}
|
||||
|
||||
ips := []net.IP{firstMasterIP}
|
||||
|
||||
for i := 1; i < m.Count; i++ {
|
||||
ips = append(ips, net.IP{firstMasterIP[12], firstMasterIP[13], firstMasterIP[14], firstMasterIP[15] + byte(i)})
|
||||
}
|
||||
|
||||
caPair, apiServerPair, clientPair, err := util.CreatePki(masterWildCardFQDN, masterExtraFQDNs, ips, DefaultKubernetesClusterDomain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
certsGenerated = true
|
||||
|
||||
o.ApiServerCertificate = apiServerPair.CertificatePem
|
||||
o.ApiServerPrivateKey = apiServerPair.PrivateKeyPem
|
||||
o.CaCertificate = caPair.CertificatePem
|
||||
o.SetCAPrivateKey(caPair.PrivateKeyPem)
|
||||
o.ClientCertificate = clientPair.CertificatePem
|
||||
o.ClientPrivateKey = clientPair.PrivateKeyPem
|
||||
|
||||
return certsGenerated, nil
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
// Package templategenerator takes an ACS cluster model and generates the corresponding template
|
||||
package templategenerator // import "./templategenerator"
|
|
@ -99,7 +99,7 @@ Get-FileContents() {
|
|||
$Locations
|
||||
)
|
||||
|
||||
$text = "package templategenerator"
|
||||
$text = "package tgen"
|
||||
$text += @"
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package templategenerator
|
||||
package tgen
|
||||
|
||||
import "fmt"
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package templategenerator
|
||||
package tgen
|
||||
|
||||
const (
|
||||
// BaseLBPriority specifies the base lb priority.
|
||||
BaseLBPriority = 200
|
||||
// DefaultMasterSubnet specifies the default master subnet
|
||||
// DefaultMasterSubnet specifies the default master subnet for DCOS or Swarm
|
||||
DefaultMasterSubnet = "172.16.0.0/24"
|
||||
// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0
|
||||
// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0 for DCOS or Swarm
|
||||
DefaultFirstConsecutiveStaticIP = "172.16.0.5"
|
||||
// DefaultKubernetesMasterSubnet specifies the default kubernetes master subnet
|
||||
DefaultKubernetesMasterSubnet = "10.240.0.0/16"
|
||||
|
@ -15,4 +15,7 @@ const (
|
|||
DefaultAgentSubnetTemplate = "10.%d.0.0/24"
|
||||
// DefaultKubernetesClusterDomain is the dns suffix used in the cluster (used as a SAN in the PKI generation)
|
||||
DefaultKubernetesClusterDomain = "cluster.local"
|
||||
// KubernetesHyperkubeSpec is the hyperkube version used for Kubernetes setup
|
||||
// The latest stable version can be found here: https://storage.googleapis.com/kubernetes-release/release/stable.txt
|
||||
KubernetesHyperkubeSpec = "gcr.io/google_containers/hyperkube-amd64:v1.4.0"
|
||||
)
|
|
@ -0,0 +1,114 @@
|
|||
package tgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"./../api/vlabs"
|
||||
"./../util"
|
||||
)
|
||||
|
||||
// SetAcsClusterDefaults for an AcsCluster, returns true if certs are generated
|
||||
func SetAcsClusterDefaults(a *vlabs.AcsCluster) (bool, error) {
|
||||
|
||||
setMasterNetworkDefaults(a)
|
||||
|
||||
setAgentNetworkDefaults(a)
|
||||
|
||||
certsGenerated, e := setDefaultCerts(a)
|
||||
if e != nil {
|
||||
return false, e
|
||||
}
|
||||
return certsGenerated, nil
|
||||
}
|
||||
|
||||
// SetMasterNetworkDefaults for masters
|
||||
func setMasterNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
a.MasterProfile.SetSubnet(DefaultKubernetesMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveKubernetesStaticIP
|
||||
} else {
|
||||
a.MasterProfile.SetSubnet(DefaultMasterSubnet)
|
||||
a.MasterProfile.FirstConsecutiveStaticIP = DefaultFirstConsecutiveStaticIP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetAgentNetworkDefaults for agents
|
||||
func setAgentNetworkDefaults(a *vlabs.AcsCluster) {
|
||||
// configure the subnets if not in custom VNET
|
||||
if !a.MasterProfile.IsCustomVNET() {
|
||||
subnetCounter := 0
|
||||
for i := range a.AgentPoolProfiles {
|
||||
profile := &a.AgentPoolProfiles[i]
|
||||
|
||||
if a.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
profile.SetSubnet(a.MasterProfile.GetSubnet())
|
||||
} else {
|
||||
profile.SetSubnet(fmt.Sprintf(DefaultAgentSubnetTemplate, subnetCounter))
|
||||
}
|
||||
|
||||
subnetCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setDefaultCerts(a *vlabs.AcsCluster) (bool, error) {
|
||||
if !certGenerationRequired(a) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
masterWildCardFQDN := FormatAzureProdFQDN(a.MasterProfile.DNSPrefix, "*")
|
||||
masterExtraFQDNs := FormatAzureProdFQDNs(a.MasterProfile.DNSPrefix)
|
||||
firstMasterIP := net.ParseIP(a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
|
||||
if firstMasterIP == nil {
|
||||
return false, fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP '%s' is an invalid IP address", a.MasterProfile.FirstConsecutiveStaticIP)
|
||||
}
|
||||
|
||||
ips := []net.IP{firstMasterIP}
|
||||
|
||||
for i := 1; i < a.MasterProfile.Count; i++ {
|
||||
ips = append(ips, net.IP{firstMasterIP[12], firstMasterIP[13], firstMasterIP[14], firstMasterIP[15] + byte(i)})
|
||||
}
|
||||
|
||||
caPair, apiServerPair, clientPair, kubeConfigPair, err := util.CreatePki(masterWildCardFQDN, masterExtraFQDNs, ips, DefaultKubernetesClusterDomain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
a.CertificateProfile.APIServerCertificate = apiServerPair.CertificatePem
|
||||
a.CertificateProfile.APIServerPrivateKey = apiServerPair.PrivateKeyPem
|
||||
a.CertificateProfile.CaCertificate = caPair.CertificatePem
|
||||
a.CertificateProfile.SetCAPrivateKey(caPair.PrivateKeyPem)
|
||||
a.CertificateProfile.ClientCertificate = clientPair.CertificatePem
|
||||
a.CertificateProfile.ClientPrivateKey = clientPair.PrivateKeyPem
|
||||
a.CertificateProfile.KubeConfigCertificate = kubeConfigPair.CertificatePem
|
||||
a.CertificateProfile.KubeConfigPrivateKey = kubeConfigPair.PrivateKeyPem
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func certGenerationRequired(a *vlabs.AcsCluster) bool {
|
||||
if len(a.CertificateProfile.APIServerCertificate) > 0 || len(a.CertificateProfile.APIServerPrivateKey) > 0 ||
|
||||
len(a.CertificateProfile.CaCertificate) > 0 ||
|
||||
len(a.CertificateProfile.ClientCertificate) > 0 || len(a.CertificateProfile.ClientPrivateKey) > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
switch a.OrchestratorProfile.OrchestratorType {
|
||||
case vlabs.DCOS:
|
||||
return false
|
||||
case vlabs.DCOS184:
|
||||
return false
|
||||
case vlabs.DCOS173:
|
||||
return false
|
||||
case vlabs.Swarm:
|
||||
return false
|
||||
case vlabs.Kubernetes:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package tgen takes an ACS cluster model and generates the corresponding template
|
||||
package tgen
|
|
@ -1,11 +1,14 @@
|
|||
package templategenerator
|
||||
package tgen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
|
@ -69,7 +72,7 @@ func VerifyFiles(partsDirectory string) error {
|
|||
}
|
||||
|
||||
// GenerateTemplate generates the template from the API Model
|
||||
func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (string, error) {
|
||||
func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (string, string, error) {
|
||||
var err error
|
||||
var templ *template.Template
|
||||
|
||||
|
@ -89,25 +92,117 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
|
|||
files = append(commonTemplateFiles, kubernetesTemplateFiles...)
|
||||
baseFile = kubernetesBaseFile
|
||||
} else {
|
||||
return "", fmt.Errorf("orchestrator '%s' is unsupported", acsCluster.OrchestratorProfile.OrchestratorType)
|
||||
return "", "", fmt.Errorf("orchestrator '%s' is unsupported", acsCluster.OrchestratorProfile.OrchestratorType)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
templateFile := path.Join(partsDirectory, file)
|
||||
bytes, e := ioutil.ReadFile(templateFile)
|
||||
if e != nil {
|
||||
return "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
|
||||
return "", "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
|
||||
}
|
||||
if _, err = templ.New(file).Parse(string(bytes)); err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
var b bytes.Buffer
|
||||
if err = templ.ExecuteTemplate(&b, baseFile, acsCluster); err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return b.String(), nil
|
||||
var parametersMap *map[string]interface{}
|
||||
if parametersMap, err = getParameters(acsCluster); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
var parameterBytes []byte
|
||||
if parameterBytes, err = json.Marshal(parametersMap); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return b.String(), string(parameterBytes), nil
|
||||
}
|
||||
|
||||
// GenerateClusterID creates a unique 8 string cluster ID
|
||||
func GenerateClusterID(acsCluster *vlabs.AcsCluster) string {
|
||||
uniqueNameSuffixSize := 8
|
||||
// the name suffix uniquely identifies the cluster and is generated off a hash
|
||||
// from the master dns name
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
|
||||
rand.Seed(int64(h.Sum64()))
|
||||
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
|
||||
}
|
||||
|
||||
// GenerateKubeConfig returns a JSON string representing the KubeConfig
|
||||
func GenerateKubeConfig(acsCluster *vlabs.AcsCluster, templateDirectory string, location string) (string, error) {
|
||||
kubeTemplateFile := path.Join(templateDirectory, kubeConfigJSON)
|
||||
if _, err := os.Stat(kubeTemplateFile); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("file %s does not exist, did you specify the correct template directory?", kubeTemplateFile)
|
||||
}
|
||||
b, err := ioutil.ReadFile(kubeTemplateFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading kube config template file %s: %s", kubeTemplateFile, err.Error())
|
||||
}
|
||||
kubeconfig := string(b)
|
||||
// variable replacement
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('caCertificate')>>>", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.CaCertificate)), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<reference(concat('Microsoft.Network/publicIPAddresses/', variables('masterPublicIPAddressName'))).dnsSettings.fqdn>>>", FormatAzureProdFQDN(acsCluster.MasterProfile.DNSPrefix, location), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "{{{resourceGroup}}}", acsCluster.MasterProfile.DNSPrefix, -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('kubeConfigCertificate')>>>", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigCertificate)), -1)
|
||||
kubeconfig = strings.Replace(kubeconfig, "<<<variables('kubeConfigPrivateKey')>>>", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigPrivateKey)), -1)
|
||||
|
||||
return kubeconfig, nil
|
||||
}
|
||||
|
||||
func getParameters(acsCluster *vlabs.AcsCluster) (*map[string]interface{}, error) {
|
||||
parametersMap := &map[string]interface{}{}
|
||||
|
||||
// Master Parameters
|
||||
addValue(parametersMap, "linuxAdminUsername", acsCluster.LinuxProfile.AdminUsername)
|
||||
addValue(parametersMap, "masterEndpointDNSNamePrefix", acsCluster.MasterProfile.DNSPrefix)
|
||||
if acsCluster.MasterProfile.IsCustomVNET() {
|
||||
addValue(parametersMap, "masterVnetSubnetID", acsCluster.MasterProfile.VnetSubnetID)
|
||||
} else {
|
||||
addValue(parametersMap, "masterSubnet", acsCluster.MasterProfile.GetSubnet())
|
||||
}
|
||||
addValue(parametersMap, "firstConsecutiveStaticIP", acsCluster.MasterProfile.FirstConsecutiveStaticIP)
|
||||
addValue(parametersMap, "masterVMSize", acsCluster.MasterProfile.VMSize)
|
||||
addValue(parametersMap, "sshRSAPublicKey", acsCluster.LinuxProfile.SSH.PublicKeys[0].KeyData)
|
||||
|
||||
// Kubernetes Parameters
|
||||
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
|
||||
addValue(parametersMap, "apiServerCertificate", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.APIServerCertificate)))
|
||||
addValue(parametersMap, "apiServerPrivateKey", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.APIServerPrivateKey)))
|
||||
addValue(parametersMap, "caCertificate", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.CaCertificate)))
|
||||
addValue(parametersMap, "clientCertificate", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientCertificate)))
|
||||
addValue(parametersMap, "clientPrivateKey", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.ClientPrivateKey)))
|
||||
addValue(parametersMap, "kubeConfigCertificate", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigCertificate)))
|
||||
addValue(parametersMap, "kubeConfigPrivateKey", base64.URLEncoding.EncodeToString([]byte(acsCluster.CertificateProfile.KubeConfigPrivateKey)))
|
||||
addValue(parametersMap, "kubernetesHyperkubeSpec", KubernetesHyperkubeSpec)
|
||||
addValue(parametersMap, "servicePrincipalClientId", acsCluster.ServicePrincipalProfile.ClientID)
|
||||
addValue(parametersMap, "servicePrincipalClientSecret", acsCluster.ServicePrincipalProfile.Secret)
|
||||
}
|
||||
|
||||
// Agent parameters
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
addValue(parametersMap, fmt.Sprintf("%sCount", agentProfile.Name), agentProfile.Count)
|
||||
addValue(parametersMap, fmt.Sprintf("%sVMSize", agentProfile.Name), agentProfile.VMSize)
|
||||
if agentProfile.IsCustomVNET() {
|
||||
addValue(parametersMap, fmt.Sprintf("%sVnetSubnetID", agentProfile.Name), agentProfile.VnetSubnetID)
|
||||
} else {
|
||||
addValue(parametersMap, fmt.Sprintf("%sSubnet", agentProfile.Name), agentProfile.GetSubnet())
|
||||
}
|
||||
if len(agentProfile.Ports) > 0 {
|
||||
addValue(parametersMap, fmt.Sprintf("%sEndpointDNSNamePrefix", agentProfile.Name), agentProfile.DNSPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
return parametersMap, nil
|
||||
}
|
||||
|
||||
func addValue(m *map[string]interface{}, k string, v interface{}) {
|
||||
(*m)[k] = *(&map[string]interface{}{})
|
||||
(*m)[k].(map[string]interface{})["Value"] = v
|
||||
}
|
||||
|
||||
// getTemplateFuncMap returns all functions used in template generation
|
||||
|
@ -147,11 +242,8 @@ func getTemplateFuncMap(acsCluster *vlabs.AcsCluster, partsDirectory string) map
|
|||
"GetDCOSGUID": func() string {
|
||||
return getPackageGUID(acsCluster.OrchestratorProfile.OrchestratorType, acsCluster.MasterProfile.Count)
|
||||
},
|
||||
"GetLinuxProfileFirstSSHPublicKey": func() string {
|
||||
return acsCluster.LinuxProfile.SSH.PublicKeys[0].KeyData
|
||||
},
|
||||
"GetUniqueNameSuffix": func() string {
|
||||
return acsCluster.OrchestratorProfile.ClusterID
|
||||
return GenerateClusterID(acsCluster)
|
||||
},
|
||||
"GetVNETAddressPrefixes": func() string {
|
||||
return getVNETAddressPrefixes(acsCluster)
|
||||
|
@ -195,6 +287,14 @@ func getTemplateFuncMap(acsCluster *vlabs.AcsCluster, partsDirectory string) map
|
|||
}
|
||||
return str
|
||||
},
|
||||
"AnyAgentHasDisks": func() bool {
|
||||
for _, agentProfile := range acsCluster.AgentPoolProfiles {
|
||||
if agentProfile.HasDisks() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
// inspired by http://stackoverflow.com/questions/18276173/calling-a-template-with-several-pipeline-parameters/18276968#18276968
|
||||
"dict": func(values ...interface{}) (map[string]interface{}, error) {
|
||||
if len(values)%2 != 0 {
|
||||
|
@ -447,6 +547,7 @@ func getSingleLineForTemplate(yamlFilename string, partsDirectory string) (strin
|
|||
if err != nil {
|
||||
return "", fmt.Errorf("error reading yaml file %s: %s", yamlFile, err.Error())
|
||||
}
|
||||
// template.JSEscapeString leaves undesirable chars that don't work with pretty print
|
||||
yamlStr := string(b)
|
||||
yamlStr = strings.Replace(yamlStr, "\\", "\\\\", -1)
|
||||
yamlStr = strings.Replace(yamlStr, "\r\n", "\\n", -1)
|
||||
|
@ -454,10 +555,16 @@ func getSingleLineForTemplate(yamlFilename string, partsDirectory string) (strin
|
|||
yamlStr = strings.Replace(yamlStr, "\"", "\\\"", -1)
|
||||
|
||||
// variable replacement
|
||||
rVariable := regexp.MustCompile("{{{([^}]*)}}}")
|
||||
rVariable, e1 := regexp.Compile("{{{([^}]*)}}}")
|
||||
if e1 != nil {
|
||||
return "", e1
|
||||
}
|
||||
yamlStr = rVariable.ReplaceAllString(yamlStr, "',variables('$1'),'")
|
||||
// verbatim replacement
|
||||
rVerbatim := regexp.MustCompile("<<<([^>]*)>>>")
|
||||
rVerbatim, e2 := regexp.Compile("<<<([^>]*)>>>")
|
||||
if e2 != nil {
|
||||
return "", e2
|
||||
}
|
||||
yamlStr = rVerbatim.ReplaceAllString(yamlStr, "',$1,'")
|
||||
return yamlStr, nil
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
// Package util provides various utility functions for the generator
|
||||
package util // import "./util"
|
||||
package util
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// util package comes from https://github.com/colemickens/azkube/blob/master/util/pki.go
|
||||
package util
|
||||
|
||||
import (
|
||||
|
@ -11,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +24,7 @@ type PkiKeyCertPair struct {
|
|||
PrivateKeyPem string
|
||||
}
|
||||
|
||||
func CreatePki(masterFQDN string, extraFQDNs []string, extraIPs []net.IP, clusterDomain string) (*PkiKeyCertPair, *PkiKeyCertPair, *PkiKeyCertPair, error) {
|
||||
func CreatePki(masterFQDN string, extraFQDNs []string, extraIPs []net.IP, clusterDomain string) (*PkiKeyCertPair, *PkiKeyCertPair, *PkiKeyCertPair, *PkiKeyCertPair, error) {
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.default"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.default.svc"))
|
||||
|
@ -32,23 +32,59 @@ func CreatePki(masterFQDN string, extraFQDNs []string, extraIPs []net.IP, cluste
|
|||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system.svc"))
|
||||
extraFQDNs = append(extraFQDNs, fmt.Sprintf("kubernetes.kube-system.svc.%s", clusterDomain))
|
||||
|
||||
start := time.Now()
|
||||
caCertificate, caPrivateKey, err := createCertificate("ca", nil, nil, false, "", nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
apiServerCertificate, apiServerPrivateKey, err := createCertificate("apiserver", caCertificate, caPrivateKey, true, masterFQDN, extraFQDNs, extraIPs)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
clientCertificate, clientPrivateKey, err := createCertificate("client", caCertificate, caPrivateKey, false, "", nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
apiServerCertificate *x509.Certificate
|
||||
apiServerPrivateKey *rsa.PrivateKey
|
||||
clientCertificate *x509.Certificate
|
||||
clientPrivateKey *rsa.PrivateKey
|
||||
kubeConfigCertificate *x509.Certificate
|
||||
kubeConfigPrivateKey *rsa.PrivateKey
|
||||
)
|
||||
errors := make(chan error)
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
apiServerCertificate, apiServerPrivateKey, err = createCertificate("apiserver", caCertificate, caPrivateKey, true, masterFQDN, extraFQDNs, extraIPs)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
clientCertificate, clientPrivateKey, err = createCertificate("client", caCertificate, caPrivateKey, false, "", nil, nil)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
kubeConfigCertificate, kubeConfigPrivateKey, err = createCertificate("client", caCertificate, caPrivateKey, false, "", nil, nil)
|
||||
errors <- err
|
||||
}()
|
||||
|
||||
e1 := <-errors
|
||||
e2 := <-errors
|
||||
e3 := <-errors
|
||||
if e1 != nil {
|
||||
return nil, nil, nil, nil, e1
|
||||
}
|
||||
if e2 != nil {
|
||||
return nil, nil, nil, nil, e2
|
||||
}
|
||||
if e3 != nil {
|
||||
return nil, nil, nil, nil, e2
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "cert creation took %s\n", time.Since(start))
|
||||
return &PkiKeyCertPair{CertificatePem: string(certificateToPem(caCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(caPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(apiServerCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(apiServerPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(clientCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(clientPrivateKey))}, nil
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(clientCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(clientPrivateKey))},
|
||||
&PkiKeyCertPair{CertificatePem: string(certificateToPem(kubeConfigCertificate.Raw)), PrivateKeyPem: string(privateKeyToPem(kubeConfigPrivateKey))},
|
||||
nil
|
||||
}
|
||||
|
||||
func createCertificate(commonName string, caCertificate *x509.Certificate, caPrivateKey *rsa.PrivateKey, isServer bool, FQDN string, extraFQDNs []string, extraIPs []net.IP) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
|
@ -72,7 +108,7 @@ func createCertificate(commonName string, caCertificate *x509.Certificate, caPri
|
|||
template.IsCA = isCA
|
||||
} else if isServer {
|
||||
extraFQDNs = append(extraFQDNs, FQDN)
|
||||
extraIPs = append(extraIPs, net.ParseIP("10.3.0.1"))
|
||||
extraIPs = append(extraIPs, net.ParseIP("10.0.0.1"))
|
||||
|
||||
template.DNSNames = extraFQDNs
|
||||
template.IPAddresses = extraIPs
|
||||
|
|
Загрузка…
Ссылка в новой задаче