diff --git a/cmd/openshift-install/main.go b/cmd/openshift-install/main.go index bb1006a71ba..e447f8d95ff 100644 --- a/cmd/openshift-install/main.go +++ b/cmd/openshift-install/main.go @@ -13,6 +13,7 @@ import ( var ( installConfigCommand = kingpin.Command("install-config", "Generate the Install Config asset") ignitionConfigsCommand = kingpin.Command("ignition-configs", "Generate the Ignition Config assets") + manifestsCommand = kingpin.Command("manifests", "Generate the Kubernetes manifests") dirFlag = kingpin.Flag("dir", "assets directory").Default(".").String() logLevel = kingpin.Flag("log-level", "log level (e.g. \"debug\")").Default("warn").Enum("debug", "info", "warn", "error", "fatal", "panic") @@ -33,6 +34,10 @@ func main() { assetStock.MasterIgnition(), assetStock.WorkerIgnition(), } + case manifestsCommand.FullCommand(): + targetAssets = []asset.Asset{ + assetStock.Manifests(), + } } l, err := log.ParseLevel(*logLevel) diff --git a/pkg/asset/cluster/BUILD.bazel b/pkg/asset/cluster/BUILD.bazel new file mode 100644 index 00000000000..957399ba6f4 --- /dev/null +++ b/pkg/asset/cluster/BUILD.bazel @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "stock.go", + "tfvar.go", + ], + importpath = "github.com/openshift/installer/pkg/asset/cluster", + visibility = ["//visibility:public"], + deps = [ + "//pkg/asset:go_default_library", + "//pkg/asset/ignition:go_default_library", + "//pkg/asset/installconfig:go_default_library", + "//pkg/types/config:go_default_library", + ], +) diff --git a/pkg/asset/manifests/BUILD.bazel b/pkg/asset/manifests/BUILD.bazel new file mode 100644 index 00000000000..2e1ca87d997 --- /dev/null +++ b/pkg/asset/manifests/BUILD.bazel @@ -0,0 +1,32 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "kube-addon-operator.go", + "kube-core-operator.go", + "machine-api-operator.go", + "network-operator.go", + "operators.go", + "stock.go", + "template.go", + "utils.go", + ], + importpath = "github.com/openshift/installer/pkg/asset/manifests", + visibility = ["//visibility:public"], + deps = [ + "//pkg/asset:go_default_library", + "//pkg/asset/installconfig:go_default_library", + "//pkg/asset/kubeconfig:go_default_library", + "//pkg/asset/manifests/content:go_default_library", + "//pkg/asset/tls:go_default_library", + "//pkg/rhcos:go_default_library", + "//pkg/types:go_default_library", + "//vendor/github.com/apparentlymart/go-cidr/cidr:go_default_library", + "//vendor/github.com/coreos/tectonic-config/config/kube-addon:go_default_library", + "//vendor/github.com/coreos/tectonic-config/config/kube-core:go_default_library", + "//vendor/github.com/coreos/tectonic-config/config/tectonic-network:go_default_library", + "//vendor/github.com/ghodss/yaml:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], +) diff --git a/pkg/asset/manifests/content/01-tectonic-namespace.go b/pkg/asset/manifests/content/01-tectonic-namespace.go new file mode 100644 index 00000000000..9206b05812d --- /dev/null +++ b/pkg/asset/manifests/content/01-tectonic-namespace.go @@ -0,0 +1,14 @@ +package content + +const ( + // TectonicNamespace is the constant to represent contents of Tectonic_Namespace.yaml file + TectonicNamespace = ` +apiVersion: v1 +kind: Namespace +metadata: + name: tectonic-system # Create the namespace first. + labels: # network policy can only select by labels + name: tectonic-system + openshift.io/run-level: "1" + ` +) diff --git a/pkg/asset/manifests/content/02-ingress-namespace.go b/pkg/asset/manifests/content/02-ingress-namespace.go new file mode 100644 index 00000000000..9d557c69076 --- /dev/null +++ b/pkg/asset/manifests/content/02-ingress-namespace.go @@ -0,0 +1,17 @@ +package content + +const ( + // IngressNamespace is the constant to represent contents of Ingress_Namespace.yaml file + IngressNamespace = ` +apiVersion: v1 +kind: Namespace +metadata: + # This is the namespace used to hold the tectonic ingress controllers + name: openshift-ingress + # Give the namespace a label, so we can select for it in networkpolicy + labels: + kubernetes.io/ingress.class: tectonic + name: openshift-ingress + openshift.io/run-level: "1" + ` +) diff --git a/pkg/asset/manifests/content/03-openshift-web-console-namespace.go b/pkg/asset/manifests/content/03-openshift-web-console-namespace.go new file mode 100644 index 00000000000..a7aac7f2237 --- /dev/null +++ b/pkg/asset/manifests/content/03-openshift-web-console-namespace.go @@ -0,0 +1,15 @@ +package content + +const ( + // OpenshiftWebConsoleNamespace is the constant to represent contents of Openshift_WebConsoleNamespace.yaml file + OpenshiftWebConsoleNamespace = ` +apiVersion: v1 +kind: Namespace +metadata: + # This is the namespace used to hold the openshift console. + # They require openshift console run in this namespace. + name: openshift-web-console + labels: + name: openshift-web-console + ` +) diff --git a/pkg/asset/manifests/content/04-openshift-machine-config-operator.go b/pkg/asset/manifests/content/04-openshift-machine-config-operator.go new file mode 100644 index 00000000000..e3f721cd733 --- /dev/null +++ b/pkg/asset/manifests/content/04-openshift-machine-config-operator.go @@ -0,0 +1,14 @@ +package content + +const ( + // OpenshiftMachineConfigOperator is the constant to represent contents of Openshift_MachineConfigOperator.yaml file + OpenshiftMachineConfigOperator = ` +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-machine-config-operator + labels: + name: openshift-machine-config-operator + openshift.io/run-level: "1" + ` +) diff --git a/pkg/asset/manifests/content/05-openshift-cluster-api-namespace.go b/pkg/asset/manifests/content/05-openshift-cluster-api-namespace.go new file mode 100644 index 00000000000..6795b263a75 --- /dev/null +++ b/pkg/asset/manifests/content/05-openshift-cluster-api-namespace.go @@ -0,0 +1,15 @@ +package content + +const ( + // OpenshiftClusterAPINamespace is the constant to represent contents of Openshift_ClusterApiNamespace.yaml file + OpenshiftClusterAPINamespace = ` +apiVersion: v1 +kind: Namespace +metadata: + # This is the namespace used to hold cluster-api components. + name: openshift-cluster-api + labels: + name: openshift-cluster-api + openshift.io/run-level: "1" + ` +) diff --git a/pkg/asset/manifests/content/BUILD.bazel b/pkg/asset/manifests/content/BUILD.bazel new file mode 100644 index 00000000000..8081a25160f --- /dev/null +++ b/pkg/asset/manifests/content/BUILD.bazel @@ -0,0 +1,32 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "01-tectonic-namespace.go", + "02-ingress-namespace.go", + "03-openshift-web-console-namespace.go", + "04-openshift-machine-config-operator.go", + "05-openshift-cluster-api-namespace.go", + "app-version-kind.go", + "app-version-mao.go", + "app-version-tectonic-network.go", + "cluster-apiserver-certs.go", + "ign-config.go", + "kube-apiserver-secret.go", + "kube-cloud-config.go", + "kube-controller-manager-secret.go", + "machine-api-operator.go", + "machine-config-operator-00-config-crd.go", + "machine-config-operator-01-images-configmap.go", + "machine-config-operator-02-rbac.go", + "machine-config-operator-03-deployment.go", + "machine-config-server-tls-secret.go", + "openshift-apiserver-secret.go", + "operatorstatus-crd.go", + "pull.go", + "tectonic-network-operator.go", + ], + importpath = "github.com/openshift/installer/pkg/asset/manifests/content", + visibility = ["//visibility:public"], +) diff --git a/pkg/asset/manifests/content/app-version-kind.go b/pkg/asset/manifests/content/app-version-kind.go new file mode 100644 index 00000000000..b6dafe7acd2 --- /dev/null +++ b/pkg/asset/manifests/content/app-version-kind.go @@ -0,0 +1,17 @@ +package content + +const ( + // AppVersionKind is the constant to represent contents of App_VersionKind.yaml file + AppVersionKind = ` +apiVersion: "apiextensions.k8s.io/v1beta1" +kind: "CustomResourceDefinition" +metadata: + name: "appversions.tco.coreos.com" +spec: + group: "tco.coreos.com" + version: "v1" + names: + plural: "appversions" + kind: "AppVersion" + ` +) diff --git a/pkg/asset/manifests/content/app-version-mao.go b/pkg/asset/manifests/content/app-version-mao.go new file mode 100644 index 00000000000..4244f115db6 --- /dev/null +++ b/pkg/asset/manifests/content/app-version-mao.go @@ -0,0 +1,22 @@ +package content + +const ( + // AppVersionMao is the constant to represent contents of App_VersionMao.yaml file + AppVersionMao = ` +apiVersion: tco.coreos.com/v1 +kind: AppVersion +metadata: + name: machine-api + namespace: tectonic-system + labels: + managed-by-channel-operator: "true" +spec: + desiredVersion: + paused: false +status: + currentVersion: + paused: false +upgradereq: 1 +upgradecomp: 0 +` +) diff --git a/pkg/asset/manifests/content/app-version-tectonic-network.go b/pkg/asset/manifests/content/app-version-tectonic-network.go new file mode 100644 index 00000000000..bf5645f60f6 --- /dev/null +++ b/pkg/asset/manifests/content/app-version-tectonic-network.go @@ -0,0 +1,22 @@ +package content + +const ( + // AppVersionTectonicNetwork is the constant to represent contents of App_VersionTectonicNetwork.yaml file + AppVersionTectonicNetwork = ` +apiVersion: tco.coreos.com/v1 +kind: AppVersion +metadata: + name: tectonic-network + namespace: kube-system + labels: + managed-by-channel-operator: "true" +spec: + desiredVersion: + paused: false +status: + currentVersion: + paused: false +upgradereq: 1 +upgradecomp: 0 +` +) diff --git a/pkg/asset/manifests/content/cluster-apiserver-certs.go b/pkg/asset/manifests/content/cluster-apiserver-certs.go new file mode 100644 index 00000000000..08f945f3622 --- /dev/null +++ b/pkg/asset/manifests/content/cluster-apiserver-certs.go @@ -0,0 +1,23 @@ +package content + +import ( + "text/template" +) + +var ( + // ClusterApiserverCerts is the constant to represent contents of cluster_apiservercerts.yaml file + ClusterApiserverCerts = template.Must(template.New("cluster-apiserver-certs.yaml").Parse(` +apiVersion: v1 +kind: Secret +type: kubernetes.io/tls +metadata: + name: cluster-apiserver-certs + namespace: openshift-cluster-api + labels: + api: clusterapi + apiserver: "true" +data: + tls.crt: {{.ClusterapiCaCert}} + tls.key: {{.ClusterapiCaKey}} + `)) +) diff --git a/pkg/asset/manifests/content/ign-config.go b/pkg/asset/manifests/content/ign-config.go new file mode 100644 index 00000000000..473e31ea3c2 --- /dev/null +++ b/pkg/asset/manifests/content/ign-config.go @@ -0,0 +1,19 @@ +package content + +import ( + "text/template" +) + +var ( + // IgnConfig is the constant to represent contents of ign_config.yaml file + IgnConfig = template.Must(template.New("ign-config.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: ignition-worker + namespace: openshift-cluster-api +type: Opaque +data: + userData: {{.WorkerIgnConfig}} + `)) +) diff --git a/pkg/asset/manifests/content/kube-apiserver-secret.go b/pkg/asset/manifests/content/kube-apiserver-secret.go new file mode 100644 index 00000000000..af80c34eaeb --- /dev/null +++ b/pkg/asset/manifests/content/kube-apiserver-secret.go @@ -0,0 +1,35 @@ +package content + +import ( + "text/template" +) + +var ( + // KubeApiserverSecret is the constant to represent contents of kube_apiserversecret.yaml file + KubeApiserverSecret = template.Must(template.New("kube-apiserver-secret.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: kube-apiserver + namespace: kube-system +type: Opaque +data: + aggregator-ca.crt: {{.AggregatorCaCert}} + aggregator-ca.key: {{.AggregatorCaKey}} + apiserver.key: {{.ApiserverKey}} + apiserver.crt: {{.ApiserverCert}} + apiserver-proxy.key: {{.ApiserverProxyKey}} + apiserver-proxy.crt: {{.ApiserverProxyCert}} + service-account.pub: {{.ServiceaccountPub}} + service-account.key: {{.ServiceaccountKey}} + root-ca.crt: {{.RootCaCert}} + kube-ca.crt: {{.KubeCaCert}} + etcd-client-ca.crt: {{.EtcdCaCert}} + etcd-client.crt: {{.EtcdClientCert}} + etcd-client.key: {{.EtcdClientKey}} + oidc-ca.crt: {{.OidcCaCert}} + service-serving-ca.crt: {{.ServiceServingCaCert}} + service-serving-ca.key: {{.ServiceServingCaKey}} + kubeconfig: {{.OpenshiftLoopbackKubeconfig}} + `)) +) diff --git a/pkg/asset/manifests/content/kube-cloud-config.go b/pkg/asset/manifests/content/kube-cloud-config.go new file mode 100644 index 00000000000..0838eca5077 --- /dev/null +++ b/pkg/asset/manifests/content/kube-cloud-config.go @@ -0,0 +1,19 @@ +package content + +import ( + "text/template" +) + +var ( + // KubeCloudConfig is the constant to represent contents of kube_cloudconfig.yaml file + KubeCloudConfig = template.Must(template.New("kube-cloud-config.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: kube-cloud-cfg + namespace: kube-system +type: Opaque +data: + config: "" + `)) +) diff --git a/pkg/asset/manifests/content/kube-controller-manager-secret.go b/pkg/asset/manifests/content/kube-controller-manager-secret.go new file mode 100644 index 00000000000..b901d07205f --- /dev/null +++ b/pkg/asset/manifests/content/kube-controller-manager-secret.go @@ -0,0 +1,22 @@ +package content + +import ( + "text/template" +) + +var ( + // KubeControllerManagerSecret is the constant to represent contents of kube_controllermanagersecret.yaml file + KubeControllerManagerSecret = template.Must(template.New("kube-controller-manager-secret.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: kube-controller-manager + namespace: kube-system +type: Opaque +data: + service-account.key: {{.ServiceaccountKey}} + root-ca.crt: {{.RootCaCert}} + kube-ca.crt: {{.KubeCaCert}} + kube-ca.key: {{.KubeCaKey}} + `)) +) diff --git a/pkg/asset/manifests/content/machine-api-operator.go b/pkg/asset/manifests/content/machine-api-operator.go new file mode 100644 index 00000000000..acd7e1ddabe --- /dev/null +++ b/pkg/asset/manifests/content/machine-api-operator.go @@ -0,0 +1,61 @@ +package content + +const ( + // MachineAPIOperator is the constant to represent contents of Machine_Api_Operator.yaml file + MachineAPIOperator = ` +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: machine-api-operator + namespace: kube-system + labels: + k8s-app: machine-api-operator + managed-by-channel-operator: "true" +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: machine-api-operator + template: + metadata: + labels: + k8s-app: machine-api-operator + tectonic-app-version-name: machine-api + spec: + containers: + - name: machine-api-operator + image: quay.io/coreos/machine-api-operator:b6a04c2 + command: + - "/machine-api-operator" + resources: + limits: + cpu: 20m + memory: 50Mi + requests: + cpu: 20m + memory: 50Mi + volumeMounts: + - name: cluster-config + mountPath: /etc/mao-config + imagePullSecrets: + - name: coreos-pull-secret + nodeSelector: + node-role.kubernetes.io/master: "" + restartPolicy: Always + securityContext: + runAsNonRoot: true + runAsUser: 65534 + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + volumes: + - name: cluster-config + configMap: + name: cluster-config-v1 + items: + - key: mao-config + path: config + + ` +) diff --git a/pkg/asset/manifests/content/machine-config-operator-00-config-crd.go b/pkg/asset/manifests/content/machine-config-operator-00-config-crd.go new file mode 100644 index 00000000000..6b3749198e6 --- /dev/null +++ b/pkg/asset/manifests/content/machine-config-operator-00-config-crd.go @@ -0,0 +1,31 @@ +package content + +const ( + // MachineConfigOperator00ConfigCrd is the constant to represent contents of Machine_ConfigOperator00ConfigCrd.yaml file + MachineConfigOperator00ConfigCrd = ` +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: mcoconfigs.machineconfiguration.openshift.io +spec: + # group name to use for REST API: /apis// + group: machineconfiguration.openshift.io + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: mcoconfigs + # singular name to be used as an alias on the CLI and for display + singular: mcoconfig + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: MCOConfig + ` +) diff --git a/pkg/asset/manifests/content/machine-config-operator-01-images-configmap.go b/pkg/asset/manifests/content/machine-config-operator-01-images-configmap.go new file mode 100644 index 00000000000..4e02244d46c --- /dev/null +++ b/pkg/asset/manifests/content/machine-config-operator-01-images-configmap.go @@ -0,0 +1,14 @@ +package content + +const ( + // MachineConfigOperator01ImagesConfigmap is the constant to represent contents of Machine_ConfigOperator01ImagesConfigmap.yaml file + MachineConfigOperator01ImagesConfigmap = ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: machine-config-operator-images + namespace: openshift-machine-config-operator +data: + images.json: '{"machineConfigController": "docker.io/openshift/origin-machine-config-controller:v4.0.0", "machineConfigDaemon": "docker.io/openshift/origin-machine-config-daemon:v4.0.0", "machineConfigServer": "docker.io/openshift/origin-machine-config-server:v4.0.0"}' + ` +) diff --git a/pkg/asset/manifests/content/machine-config-operator-02-rbac.go b/pkg/asset/manifests/content/machine-config-operator-02-rbac.go new file mode 100644 index 00000000000..ed406076baf --- /dev/null +++ b/pkg/asset/manifests/content/machine-config-operator-02-rbac.go @@ -0,0 +1,20 @@ +package content + +const ( + // MachineConfigOperator02Rbac is the constant to represent contents of manifest file machine-config-operator-02-rbac.yaml + MachineConfigOperator02Rbac = ` +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: default-account-openshift-machine-config-operator +subjects: +- kind: ServiceAccount + name: default + namespace: openshift-machine-config-operator +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io + ` +) diff --git a/pkg/asset/manifests/content/machine-config-operator-03-deployment.go b/pkg/asset/manifests/content/machine-config-operator-03-deployment.go new file mode 100644 index 00000000000..4893531d315 --- /dev/null +++ b/pkg/asset/manifests/content/machine-config-operator-03-deployment.go @@ -0,0 +1,68 @@ +package content + +import ( + "text/template" +) + +var ( + // MachineConfigOperator03Deployment is the constant to represent contents of machine_configoperator03deployment.yaml file + MachineConfigOperator03Deployment = template.Must(template.New("machine-config-operator-03-deployment.yaml").Parse(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: machine-config-operator + namespace: openshift-machine-config-operator + labels: + k8s-app: machine-config-operator +spec: + replicas: 1 + selector: + matchLabels: + k8s-app: machine-config-operator + template: + metadata: + labels: + k8s-app: machine-config-operator + spec: + containers: + - name: machine-config-operator + image: {{.MachineConfigOperatorImage}} + args: + - "start" + - "--images-json=/etc/mco/images/images.json" + resources: + limits: + cpu: 20m + memory: 50Mi + requests: + cpu: 20m + memory: 50Mi + volumeMounts: + - name: root-ca + mountPath: /etc/ssl/kubernetes/ca.crt + - name: etcd-ca + mountPath: /etc/ssl/etcd/ca.crt + - name: images + mountPath: /etc/mco/images + nodeSelector: + node-role.kubernetes.io/master: "" + restartPolicy: Always + securityContext: + runAsNonRoot: true + runAsUser: 65534 + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + volumes: + - name: images + configMap: + name: machine-config-operator-images + - name: etcd-ca + hostPath: + path: /etc/ssl/etcd/ca.crt + - name: root-ca + hostPath: + path: /etc/kubernetes/ca.crt + `)) +) diff --git a/pkg/asset/manifests/content/machine-config-server-tls-secret.go b/pkg/asset/manifests/content/machine-config-server-tls-secret.go new file mode 100644 index 00000000000..838cd1b6ae9 --- /dev/null +++ b/pkg/asset/manifests/content/machine-config-server-tls-secret.go @@ -0,0 +1,20 @@ +package content + +import ( + "text/template" +) + +var ( + // MachineConfigServerTLSSecret is the constant to represent contents of machine_configservertlssecret.yaml file + MachineConfigServerTLSSecret = template.Must(template.New("machine-config-server-tls-secret.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: machine-config-server-tls + namespace: openshift-machine-config-operator +type: Opaque +data: + tls.crt: {{.McsTLSCert}} + tls.key: {{.McsTLSKey}} + `)) +) diff --git a/pkg/asset/manifests/content/openshift-apiserver-secret.go b/pkg/asset/manifests/content/openshift-apiserver-secret.go new file mode 100644 index 00000000000..fe6c6c2da43 --- /dev/null +++ b/pkg/asset/manifests/content/openshift-apiserver-secret.go @@ -0,0 +1,37 @@ +package content + +import ( + "text/template" +) + +var ( + // OpenshiftApiserverSecret is the constant to represent contents of openshift_apiserversecret.yaml file + OpenshiftApiserverSecret = template.Must(template.New("openshift-apiserver-secret.yaml").Parse(` +apiVersion: v1 +kind: Secret +metadata: + name: openshift-apiserver + namespace: kube-system +type: Opaque +data: + aggregator-ca.crt: {{.AggregatorCaCert}} + aggregator-ca.key: {{.AggregatorCaKey}} + apiserver.key: {{.ApiserverKey}} + apiserver.crt: {{.ApiserverCert}} + openshift-apiserver.key: {{.OpenshiftApiserverKey}} + openshift-apiserver.crt: {{.OpenshiftApiserverCert}} + apiserver-proxy.key: {{.ApiserverProxyKey}} + apiserver-proxy.crt: {{.ApiserverProxyCert}} + service-account.pub: {{.ServiceaccountPub}} + service-account.key: {{.ServiceaccountKey}} + root-ca.crt: {{.RootCaCert}} + kube-ca.crt: {{.KubeCaCert}} + etcd-client-ca.crt: {{.EtcdCaCert}} + etcd-client.crt: {{.EtcdClientCert}} + etcd-client.key: {{.EtcdClientKey}} + oidc-ca.crt: {{.OidcCaCert}} + service-serving-ca.crt: {{.ServiceServingCaCert}} + service-serving-ca.key: {{.ServiceServingCaKey}} + kubeconfig: {{.OpenshiftLoopbackKubeconfig}} + `)) +) diff --git a/pkg/asset/manifests/content/operatorstatus-crd.go b/pkg/asset/manifests/content/operatorstatus-crd.go new file mode 100644 index 00000000000..e3e3eac2776 --- /dev/null +++ b/pkg/asset/manifests/content/operatorstatus-crd.go @@ -0,0 +1,31 @@ +package content + +const ( + // OperatorstatusCrd is the constant to represent contents of Operatorstatus_Crd.yaml file + OperatorstatusCrd = ` +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + # name must match the spec fields below, and be in the form: . + name: operatorstatuses.clusterversion.openshift.io +spec: + # group name to use for REST API: /apis// + group: clusterversion.openshift.io + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + # Each version can be enabled/disabled by Served flag. + served: true + # One and only one version must be marked as the storage version. + storage: true + # either Namespaced or Cluster + scope: Cluster + names: + # plural name to be used in the URL: /apis/// + plural: operatorstatuses + # singular name to be used as an alias on the CLI and for display + singular: operatorstatus + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: OperatorStatus + ` +) diff --git a/pkg/asset/manifests/content/pull.go b/pkg/asset/manifests/content/pull.go new file mode 100644 index 00000000000..95c191672db --- /dev/null +++ b/pkg/asset/manifests/content/pull.go @@ -0,0 +1,23 @@ +package content + +import ( + "text/template" +) + +var ( + // Pull is the constant to represent contents of pull.yaml file + Pull = template.Must(template.New("pull.json").Parse(` +{ + "apiVersion": "v1", + "kind": "Secret", + "type": "kubernetes.io/dockerconfigjson", + "metadata": { + "namespace": "kube-system", + "name": "coreos-pull-secret" + }, + "data": { + ".dockerconfigjson": "{{.PullSecret}}" + } +} +`)) +) diff --git a/pkg/asset/manifests/content/tectonic-network-operator.go b/pkg/asset/manifests/content/tectonic-network-operator.go new file mode 100644 index 00000000000..86c89a133b8 --- /dev/null +++ b/pkg/asset/manifests/content/tectonic-network-operator.go @@ -0,0 +1,70 @@ +package content + +import ( + "text/template" +) + +var ( + // TectonicNetworkOperator represents the template variable for tectonic-network-operator.yaml file + TectonicNetworkOperator = template.Must(template.New("tectonic-network-operator.yaml").Parse(` +apiVersion: apps/v1beta2 +kind: DaemonSet +metadata: + name: tectonic-network-operator + namespace: kube-system + labels: + k8s-app: tectonic-network-operator + managed-by-channel-operator: "true" +spec: + selector: + matchLabels: + k8s-app: tectonic-network-operator + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + k8s-app: tectonic-network-operator + tectonic-app-version-name: tectonic-network + spec: + containers: + - name: tectonic-network-operator + image: {{.TectonicNetworkOperatorImage}} + resources: + limits: + cpu: 20m + memory: 50Mi + requests: + cpu: 20m + memory: 50Mi + volumeMounts: + - name: cluster-config + mountPath: /etc/cluster-config + hostNetwork: true + restartPolicy: Always + imagePullSecrets: + - name: coreos-pull-secret + securityContext: + runAsNonRoot: true + runAsUser: 65534 + volumes: + - name: cluster-config + configMap: + name: cluster-config-v1 + items: + - key: network-config + path: network-config + nodeSelector: + node-role.kubernetes.io/master: "" + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + `)) +) diff --git a/pkg/asset/manifests/kube-addon-operator.go b/pkg/asset/manifests/kube-addon-operator.go new file mode 100644 index 00000000000..196d1e0699d --- /dev/null +++ b/pkg/asset/manifests/kube-addon-operator.go @@ -0,0 +1,103 @@ +package manifests + +import ( + "crypto/rand" + "encoding/base64" + "errors" + "fmt" + "path/filepath" + + "github.com/ghodss/yaml" + + kubeaddon "github.com/coreos/tectonic-config/config/kube-addon" + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// kubeAddonOperator generates the network-operator-*.yml files +type kubeAddonOperator struct { + installConfigAsset asset.Asset + installConfig *types.InstallConfig + directory string +} + +var _ asset.Asset = (*kubeAddonOperator)(nil) + +// Name returns a human friendly name for the operator +func (kao *kubeAddonOperator) Name() string { + return "Kube Addon Operator" +} + +// Dependencies returns all of the dependencies directly needed by an +// kubeAddonOperator asset. +func (kao *kubeAddonOperator) Dependencies() []asset.Asset { + return []asset.Asset{ + kao.installConfigAsset, + } +} + +// Generate generates the network-operator-config.yml and network-operator-manifest.yml files +func (kao *kubeAddonOperator) Generate(dependencies map[asset.Asset]*asset.State) (*asset.State, error) { + ic, err := installconfig.GetInstallConfig(kao.installConfigAsset, dependencies) + if err != nil { + return nil, err + } + kao.installConfig = ic + + // installconfig is ready, we can create the addon config from it now + addonConfig, err := kao.addonConfig() + if err != nil { + return nil, err + } + + state := &asset.State{ + Contents: []asset.Content{ + { + Name: filepath.Join(kao.directory, "kube-addon-operator-config.yml"), + Data: addonConfig, + }, + }, + } + return state, nil +} + +func (kao *kubeAddonOperator) addonConfig() ([]byte, error) { + addonConfig := kubeaddon.OperatorConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kubeaddon.APIVersion, + Kind: kubeaddon.Kind, + }, + } + addonConfig.CloudProvider = tectonicCloudProvider(kao.installConfig.Platform) + addonConfig.ClusterConfig.APIServerURL = kao.getAPIServerURL() + registrySecret, err := generateRandomID(16) + if err != nil { + return nil, err + } + addonConfig.RegistryHTTPSecret = registrySecret + return yaml.Marshal(addonConfig) +} + +func (kao *kubeAddonOperator) getAPIServerURL() string { + return fmt.Sprintf("https://%s-api.%s:6443", kao.installConfig.Name, kao.installConfig.BaseDomain) +} + +// generateRandomID reproduce tf random_id behaviour +// TODO: re-evaluate solution +func generateRandomID(byteLength int) (string, error) { + bytes := make([]byte, byteLength) + + n, err := rand.Reader.Read(bytes) + if n != byteLength { + return "", errors.New("generated insufficient random bytes") + } + if err != nil { + return "", err + } + + b64Str := base64.RawURLEncoding.EncodeToString(bytes) + + return b64Str, nil +} diff --git a/pkg/asset/manifests/kube-core-operator.go b/pkg/asset/manifests/kube-core-operator.go new file mode 100644 index 00000000000..9aa07bb6b1d --- /dev/null +++ b/pkg/asset/manifests/kube-core-operator.go @@ -0,0 +1,134 @@ +package manifests + +import ( + "fmt" + "net" + "path/filepath" + + "github.com/ghodss/yaml" + + "github.com/apparentlymart/go-cidr/cidr" + kubecore "github.com/coreos/tectonic-config/config/kube-core" + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + authConfigOIDCClientID = "tectonic-kubectl" + authConfigOIDCGroupsClaim = "groups" + authConfigOIDCUsernameClaim = "email" + networkConfigAdvertiseAddress = "0.0.0.0" +) + +// kubeCoreOperator generates the kube-core-operator.yaml files +type kubeCoreOperator struct { + installConfigAsset asset.Asset + installConfig *types.InstallConfig + directory string +} + +var _ asset.Asset = (*kubeCoreOperator)(nil) + +// Name returns a human friendly name for the operator +func (kco *kubeCoreOperator) Name() string { + return "Kube Core Operator" +} + +// Dependencies returns all of the dependencies directly needed by an +// kubeCoreOperator asset. +func (kco *kubeCoreOperator) Dependencies() []asset.Asset { + return []asset.Asset{ + kco.installConfigAsset, + } +} + +// Generate generates the kube-core-operator-config.yml files +func (kco *kubeCoreOperator) Generate(dependencies map[asset.Asset]*asset.State) (*asset.State, error) { + ic, err := installconfig.GetInstallConfig(kco.installConfigAsset, dependencies) + if err != nil { + return nil, err + } + kco.installConfig = ic + + // installconfig is ready, we can create the core config from it now + coreConfig, err := kco.coreConfig() + if err != nil { + return nil, err + } + + data, err := yaml.Marshal(coreConfig) + if err != nil { + return nil, fmt.Errorf("failed to marshal core config: %v", err) + } + state := &asset.State{ + Contents: []asset.Content{ + { + Name: filepath.Join(kco.directory, "kube-core-operator-config.yml"), + Data: data, + }, + }, + } + return state, nil +} + +func (kco *kubeCoreOperator) coreConfig() (*kubecore.OperatorConfig, error) { + coreConfig := kubecore.OperatorConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: kubecore.APIVersion, + Kind: kubecore.Kind, + }, + } + coreConfig.ClusterConfig.APIServerURL = kco.getAPIServerURL() + coreConfig.AuthConfig.OIDCClientID = authConfigOIDCClientID + coreConfig.AuthConfig.OIDCIssuerURL = kco.getOicdIssuerURL() + coreConfig.AuthConfig.OIDCGroupsClaim = authConfigOIDCGroupsClaim + coreConfig.AuthConfig.OIDCUsernameClaim = authConfigOIDCUsernameClaim + + svcCidr := kco.installConfig.Networking.ServiceCIDR + ip, err := cidr.Host(&net.IPNet{IP: svcCidr.IP, Mask: svcCidr.Mask}, 10) + if err != nil { + return nil, err + } + coreConfig.DNSConfig.ClusterIP = ip.String() + + coreConfig.CloudProviderConfig.CloudConfigPath = "" + coreConfig.CloudProviderConfig.CloudProviderProfile = k8sCloudProvider(kco.installConfig.Platform) + + coreConfig.RoutingConfig.Subdomain = kco.getBaseAddress() + + coreConfig.NetworkConfig.ClusterCIDR = kco.installConfig.Networking.PodCIDR.String() + coreConfig.NetworkConfig.ServiceCIDR = kco.installConfig.Networking.ServiceCIDR.String() + coreConfig.NetworkConfig.AdvertiseAddress = networkConfigAdvertiseAddress + coreConfig.NetworkConfig.EtcdServers = kco.getEtcdServersURLs() + + return &coreConfig, nil +} + +func (kco *kubeCoreOperator) getAPIServerURL() string { + return fmt.Sprintf("https://%s-api.%s:6443", kco.installConfig.Name, kco.installConfig.BaseDomain) +} + +func (kco *kubeCoreOperator) getEtcdServersURLs() string { + return fmt.Sprintf("https://%s-etcd.%s:2379", kco.installConfig.Name, kco.installConfig.BaseDomain) +} + +func (kco *kubeCoreOperator) getOicdIssuerURL() string { + return fmt.Sprintf("https://%s.%s/identity", kco.installConfig.Name, kco.installConfig.BaseDomain) +} + +func (kco *kubeCoreOperator) getBaseAddress() string { + return fmt.Sprintf("%s.%s", kco.installConfig.Name, kco.installConfig.BaseDomain) +} + +// Converts a platform to the cloudProvider that k8s understands +func k8sCloudProvider(platform types.Platform) string { + if platform.AWS != nil { + return "aws" + } + if platform.Libvirt != nil { + //return "libvirt" + } + return "" +} diff --git a/pkg/asset/manifests/machine-api-operator.go b/pkg/asset/manifests/machine-api-operator.go new file mode 100644 index 00000000000..a1f61ee14f9 --- /dev/null +++ b/pkg/asset/manifests/machine-api-operator.go @@ -0,0 +1,140 @@ +package manifests + +import ( + "fmt" + "path/filepath" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/rhcos" + "github.com/openshift/installer/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + maoTargetNamespace = "openshift-cluster-api" + // DefaultChannel is the default RHCOS channel for the cluster. + DefaultChannel = "tested" +) + +// machineAPIOperator generates the network-operator-*.yml files +type machineAPIOperator struct { + installConfigAsset asset.Asset + installConfig *types.InstallConfig + aggregatorCA asset.Asset + directory string +} + +var _ asset.Asset = (*machineAPIOperator)(nil) + +// maoOperatorConfig contains configuration for mao managed stack +// TODO(enxebre): move up to github.com/coreos/tectonic-config (to install-config? /rchopra) +type maoOperatorConfig struct { + metav1.TypeMeta `json:",inline"` + TargetNamespace string `json:"targetNamespace"` + APIServiceCA string `json:"apiServiceCA"` + Provider string `json:"provider"` + AWS *awsConfig `json:"aws"` + Libvirt *libvirtConfig `json:"libvirt"` +} + +type libvirtConfig struct { + ClusterName string `json:"clusterName"` + URI string `json:"uri"` + NetworkName string `json:"networkName"` + IPRange string `json:"iprange"` + Replicas int `json:"replicas"` +} + +type awsConfig struct { + ClusterName string `json:"clusterName"` + ClusterID string `json:"clusterID"` + Region string `json:"region"` + AvailabilityZone string `json:"availabilityZone"` + Image string `json:"image"` + Replicas int `json:"replicas"` +} + +// Name returns a human friendly name for the operator +func (mao *machineAPIOperator) Name() string { + return "Machine API Operator" +} + +// Dependencies returns all of the dependencies directly needed by an +// machineAPIOperator asset. +func (mao *machineAPIOperator) Dependencies() []asset.Asset { + return []asset.Asset{ + mao.installConfigAsset, + mao.aggregatorCA, + } +} + +// Generate generates the network-operator-config.yml and network-operator-manifest.yml files +func (mao *machineAPIOperator) Generate(dependencies map[asset.Asset]*asset.State) (*asset.State, error) { + ic, err := installconfig.GetInstallConfig(mao.installConfigAsset, dependencies) + if err != nil { + return nil, err + } + mao.installConfig = ic + + // installconfig is ready, we can create the mao config from it now + maoConfig, err := mao.maoConfig(dependencies) + if err != nil { + return nil, err + } + + state := &asset.State{ + Contents: []asset.Content{ + { + Name: filepath.Join(mao.directory, "machine-api-operator-config.yml"), + Data: []byte(maoConfig), + }, + }, + } + return state, nil +} + +func (mao *machineAPIOperator) maoConfig(dependencies map[asset.Asset]*asset.State) (string, error) { + cfg := maoOperatorConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "machineAPIOperatorConfig", + }, + + TargetNamespace: maoTargetNamespace, + } + + ca := dependencies[mao.aggregatorCA].Contents[certIndex].Data + cfg.APIServiceCA = string(ca) + cfg.Provider = tectonicCloudProvider(mao.installConfig.Platform) + + if mao.installConfig.Platform.AWS != nil { + var ami string + + ami, err := rhcos.AMI(DefaultChannel, mao.installConfig.Platform.AWS.Region) + if err != nil { + return "", fmt.Errorf("failed to lookup RHCOS AMI: %v", err) + } + + cfg.AWS = &awsConfig{ + ClusterName: mao.installConfig.Name, + ClusterID: mao.installConfig.ClusterID, + Region: mao.installConfig.Platform.AWS.Region, + AvailabilityZone: "", + Image: ami, + Replicas: int(*mao.installConfig.Machines[1].Replicas), + } + } else if mao.installConfig.Platform.Libvirt != nil { + cfg.Libvirt = &libvirtConfig{ + ClusterName: mao.installConfig.Name, + URI: mao.installConfig.Platform.Libvirt.URI, + NetworkName: mao.installConfig.Platform.Libvirt.Network.Name, + IPRange: mao.installConfig.Platform.Libvirt.Network.IPRange, + Replicas: int(*mao.installConfig.Machines[1].Replicas), + } + } else { + return "", fmt.Errorf("unknown provider for machine-api-operator") + } + + return marshalYAML(cfg) +} diff --git a/pkg/asset/manifests/network-operator.go b/pkg/asset/manifests/network-operator.go new file mode 100644 index 00000000000..09778a5712f --- /dev/null +++ b/pkg/asset/manifests/network-operator.go @@ -0,0 +1,92 @@ +package manifests + +import ( + "path/filepath" + + "github.com/ghodss/yaml" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/types" + + tectonicnetwork "github.com/coreos/tectonic-config/config/tectonic-network" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + defaultMTU = "1450" +) + +// networkOperator generates the network-operator-*.yml files +type networkOperator struct { + installConfigAsset asset.Asset + installConfig *types.InstallConfig + directory string +} + +var _ asset.Asset = (*networkOperator)(nil) + +// Name returns a human friendly name for the operator +func (no *networkOperator) Name() string { + return "Network Operator" +} + +// Dependencies returns all of the dependencies directly needed by an +// networkOperator asset. +func (no *networkOperator) Dependencies() []asset.Asset { + return []asset.Asset{ + no.installConfigAsset, + } +} + +// Generate generates the network-operator-config.yml and network-operator-manifest.yml files +func (no *networkOperator) Generate(dependencies map[asset.Asset]*asset.State) (*asset.State, error) { + ic, err := installconfig.GetInstallConfig(no.installConfigAsset, dependencies) + if err != nil { + return nil, err + } + no.installConfig = ic + + // installconfig is ready, we can create the core config from it now + netConfig, err := no.netConfig() + if err != nil { + return nil, err + } + + netManifest, err := no.manifest() + if err != nil { + return nil, err + } + state := &asset.State{ + Contents: []asset.Content{ + { + Name: filepath.Join(no.directory, "network-operator-config.yml"), + Data: netConfig, + }, + { + Name: filepath.Join(no.directory, "network-operator-manifests.yml"), + Data: netManifest, + }, + }, + } + return state, nil +} + +func (no *networkOperator) netConfig() ([]byte, error) { + networkConfig := tectonicnetwork.OperatorConfig{ + TypeMeta: metav1.TypeMeta{ + APIVersion: tectonicnetwork.APIVersion, + Kind: tectonicnetwork.Kind, + }, + } + + networkConfig.PodCIDR = no.installConfig.Networking.PodCIDR.String() + networkConfig.CalicoConfig.MTU = defaultMTU + networkConfig.NetworkProfile = tectonicnetwork.NetworkType(no.installConfig.Networking.Type) + + return yaml.Marshal(networkConfig) +} + +func (no *networkOperator) manifest() ([]byte, error) { + return []byte(""), nil +} diff --git a/pkg/asset/manifests/operators.go b/pkg/asset/manifests/operators.go new file mode 100644 index 00000000000..a8ca0d5e613 --- /dev/null +++ b/pkg/asset/manifests/operators.go @@ -0,0 +1,243 @@ +// Package manifests deals with creating manifests for all manifests to be installed for the cluster +package manifests + +import ( + "bytes" + "path/filepath" + "text/template" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/asset/manifests/content" +) + +const ( + keyIndex = 0 + certIndex = 1 +) + +// manifests generates the dependent operator config.yaml files +type manifests struct { + assetStock Stock + installConfig asset.Asset + directory string + rootCA asset.Asset + etcdCA asset.Asset + ingressCertKey asset.Asset + kubeCA asset.Asset + aggregatorCA asset.Asset + serviceServingCA asset.Asset + clusterAPIServerCertKey asset.Asset + etcdClientCertKey asset.Asset + apiServerCertKey asset.Asset + openshiftAPIServerCertKey asset.Asset + apiServerProxyCertKey asset.Asset + adminCertKey asset.Asset + kubeletCertKey asset.Asset + tncCertKey asset.Asset + serviceAccountKeyPair asset.Asset + kubeconfig asset.Asset +} + +var _ asset.Asset = (*manifests)(nil) + +type genericData map[string]string + +// Name returns a human friendly name for the operator +func (o *manifests) Name() string { + return "Common Manifests" +} + +// Dependencies returns all of the dependencies directly needed by an +// manifests asset. +func (o *manifests) Dependencies() []asset.Asset { + return []asset.Asset{ + o.installConfig, + o.assetStock.KubeCoreOperator(), + o.assetStock.NetworkOperator(), + o.assetStock.KubeAddonOperator(), + o.assetStock.Mao(), + o.rootCA, + o.etcdCA, + o.ingressCertKey, + o.kubeCA, + o.aggregatorCA, + o.serviceServingCA, + o.clusterAPIServerCertKey, + o.etcdClientCertKey, + o.apiServerCertKey, + o.openshiftAPIServerCertKey, + o.apiServerProxyCertKey, + o.adminCertKey, + o.kubeletCertKey, + o.tncCertKey, + o.serviceAccountKeyPair, + o.kubeconfig, + } +} + +// Generate generates the respective operator config.yml files +func (o *manifests) Generate(dependencies map[asset.Asset]*asset.State) (*asset.State, error) { + //cvo := dependencies[o.assetStock.ClusterVersionOperator()].Contents[0] + kco := dependencies[o.assetStock.KubeCoreOperator()].Contents[0] + no := dependencies[o.assetStock.NetworkOperator()].Contents[0] + //ingress := dependencies[o.assetStock.IngressOperator()].Contents[0] + addon := dependencies[o.assetStock.KubeAddonOperator()].Contents[0] + mao := dependencies[o.assetStock.Mao()].Contents[0] + installConfig := dependencies[o.installConfig].Contents[0] + + // kco+no+mao go to kube-system config map + kubeSys, err := configMap("kube-system", "cluster-config-v1", genericData{ + "kco-config": string(kco.Data), + "network-config": string(no.Data), + "install-config": string(installConfig.Data), + "mao-config": string(mao.Data), + }) + if err != nil { + return nil, err + } + + // addon goes to openshift system + tectonicSys, err := configMap("tectonic-system", "cluster-config-v1", genericData{ + "addon-config": string(addon.Data), + }) + if err != nil { + return nil, err + } + + templateAssetContents := o.generateTemplateAssets(dependencies) + + state := &asset.State{ + Contents: []asset.Content{ + { + Name: filepath.Join(o.directory, "cluster-config.yaml"), + Data: []byte(kubeSys), + }, + { + Name: filepath.Join(o.directory, "tectonic-config.yaml"), + Data: []byte(tectonicSys), + }, + { + Name: filepath.Join(o.directory, "mao-config.yaml"), + Data: mao.Data, + }, + }, + } + state.Contents = append(state.Contents, templateAssetContents...) + return state, nil +} + +func (o *manifests) generateTemplateAssets(dependencies map[asset.Asset]*asset.State) []asset.Content { + ic, err := installconfig.GetInstallConfig(o.installConfig, dependencies) + if err != nil { + return nil + } + manifestDir := filepath.Join(o.directory, "manifests") + assetContents := make([]asset.Content, 0) + templateData := &templateData{ + AggregatorCaCert: string(dependencies[o.aggregatorCA].Contents[certIndex].Data), + AggregatorCaKey: string(dependencies[o.aggregatorCA].Contents[keyIndex].Data), + ApiserverCert: string(dependencies[o.apiServerCertKey].Contents[certIndex].Data), + ApiserverKey: string(dependencies[o.apiServerCertKey].Contents[keyIndex].Data), + ApiserverProxyCert: string(dependencies[o.apiServerProxyCertKey].Contents[certIndex].Data), + ApiserverProxyKey: string(dependencies[o.apiServerProxyCertKey].Contents[keyIndex].Data), + Base64encodeCloudProviderConfig: "", // FIXME + ClusterapiCaCert: string(dependencies[o.clusterAPIServerCertKey].Contents[certIndex].Data), + ClusterapiCaKey: string(dependencies[o.clusterAPIServerCertKey].Contents[keyIndex].Data), + EtcdCaCert: string(dependencies[o.etcdCA].Contents[certIndex].Data), + EtcdClientCert: string(dependencies[o.etcdClientCertKey].Contents[certIndex].Data), + EtcdClientKey: string(dependencies[o.etcdClientCertKey].Contents[keyIndex].Data), + KubeCaCert: string(dependencies[o.kubeCA].Contents[certIndex].Data), + KubeCaKey: string(dependencies[o.kubeCA].Contents[keyIndex].Data), + MachineConfigOperatorImage: "docker.io/openshift/origin-machine-config-operator:v4.0.0", + McsTLSCert: string(dependencies[o.adminCertKey].Contents[certIndex].Data), + McsTLSKey: string(dependencies[o.adminCertKey].Contents[keyIndex].Data), + OidcCaCert: string(dependencies[o.kubeCA].Contents[certIndex].Data), + OpenshiftApiserverCert: string(dependencies[o.openshiftAPIServerCertKey].Contents[certIndex].Data), + OpenshiftApiserverKey: string(dependencies[o.openshiftAPIServerCertKey].Contents[keyIndex].Data), + OpenshiftLoopbackKubeconfig: string(dependencies[o.kubeconfig].Contents[0].Data), + PullSecret: string(ic.PullSecret), + RootCaCert: string(dependencies[o.rootCA].Contents[certIndex].Data), + ServiceaccountKey: string(dependencies[o.serviceAccountKeyPair].Contents[keyIndex].Data), + ServiceaccountPub: string(dependencies[o.serviceAccountKeyPair].Contents[certIndex].Data), + ServiceServingCaCert: string(dependencies[o.serviceServingCA].Contents[certIndex].Data), + ServiceServingCaKey: string(dependencies[o.serviceServingCA].Contents[keyIndex].Data), + TectonicNetworkOperatorImage: "quay.io/coreos/tectonic-network-operator-dev:3b6952f5a1ba89bb32dd0630faddeaf2779c9a85", + WorkerIgnConfig: "", // FIXME: this means that depending on ignition assets (risk of cyclical dependencies) + } + + // belongs to machine api operator + data := applyTemplateData(content.ClusterApiserverCerts, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "cluster-apiserver-certs.yaml"), Data: []byte(data)}) + + // machine api operator + data = applyTemplateData(content.IgnConfig, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "ign-config.yaml"), Data: []byte(data)}) + + // kco + data = applyTemplateData(content.KubeApiserverSecret, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "kube-apiserver-secret.yaml"), Data: []byte(data)}) + + // kco + data = applyTemplateData(content.KubeCloudConfig, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "kube-cloud-config.yaml"), Data: []byte(data)}) + + // kco + data = applyTemplateData(content.KubeControllerManagerSecret, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "kube-controller-manager-secret.yaml"), Data: []byte(data)}) + + // mco + data = applyTemplateData(content.MachineConfigOperator03Deployment, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-config-operator-03-deployment.yaml"), Data: []byte(data)}) + + // mco + data = applyTemplateData(content.MachineConfigServerTLSSecret, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-config-server-tls-secret.yaml"), Data: []byte(data)}) + + // kube core + data = applyTemplateData(content.OpenshiftApiserverSecret, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "openshift-apiserver-secret.yaml"), Data: []byte(data)}) + + // common + data = applyTemplateData(content.Pull, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "pull.json"), Data: []byte(data)}) + + // network operator + data = applyTemplateData(content.TectonicNetworkOperator, templateData) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "tectonic-network-operator.yaml"), Data: []byte(data)}) + + // common + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "01-tectonic-namespace.yaml"), Data: []byte(content.TectonicNamespace)}) + // ingress + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "02-ingress-namespace.yaml"), Data: []byte(content.IngressNamespace)}) + // kao + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "03-openshift-web-console-namespace.yaml"), Data: []byte(content.OpenshiftWebConsoleNamespace)}) + // mco + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "openshift-machine-config-operator.yaml"), Data: []byte(content.OpenshiftMachineConfigOperator)}) + // machine api operator + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "openshift-cluster-api-namespace.yaml"), Data: []byte(content.OpenshiftClusterAPINamespace)}) + // common + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "app-version-kind.yaml"), Data: []byte(content.AppVersionKind)}) + // cmacine api operator + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "app-version-mao.yaml"), Data: []byte(content.AppVersionMao)}) + // network + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "app-version-tectonic-network.yaml"), Data: []byte(content.AppVersionTectonicNetwork)}) + // machine api operator + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-api-operator.yaml"), Data: []byte(content.MachineAPIOperator)}) + + // mco + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-config-operator-00-config-crd.yaml"), Data: []byte(content.MachineConfigOperator00ConfigCrd)}) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-config-operator-01-images-configmap.yaml"), Data: []byte(content.MachineConfigOperator01ImagesConfigmap)}) + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "machine-config-operator-02-rbac.yaml"), Data: []byte(content.MachineConfigOperator02Rbac)}) + // common/cvo + assetContents = append(assetContents, asset.Content{Name: filepath.Join(manifestDir, "operatorstatus-crd.yaml"), Data: []byte(content.OperatorstatusCrd)}) + return assetContents +} + +func applyTemplateData(template *template.Template, templateData interface{}) string { + buf := &bytes.Buffer{} + if err := template.Execute(buf, templateData); err != nil { + panic(err) + } + return buf.String() +} diff --git a/pkg/asset/manifests/stock.go b/pkg/asset/manifests/stock.go new file mode 100644 index 00000000000..8d600e70b9d --- /dev/null +++ b/pkg/asset/manifests/stock.go @@ -0,0 +1,100 @@ +package manifests + +import ( + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/asset/kubeconfig" + "github.com/openshift/installer/pkg/asset/tls" +) + +// Stock is the stock of operator assets that can be generated. +type Stock interface { + // ClusterVersionOperator returns the cvo asset object + ClusterVersionOperator() asset.Asset + + // KubeCoreOperator returns the kco asset object + KubeCoreOperator() asset.Asset + + // NetworkOperator returns the network operator asset object + NetworkOperator() asset.Asset + + // KubeAddonOperator returns the addon asset object + KubeAddonOperator() asset.Asset + + // Mao returns the machine api operator asset object + Mao() asset.Asset +} + +// StockImpl implements the Stock interface for manifests +type StockImpl struct { + manifests asset.Asset + clusterVersionOperator asset.Asset + kubeCoreOperator asset.Asset + networkOperator asset.Asset + addonOperator asset.Asset + mao asset.Asset +} + +var _ Stock = (*StockImpl)(nil) + +// EstablishStock establishes the stock of assets in the specified directory. +func (s *StockImpl) EstablishStock(rootDir string, stock installconfig.Stock, tlsStock tls.Stock, kubeConfigStock kubeconfig.Stock) { + s.manifests = &manifests{ + assetStock: s, + installConfig: stock.InstallConfig(), + directory: rootDir, + rootCA: tlsStock.RootCA(), + etcdCA: tlsStock.EtcdCA(), + ingressCertKey: tlsStock.IngressCertKey(), + kubeCA: tlsStock.KubeCA(), + aggregatorCA: tlsStock.AggregatorCA(), + serviceServingCA: tlsStock.ServiceServingCA(), + clusterAPIServerCertKey: tlsStock.ClusterAPIServerCertKey(), + etcdClientCertKey: tlsStock.EtcdClientCertKey(), + apiServerCertKey: tlsStock.APIServerCertKey(), + openshiftAPIServerCertKey: tlsStock.OpenshiftAPIServerCertKey(), + apiServerProxyCertKey: tlsStock.APIServerProxyCertKey(), + adminCertKey: tlsStock.AdminCertKey(), + kubeletCertKey: tlsStock.KubeletCertKey(), + tncCertKey: tlsStock.TNCCertKey(), + serviceAccountKeyPair: tlsStock.ServiceAccountKeyPair(), + kubeconfig: kubeConfigStock.KubeconfigAdmin(), + } + s.kubeCoreOperator = &kubeCoreOperator{ + installConfigAsset: stock.InstallConfig(), + directory: rootDir, + } + s.addonOperator = &kubeAddonOperator{ + installConfigAsset: stock.InstallConfig(), + directory: rootDir, + } + s.networkOperator = &networkOperator{ + installConfigAsset: stock.InstallConfig(), + directory: rootDir, + } + s.mao = &machineAPIOperator{ + installConfigAsset: stock.InstallConfig(), + aggregatorCA: tlsStock.AggregatorCA(), + directory: rootDir, + } + // TODO: + //s.clusterVersionOperator = &clusterVersionOperator{} +} + +// Manifests returns the manifests asset +func (s *StockImpl) Manifests() asset.Asset { return s.manifests } + +// ClusterVersionOperator returns the cvo asset object +func (s *StockImpl) ClusterVersionOperator() asset.Asset { return s.clusterVersionOperator } + +// KubeCoreOperator returns the kco asset object +func (s *StockImpl) KubeCoreOperator() asset.Asset { return s.kubeCoreOperator } + +// NetworkOperator returns the network operator asset object +func (s *StockImpl) NetworkOperator() asset.Asset { return s.networkOperator } + +// KubeAddonOperator returns the addon operator asset object +func (s *StockImpl) KubeAddonOperator() asset.Asset { return s.addonOperator } + +// Mao returns the machine API operator asset object +func (s *StockImpl) Mao() asset.Asset { return s.mao } diff --git a/pkg/asset/manifests/template.go b/pkg/asset/manifests/template.go new file mode 100644 index 00000000000..2b41f1ff0d2 --- /dev/null +++ b/pkg/asset/manifests/template.go @@ -0,0 +1,33 @@ +package manifests + +type templateData struct { + AggregatorCaCert string + AggregatorCaKey string + ApiserverCert string + ApiserverKey string + ApiserverProxyCert string + ApiserverProxyKey string + Base64encodeCloudProviderConfig string + ClusterapiCaCert string + ClusterapiCaKey string + EtcdCaCert string + EtcdClientCert string + EtcdClientKey string + KubeCaCert string + KubeCaKey string + MachineConfigOperatorImage string + McsTLSCert string + McsTLSKey string + OidcCaCert string + OpenshiftApiserverCert string + OpenshiftApiserverKey string + OpenshiftLoopbackKubeconfig string + PullSecret string + RootCaCert string + ServiceaccountKey string + ServiceaccountPub string + ServiceServingCaCert string + ServiceServingCaKey string + TectonicNetworkOperatorImage string + WorkerIgnConfig string +} diff --git a/pkg/asset/manifests/utils.go b/pkg/asset/manifests/utils.go new file mode 100644 index 00000000000..dc54ab13d16 --- /dev/null +++ b/pkg/asset/manifests/utils.go @@ -0,0 +1,59 @@ +package manifests + +import ( + "github.com/ghodss/yaml" + "github.com/openshift/installer/pkg/types" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type configurationObject struct { + metav1.TypeMeta + + Metadata metadata `json:"metadata,omitempty"` + Data genericData `json:"data,omitempty"` +} + +type metadata struct { + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` +} + +func configMap(namespace, name string, data genericData) (string, error) { + configurationObject := configurationObject{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "ConfigMap", + }, + Metadata: metadata{ + Name: name, + Namespace: namespace, + }, + Data: data, + } + + str, err := marshalYAML(configurationObject) + if err != nil { + return "", err + } + return str, nil +} + +func marshalYAML(obj interface{}) (string, error) { + data, err := yaml.Marshal(&obj) + if err != nil { + return "", err + } + + return string(data), nil +} + +// Converts a platform to the cloudProvider that k8s understands +func tectonicCloudProvider(platform types.Platform) string { + if platform.AWS != nil { + return "aws" + } + if platform.Libvirt != nil { + return "libvirt" + } + return "" +} diff --git a/pkg/asset/stock/BUILD.bazel b/pkg/asset/stock/BUILD.bazel index c7a5d8d8d32..605f83aa8ee 100644 --- a/pkg/asset/stock/BUILD.bazel +++ b/pkg/asset/stock/BUILD.bazel @@ -13,6 +13,7 @@ go_library( "//pkg/asset/ignition:go_default_library", "//pkg/asset/installconfig:go_default_library", "//pkg/asset/kubeconfig:go_default_library", + "//pkg/asset/manifests:go_default_library", "//pkg/asset/tls:go_default_library", ], ) diff --git a/pkg/asset/stock/stock.go b/pkg/asset/stock/stock.go index 3562db9e0cf..40b61eb94dd 100644 --- a/pkg/asset/stock/stock.go +++ b/pkg/asset/stock/stock.go @@ -8,6 +8,7 @@ import ( "github.com/openshift/installer/pkg/asset/ignition" "github.com/openshift/installer/pkg/asset/installconfig" "github.com/openshift/installer/pkg/asset/kubeconfig" + "github.com/openshift/installer/pkg/asset/manifests" "github.com/openshift/installer/pkg/asset/tls" ) @@ -18,6 +19,7 @@ type Stock struct { tlsStock ignitionStock clusterStock + manifestsStock } type installConfigStock struct { @@ -40,6 +42,10 @@ type clusterStock struct { cluster.StockImpl } +type manifestsStock struct { + manifests.StockImpl +} + var _ installconfig.Stock = (*Stock)(nil) // EstablishStock establishes the stock of assets in the specified directory. @@ -51,6 +57,7 @@ func EstablishStock(directory string) *Stock { s.kubeconfigStock.EstablishStock(directory, &s.installConfigStock, &s.tlsStock) s.ignitionStock.EstablishStock(directory, s, s, s) s.clusterStock.EstablishStock(directory, s, s) + s.manifestsStock.EstablishStock(directory, &s.installConfigStock, s, s) return s }