def internal_build_config(self) -> Sequence[ObjectItem]: ret = [ Object( { 'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': { 'name': self.object_name('config'), 'namespace': self.namespace(), }, 'data': { 'enabled_plugins': LiteralStr('[{}].'.format(', '.join( self.option_get('config.enabled_plugins')))), 'rabbitmq.conf': LiteralStr(self.configfile_get()), } }, name=self.BUILDITEM_CONFIG, source=self.SOURCE_NAME, instance=self.basename()) ] config_secret = {} if not IsKData(self.option_get('config.erlang_cookie')): config_secret.update({ 'erlang_cookie': self.kubragen.secret_data_encode( self.option_get('config.erlang_cookie')), }) if not IsKData(self.option_get('config.load_definitions')): if self.option_get('config.load_definitions') is not None: config_secret.update({ 'load_definition.json': self.kubragen.secret_data_encode( self.option_get('config.load_definitions')), }) if len(config_secret) > 0: ret.append( Object( { 'apiVersion': 'v1', 'kind': 'Secret', 'metadata': { 'name': self.object_name('config-secret'), 'namespace': self.namespace(), }, 'type': 'Opaque', 'data': config_secret, }, name=self.BUILDITEM_CONFIG_SECRET, source=self.SOURCE_NAME, instance=self.basename())) return ret
def test_merge(self): data = [ Object({ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai', }, }, name='x') ] ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch( filters={'names': ['x']}, patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai', 'tari': 'bai' } }])
def internal_build_accesscontrol(self) -> Sequence[ObjectItem]: ret: List[ObjectItem] = [] if self.option_get( 'config.authorization.serviceaccount_create') is not False: ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': { 'name': self.object_name('service-account'), 'namespace': self.namespace(), } }, name=self.BUILDITEM_SERVICE_ACCOUNT, source=self.SOURCE_NAME, instance=self.basename()), ]) ret.extend( self._build_result_change( self._create_prometheus_config().build( PrometheusBuilder.BUILD_ACCESSCONTROL), 'prometheus')) if self.option_get('enable.kube-state-metrics') is not False: ret.extend( self._build_result_change( self._create_kubestatemetrics_config().build( KubeStateMetricsBuilder.BUILD_ACCESSCONTROL), 'kube-state-metrics')) return ret
def test_merge_filters_4(self): data = [ Object({ 'foo': 'bar', 'shin': 'gami', }, name='x', source='y', instance='z') ] ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch(filters=[ lambda o: o.name == 'a', lambda o: o.name == 'x' ], patches=[{ 'op': 'add', 'path': '/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{'foo': 'bar', 'shin': 'gami', 'tari': 'bai'}])
def test_merge_str_to_helperstr(self): data = [Object({ 'foo': 'bar', 'shin': QuotedStr('gami'), }, name='x')] ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch( filters={'names': ['x']}, patches=[{ 'op': 'replace', 'path': '/shin', 'value': 'bai' }]) ]) self.assertEqual(ret, [{'foo': 'bar', 'shin': 'bai'}]) self.assertNotIsInstance(ret[0]['shin'], HelperStr)
def internal_build_config(self) -> Sequence[ObjectItem]: ret = [] ret.append( Object( { 'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': { 'name': self.object_name('config'), 'namespace': self.namespace(), }, 'data': { 'promtail.yaml': LiteralStr(self.promtail_configfile_get()), } }, name=self.BUILDITEM_CONFIG, source=self.SOURCE_NAME, instance=self.basename())) return ret
def internal_build_config(self) -> Sequence[ObjectItem]: ret = [] ret.append( Object( { 'apiVersion': 'v1', 'kind': 'Secret', 'metadata': { 'name': self.object_name('config-secret'), 'namespace': self.namespace(), }, 'type': 'Opaque', 'data': { 'loki.yaml': self.kubragen.secret_data_encode( self.loki_configfile_get()), } }, name=self.BUILDITEM_CONFIG_SECRET, source=self.SOURCE_NAME, instance=self.basename())) return ret
out.append(shell_script) shell_script.append('set -e') # # OUTPUTFILE: app-namespace.yaml # file = OutputFile_Kubernetes('app-namespace.yaml') file.append([ Object( { 'apiVersion': 'v1', 'kind': 'Namespace', 'metadata': { 'name': 'app-monitoring', }, }, name='ns-monitoring', source='app', instance='app') ]) out.append(file) shell_script.append( OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) shell_script.append( f'kubectl config set-context --current --namespace=app-monitoring') #
def internal_build_service(self) -> Sequence[ObjectItem]: ret = [] ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': self.object_name('service-headless'), 'namespace': self.namespace(), }, 'spec': { 'clusterIP': 'None', 'ports': [{ 'name': 'epmd', 'port': 4369, 'protocol': 'TCP', 'targetPort': 4369 }, { 'name': 'cluster-links', 'port': 25672, 'protocol': 'TCP', 'targetPort': 25672 }], 'selector': { 'app': self.object_name('pod-label-app'), }, 'type': 'ClusterIP', 'sessionAffinity': 'None' } }, name=self.BUILDITEM_SERVICE_HEADLESS, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'apps/v1', 'kind': 'StatefulSet', 'metadata': { 'name': self.object_name('statefulset'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'selector': { 'matchLabels': { 'app': self.object_name('pod-label-app'), } }, 'serviceName': self.object_name('service-headless'), 'replicas': 1, 'template': { 'metadata': { 'name': self.object_name('pod-label-app'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, 'annotations': ValueData( { 'prometheus.io/scrape': QuotedStr('true'), 'prometheus.io/path': QuotedStr('/metrics'), 'prometheus.io/port': QuotedStr('15692'), }, enabled=self.option_get( 'config.enable_prometheus') is not False and self.option_get( 'config.prometheus_annotation') is not False), }, 'spec': { 'initContainers': [{ 'name': 'rabbitmq-config', 'image': self.option_get('container.busybox'), 'securityContext': { 'runAsUser': 0, 'runAsGroup': 0 }, 'volumeMounts': [ { 'name': 'rabbitmq-config', 'mountPath': '/tmp/rabbitmq' }, { 'name': 'rabbitmq-config-rw', 'mountPath': '/etc/rabbitmq' }, { 'name': 'rabbitmq-config-erlang-cookie', 'mountPath': '/tmp/rabbitmq-cookie' } ], 'command': [ 'sh', '-c', 'cp ' '/tmp/rabbitmq/rabbitmq.conf ' '/etc/rabbitmq/rabbitmq.conf ' "&& echo '' " '>> ' '/etc/rabbitmq/rabbitmq.conf; ' 'cp ' '/tmp/rabbitmq/enabled_plugins ' '/etc/rabbitmq/enabled_plugins; ' 'mkdir -p ' '/var/lib/rabbitmq; ' 'cp ' '/tmp/rabbitmq-cookie/erlang_cookie ' '/var/lib/rabbitmq/.erlang.cookie; ' 'chmod 600 ' '/var/lib/rabbitmq/.erlang.cookie; ' 'chown ' '999.999 ' '/etc/rabbitmq/rabbitmq.conf ' '/etc/rabbitmq/enabled_plugins ' '/var/lib/rabbitmq ' '/var/lib/rabbitmq/.erlang.cookie' ] }], 'volumes': [ { 'name': 'rabbitmq-config', 'configMap': { 'name': self.object_name('config'), 'optional': False, 'items': [{ 'key': 'enabled_plugins', 'path': 'enabled_plugins' }, { 'key': 'rabbitmq.conf', 'path': 'rabbitmq.conf' }] } }, { 'name': 'rabbitmq-config-rw', 'emptyDir': {} }, KDataHelper_Volume.info( base_value={ 'name': 'rabbitmq-config-erlang-cookie', }, value_if_kdata=self.option_get( 'config.erlang_cookie'), default_value={ 'secret': { 'secretName': self.object_name( 'config-secret'), 'items': [{ 'key': 'erlang_cookie', 'path': 'erlang_cookie', }] }, }, key_path='erlang_cookie'), KDataHelper_Volume.info( base_value={ 'name': 'rabbitmq-config-load-definition', }, value_if_kdata=self.option_get( 'config.load_definitions'), default_value={ 'secret': { 'secretName': self.object_name( 'config-secret'), 'items': [{ 'key': 'load_definition.json', 'path': 'load_definition.json', }] } }, key_path='load_definition.json', enabled=self.option_get( 'config.load_definitions') is not None), KDataHelper_Volume.info( base_value={ 'name': 'rabbitmq-data', }, value=self.option_get( 'kubernetes.volumes.data')), ], 'serviceAccountName': ValueData( value=self.object_name('service-account'), enabled=self.object_name('service-account') is not None), 'securityContext': { 'fsGroup': 999, 'runAsUser': 999, 'runAsGroup': 999 }, 'containers': [{ 'name': 'rabbitmq', 'image': self.option_get('container.rabbitmq'), 'volumeMounts': [ { 'name': 'rabbitmq-config-rw', 'mountPath': '/etc/rabbitmq' }, { 'name': 'rabbitmq-data', 'mountPath': '/var/lib/rabbitmq/mnesia' }, ValueData(value={ 'name': 'rabbitmq-config-load-definition', 'mountPath': '/etc/rabbitmq-load-definition', 'readOnly': True, }, enabled=self.option_get( 'config.load_definitions' ) is not None) ], 'ports': [ { 'name': 'amqp', 'containerPort': 5672, 'protocol': 'TCP' }, { 'name': 'management', 'containerPort': 15672, 'protocol': 'TCP' }, ValueData( value={ 'name': 'prometheus', 'containerPort': 15692, 'protocol': 'TCP' }, enabled=self.option_get( 'config.enable_prometheus') is not False), { 'name': 'epmd', 'containerPort': 4369, 'protocol': 'TCP' } ], 'livenessProbe': { 'exec': { 'command': ['rabbitmq-diagnostics', 'status'] }, 'initialDelaySeconds': 60, 'periodSeconds': 60, 'timeoutSeconds': 15 }, 'readinessProbe': { 'exec': { 'command': ['rabbitmq-diagnostics', 'ping'] }, 'initialDelaySeconds': 20, 'periodSeconds': 60, 'timeoutSeconds': 10 }, 'resources': ValueData(value=self.option_get( 'kubernetes.resources.statefulset'), disabled_if_none=True), }] } } } }, name=self.BUILDITEM_STATEFULSET, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'kind': 'Service', 'apiVersion': 'v1', 'metadata': { 'name': self.object_name('service'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app') }, }, 'spec': { 'type': 'ClusterIP', 'ports': [{ 'name': 'http', 'protocol': 'TCP', 'port': 15672, }, ValueData(value={ 'name': 'prometheus', 'protocol': 'TCP', 'port': 15692 }, enabled=self.option_get( 'config.enable_prometheus') is not False), { 'name': 'amqp', 'protocol': 'TCP', 'port': 5672 }], 'selector': { 'app': self.object_name('pod-label-app') } } }, name=self.BUILDITEM_SERVICE, source=self.SOURCE_NAME, instance=self.basename()) ]) return ret
# # OUTPUTFILE: app-namespace.yaml # file = OutputFile_Kubernetes('app-namespace.yaml') out.append(file) file.append( FilterJSONPatches_Apply( [ Object( { 'apiVersion': 'v1', 'kind': 'Namespace', 'metadata': { 'name': 'app-default', 'annotations': { 'will-not-output': ValueData(value='anything', enabled=False), } }, }, name='ns-default', source='app'), Object( { 'apiVersion': 'v1', 'kind': 'Namespace', 'metadata': { 'name': 'app-monitoring', }, }, name='ns-monitoring',
def internal_build_accesscontrol(self) -> Sequence[ObjectItem]: ret = [] if self.option_get( 'config.authorization.serviceaccount_create') is not False: ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': { 'name': self.object_name('service-account'), 'namespace': self.namespace(), } }, name=self.BUILDITEM_SERVICE_ACCOUNT, source=self.SOURCE_NAME, instance=self.basename()), ]) if self.option_get('config.authorization.roles_create') is not False: ret.extend([ Object( { 'kind': 'Role', 'apiVersion': 'rbac.authorization.k8s.io/v1beta1', 'metadata': { 'name': self.object_name('role'), 'namespace': self.namespace(), }, 'rules': [{ 'apiGroups': [''], 'resources': ['endpoints'], 'verbs': ['get'] }, { 'apiGroups': [''], 'resources': ['events'], 'verbs': ['create'] }] }, name=self.BUILDITEM_ROLE, source=self.SOURCE_NAME, instance=self.basename()), ]) if self.option_get('config.authorization.roles_bind') is not False: ret.extend([ Object( { 'kind': 'RoleBinding', 'apiVersion': 'rbac.authorization.k8s.io/v1beta1', 'metadata': { 'name': self.object_name('role-binding'), 'namespace': self.namespace(), }, 'subjects': [{ 'kind': 'ServiceAccount', 'name': self.object_name('service-account'), }], 'roleRef': { 'apiGroup': 'rbac.authorization.k8s.io', 'kind': 'Role', 'name': self.object_name('role'), } }, name=self.BUILDITEM_ROLE_BINDING, source=self.SOURCE_NAME, instance=self.basename()) ]) return ret
def test_no_merge(self): data = [ Object({ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai', }, }, name='x', source='y', instance='z') ] ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch( filters={'names': ['a']}, patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai' } }]) ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch( filters={'sources': ['b']}, patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai' } }]) ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch( filters={'instances': ['c']}, patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai' } }]) ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch(filters=ObjectFilter( names='a', sources='y', instances='z'), patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai' } }]) ret = FilterJSONPatches_Apply(items=data, jsonpatches=[ FilterJSONPatch(filters=[ ObjectFilter(sources='h', instances='j'), lambda o: o.name == 'i' ], patches=[{ 'op': 'add', 'path': '/shin/tari', 'value': 'bai' }]) ]) self.assertEqual(ret, [{ 'foo': 'bar', 'shin': { 'gami': 'hai', 'shami': 'nai' } }])
def internal_build_service(self) -> Sequence[ObjectItem]: self._checkdownloaded() ret = [] if self._downloadedfiles is not None: for item in self._downloadedfiles['headless-service.yaml']: ritem = item if ritem['kind'] == 'Service': ritem = Object(jsonpatchext.apply_patch(ritem, [ { 'op': 'check', 'path': '/metadata/name', 'cmp': 'equals', 'value': 'rabbitmq-headless' }, { 'op': 'check', 'path': '/metadata/namespace', 'cmp': 'equals', 'value': 'test-rabbitmq' }, { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('service-headless') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, { 'op': 'replace', 'path': '/spec/selector/app', 'value': self.object_name('pod-label-app') }, ], in_place=False), name=self.BUILDITEM_SERVICE_HEADLESS, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) for item in self._downloadedfiles['statefulset.yaml']: ritem = item if ritem['kind'] == 'StatefulSet': ritempatch = [ { 'op': 'check', 'path': '/metadata/name', 'cmp': 'equals', 'value': 'rabbitmq' }, { 'op': 'check', 'path': '/metadata/namespace', 'cmp': 'equals', 'value': 'test-rabbitmq' }, { 'op': 'check', 'path': '/spec/template/spec/initContainers/0/image', 'cmp': 'startswith', 'value': 'busybox' }, { 'op': 'check', 'path': '/spec/template/spec/volumes/2/name', 'cmp': 'equals', 'value': 'rabbitmq-data' }, { 'op': 'check', 'path': '/spec/template/spec/containers/0/image', 'cmp': 'startswith', 'value': 'rabbitmq' }, { 'op': 'check', 'path': '/spec/template/spec/containers/0/env/0/name', 'cmp': 'equals', 'value': 'RABBITMQ_DEFAULT_PASS' }, { 'op': 'check', 'path': '/spec/template/spec/containers/0/env/1/name', 'cmp': 'equals', 'value': 'RABBITMQ_DEFAULT_USER' }, { 'op': 'check', 'path': '/spec/template/spec/containers/0/env/2/name', 'cmp': 'equals', 'value': 'RABBITMQ_ERLANG_COOKIE' }, { 'op': 'check', 'path': '/spec/template/spec/containers/0/ports/2/name', 'cmp': 'equals', 'value': 'prometheus' }, { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('statefulset') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, { 'op': 'merge', 'path': '/metadata', 'value': { 'labels': {} } }, { 'op': 'merge', 'path': '/metadata/labels', 'value': { 'app': self.object_name('pod-label-app') } }, { 'op': 'replace', 'path': '/spec/selector/matchLabels/app', 'value': self.object_name('pod-label-app') }, { 'op': 'replace', 'path': '/spec/serviceName', 'value': self.object_name('service-headless') }, { 'op': 'remove', 'path': '/spec/volumeClaimTemplates' }, { 'op': 'replace', 'path': '/spec/template/metadata/name', 'value': self.object_name('pod-label-app') }, { 'op': 'replace', 'path': '/spec/template/metadata/namespace', 'value': self.namespace() }, { 'op': 'replace', 'path': '/spec/template/metadata/labels/app', 'value': self.object_name('pod-label-app') }, { 'op': 'replace', 'path': '/spec/template/spec/serviceAccount', 'value': ValueData( value=self.object_name('service-account'), enabled=self.object_name('service-account') is not None) }, { 'op': 'replace', 'path': '/spec/template/spec/volumes/2', 'value': KDataHelper_Volume.info( base_value={ 'name': 'rabbitmq-data', }, value=self.option_get( 'kubernetes.volumes.data')) }, { 'op': 'replace', 'path': '/spec/template/spec/containers/0/env/0', 'value': KDataHelper_Env.info( base_value={'name': 'RABBITMQ_DEFAULT_PASS'}, value=self.option_get('config.admin.password'), default_value={ 'valueFrom': { 'secretKeyRef': { 'name': self.object_name('config-secret'), 'key': 'admin.password' } }, }) }, { 'op': 'replace', 'path': '/spec/template/spec/containers/0/env/1', 'value': KDataHelper_Env.info( base_value={'name': 'RABBITMQ_DEFAULT_USER'}, value=self.option_get('config.admin.username'), default_value={ 'valueFrom': { 'secretKeyRef': { 'name': self.object_name('config-secret'), 'key': 'admin.username' } }, }) }, { 'op': 'replace', 'path': '/spec/template/spec/containers/0/env/2', 'value': KDataHelper_Env.info( base_value={'name': 'RABBITMQ_ERLANG_COOKIE'}, value=self.option_get('config.erlang_cookie'), default_value={ 'valueFrom': { 'secretKeyRef': { 'name': self.object_name('config-secret'), 'key': 'erlang_cookie' } }, }) }, { 'op': 'add', 'path': '/spec/template/spec/containers/0/resources', 'value': ValueData(value=self.option_get( 'kubernetes.resources.statefulset'), disabled_if_none=True), }, ] if self.option_get('container.busybox') is not None: ritempatch.append({ 'op': 'replace', 'path': '/spec/template/spec/initContainers/0/image', 'value': self.option_get('container.busybox') }) if self.option_get('container.rabbitmq') is not None: ritempatch.append({ 'op': 'replace', 'path': '/spec/template/spec/containers/0/image', 'value': self.option_get('container.rabbitmq') }) if self.option_get('config.enable_prometheus') is False: ritempatch.append({ 'op': 'remove', 'path': '/spec/template/spec/containers/0/ports/2' }) if self.option_get( 'config.enable_prometheus' ) is not False and self.option_get( 'config.prometheus_annotation') is not False: ritempatch.append({ 'op': 'merge', 'path': '/spec/template/metadata', 'value': { 'annotations': { 'prometheus.io/scrape': QuotedStr('true'), 'prometheus.io/path': QuotedStr('/metrics'), 'prometheus.io/port': QuotedStr('15692'), } } }) if self.option_get('config.load_definitions') is not None: ritempatch.append({ 'op': 'add', 'path': '/spec/template/spec/volumes', 'value': KDataHelper_Volume.info( base_value={ 'name': 'rabbitmq-config-load-definition', }, value_if_kdata=self.option_get( 'config.load_definitions'), default_value={ 'secret': { 'secretName': self.object_name('config-secret'), 'items': [{ 'key': 'load_definition.json', 'path': 'load_definition.json', }] } }, key_path='load_definition.json') }) ritempatch.append({ 'op': 'add', 'path': '/spec/template/spec/containers/0/volumeMounts', 'value': { 'name': 'rabbitmq-config-load-definition', 'mountPath': '/etc/rabbitmq-load-definition', 'readOnly': True, } }) ritem = Object(jsonpatchext.apply_patch(ritem, ritempatch, in_place=False), name=self.BUILDITEM_STATEFULSET, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) for item in self._downloadedfiles['client-service.yaml']: ritem = item if ritem['kind'] == 'Service': ritempatch = [ { 'op': 'check', 'path': '/metadata/name', 'cmp': 'equals', 'value': 'rabbitmq-client' }, { 'op': 'check', 'path': '/metadata/namespace', 'cmp': 'equals', 'value': 'test-rabbitmq' }, { 'op': 'check', 'path': '/spec/ports/1/name', 'cmp': 'equals', 'value': 'prometheus' }, { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('service') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, { 'op': 'replace', 'path': '/metadata/labels/app', 'value': self.object_name('pod-label-app') }, { 'op': 'replace', 'path': '/spec/type', 'value': self.option_get('config.servicetype') }, { 'op': 'replace', 'path': '/spec/selector/app', 'value': self.object_name('pod-label-app') }, ] if self.option_get('config.enable_prometheus') is False: ritempatch.append({ 'op': 'remove', 'path': '/spec/ports/1' }) ritem = Object(jsonpatchext.apply_patch(ritem, ritempatch, in_place=False), name=self.BUILDITEM_SERVICE, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) self._check_object_must_have( ret, [ self.BUILDITEM_SERVICE_HEADLESS, self.BUILDITEM_STATEFULSET, self.BUILDITEM_SERVICE ], 'headless-service.yaml, statefulset.yaml, client-service.yaml') return ret
def main(): parser = argparse.ArgumentParser(description='Kube Creator') parser.add_argument('-p', '--provider', help='provider', required=True, choices=[ 'google-gke', 'amazon-eks', 'digitalocean-kubernetes', 'k3d', ]) parser.add_argument('-o', '--output-path', help='output path', default='output') args = parser.parse_args() if args.provider == 'k3d': kgprovider = ProviderK3DGeneric() elif args.provider == 'google-gke': kgprovider = ProviderGoogleGKE() elif args.provider == 'digitalocean-kubernetes': kgprovider = ProviderDigitalOceanKubernetes() elif args.provider == 'amazon-eks': kgprovider = ProviderAmazonEKS() else: raise Exception('Unknown target') kg = KubraGen(provider=kgprovider, options=Options({ 'namespaces': { 'default': 'default', 'mon': 'monitoring', }, })) if kgprovider.provider == PROVIDER_K3D: kg.resources().persistentvolumeprofile_add('default', KRPersistentVolumeProfile_HostPath()) elif kgprovider.provider == PROVIDER_GOOGLE: kg.resources().persistentvolumeprofile_add('default', KRPersistentVolumeProfile_GCEPersistentDisk()) elif kgprovider.provider == PROVIDER_DIGITALOCEAN: kg.resources().persistentvolumeprofile_add('default', KRPersistentVolumeProfile_CSI_DOBS()) elif kgprovider.provider == PROVIDER_AMAZON: kg.resources().persistentvolumeprofile_add('default', KRPersistentVolumeProfile_AWSElasticBlockStore()) if kgprovider.provider == PROVIDER_K3D: kg.resources().persistentvolumeclaimprofile_add('default', KRPersistentVolumeClaimProfile_Basic(allow_selector=False)) else: kg.resources().persistentvolumeclaimprofile_add('default', KRPersistentVolumeClaimProfile_Basic()) kg.resources().persistentvolume_add('elasticsearch-storage', 'default', { 'hostPath': { 'path': '/var/storage/elasticsearch' }, 'csi': { 'fsType': 'ext4', }, }, { 'metadata': { 'labels': { 'pv.role': 'elasticsearch', }, }, 'spec': { 'persistentVolumeReclaimPolicy': 'Retain', 'capacity': { 'storage': '50Gi' }, 'accessModes': ['ReadWriteOnce'], }, }) kg.resources().persistentvolumeclaim_add('elasticsearch-storage-claim', 'default', { 'namespace': 'monitoring', 'persistentVolume': 'elasticsearch-storage', }, { 'spec': { 'selector': { 'matchLabels': { 'pv.role': 'elasticsearch', } }, } }) out = OutputProject(kg) shell_script = OutputFile_ShellScript('create_{}.sh'.format(args.provider)) out.append(shell_script) shell_script.append('set -e') # # Provider setup # if kgprovider.provider == PROVIDER_K3D: storage_directory = os.path.join(os.getcwd(), 'output', 'storage') if not os.path.exists(storage_directory): os.makedirs(storage_directory) shell_script.append(f'# k3d cluster create kgsample-efk-stack --port 5051:80@loadbalancer --port 5052:443@loadbalancer -v {storage_directory}:/var/storage') # # OUTPUTFILE: namespace.yaml # file = OutputFile_Kubernetes('namespace.yaml') file.append([{ 'apiVersion': 'v1', 'kind': 'Namespace', 'metadata': { 'name': 'monitoring', }, }]) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: storage.yaml # file = OutputFile_Kubernetes('storage.yaml') file.append(kg.persistentvolume_build()) file.append(kg.persistentvolumeclaim_build()) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # SETUP: Traefik 2 # traefik2_config = Traefik2Builder(kubragen=kg, options=Traefik2Options({ 'namespace': OptionRoot('namespaces.default'), 'config': { 'traefik_args': [ '--api.dashboard=true', '--api.insecure=false', '--entrypoints.web.Address=:80', '--entrypoints.api.Address=:8080', '--providers.kubernetescrd', f'--providers.kubernetescrd.namespaces=default,monitoring' ], 'ports': [ Traefik2OptionsPort(name='web', port_container=80, port_service=80), Traefik2OptionsPort(name='api', port_container=8080, port_service=8080), ], 'create_traefik_crd': True, }, }) ) traefik2_config.ensure_build_names(traefik2_config.BUILD_CRD, traefik2_config.BUILD_ACCESSCONTROL, traefik2_config.BUILD_SERVICE) # # OUTPUTFILE: traefik-config-crd.yaml # file = OutputFile_Kubernetes('traefik-config-crd.yaml') file.append(traefik2_config.build(traefik2_config.BUILD_CRD)) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: traefik-config.yaml # file = OutputFile_Kubernetes('traefik-config.yaml') file.append(traefik2_config.build(traefik2_config.BUILD_ACCESSCONTROL)) file.append([{ 'apiVersion': 'traefik.containo.us/v1alpha1', 'kind': 'IngressRoute', 'metadata': { 'name': 'traefik-api', 'namespace': kg.option_get('namespaces.default'), }, 'spec': { 'entryPoints': ['api'], 'routes': [{ 'match': 'Method(`GET`)', 'kind': 'Rule', 'services': [{ 'name': 'api@internal', 'kind': 'TraefikService' }] }] } }]) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: traefik.yaml # file = OutputFile_Kubernetes('traefik.yaml') file.append(traefik2_config.build(traefik2_config.BUILDITEM_SERVICE)) file.append({ 'apiVersion': 'traefik.containo.us/v1alpha1', 'kind': 'IngressRoute', 'metadata': { 'name': 'admin-traefik', 'namespace': kg.option_get('namespaces.default'), }, 'spec': { 'entryPoints': ['web'], 'routes': [{ 'match': f'Host(`admin-traefik.localdomain`)', 'kind': 'Rule', 'services': [{ 'name': traefik2_config.object_name('service'), 'port': 8080 }], }] } }) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # SETUP: efk # efk_config = EFKBuilder(kubragen=kg, options=EFKOptions({ 'namespace': OptionRoot('namespaces.mon'), 'config': { 'probes': False, 'elasticsearch': { 'replicas': 1 if kgprovider.provider == PROVIDER_K3D else 3, }, 'kibana': { 'service_port': 80, }, }, 'enable': { 'kibana': True, }, 'kubernetes': { 'volumes': { 'elasticsearch-data': { 'persistentVolumeClaim': { 'claimName': 'elasticsearch-storage-claim' } } }, }, })) efk_config.ensure_build_names(efk_config.BUILD_ACCESSCONTROL, efk_config.BUILD_CONFIG, efk_config.BUILD_SERVICE) # # OUTPUTFILE: efk-config.yaml # file = OutputFile_Kubernetes('efk-config.yaml') out.append(file) file.append(efk_config.build(efk_config.BUILD_ACCESSCONTROL, efk_config.BUILD_CONFIG)) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: efk.yaml # file = OutputFile_Kubernetes('efk.yaml') out.append(file) file.append(efk_config.build(efk_config.BUILD_SERVICE)) file.append([{ 'apiVersion': 'traefik.containo.us/v1alpha1', 'kind': 'IngressRoute', 'metadata': { 'name': 'admin-kibana', 'namespace': kg.option_get('namespaces.mon'), }, 'spec': { 'entryPoints': ['web'], 'routes': [{ 'match': f'Host(`admin-kibana.localdomain`)', 'kind': 'Rule', 'services': [{ 'name': efk_config.object_name('kibana-service'), 'namespace': efk_config.namespace(), 'port': efk_config.option_get('config.kibana.service_port'), }], }] } }]) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: http-echo.yaml # file = OutputFile_Kubernetes('http-echo.yaml') out.append(file) file.append([{ 'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': { 'name': 'echo-deployment', 'namespace': kg.option_get('namespaces.default'), 'labels': { 'app': 'echo' } }, 'spec': { 'replicas': 1, 'selector': { 'matchLabels': { 'app': 'echo' } }, 'template': { 'metadata': { 'labels': { 'app': 'echo' } }, 'spec': { 'containers': [{ 'name': 'echo', 'image': 'mendhak/http-https-echo', 'ports': [{ 'containerPort': 80 }, { 'containerPort': 443 }], }] } } } }, { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': 'echo-service', 'namespace': kg.option_get('namespaces.default'), }, 'spec': { 'selector': { 'app': 'echo' }, 'ports': [{ 'name': 'http', 'port': 80, 'targetPort': 80, 'protocol': 'TCP' }] } }, { 'apiVersion': 'traefik.containo.us/v1alpha1', 'kind': 'IngressRoute', 'metadata': { 'name': 'http-echo', 'namespace': kg.option_get('namespaces.default'), }, 'spec': { 'entryPoints': ['web'], 'routes': [{ # 'match': f'Host(`http-echo.localdomain`)', 'match': f'PathPrefix(`/`)', 'kind': 'Rule', 'services': [{ 'name': 'echo-service', 'port': 80, }], }] } }]) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUTFILE: ingress.yaml # file = OutputFile_Kubernetes('ingress.yaml') http_path = '/' if kgprovider.provider == PROVIDER_GOOGLE or kgprovider.provider == PROVIDER_AMAZON: http_path = '/*' file_data = [ Object({ 'apiVersion': 'extensions/v1beta1', 'kind': 'Ingress', 'metadata': { 'name': 'ingress', 'namespace': kg.option_get('namespaces.default'), }, 'spec': { 'rules': [{ 'http': { 'paths': [{ 'path': http_path, 'backend': { 'serviceName': traefik2_config.object_name('service'), 'servicePort': 80, } }] } }] } }, name='ingress', source='app', instance='ingress') ] if kgprovider.provider == PROVIDER_AMAZON: FilterJSONPatches_Apply(file_data, jsonpatches=[ FilterJSONPatch(filters={'names': ['ingress']}, patches=[ {'op': 'merge', 'path': '/metadata', 'value': {'annotations': { 'kubernetes.io/ingress.class': 'alb', 'alb.ingress.kubernetes.io/scheme': 'internet-facing', 'alb.ingress.kubernetes.io/listen-ports': QuotedStr('[{"HTTP": 80}]'), }}} ]) ]) file.append(file_data) out.append(file) shell_script.append(OD_FileTemplate(f'kubectl apply -f ${{FILE_{file.fileid}}}')) # # OUTPUT # output_path = os.path.join(args.output_path, '{}-{}'.format( args.provider, datetime.datetime.today().strftime("%Y%m%d-%H%M%S"))) print('Saving files to {}'.format(output_path)) if not os.path.exists(output_path): os.makedirs(output_path) out.output(OutputDriver_Directory(output_path))
def internal_build_accesscontrol(self) -> Sequence[ObjectItem]: self._checkdownloaded() ret = [] must_have = [] if self.option_get( 'config.authorization.serviceaccount_create') is not False: must_have.append(self.BUILDITEM_SERVICE_ACCOUNT) if self.option_get('config.authorization.roles_create') is not False: must_have.append(self.BUILDITEM_ROLE) if self.option_get('config.authorization.roles_bind') is not False: must_have.append(self.BUILDITEM_ROLE_BINDING) if self._downloadedfiles is not None: for item in self._downloadedfiles['rbac.yaml']: ritem = item if ritem['kind'] == 'ServiceAccount': if self.option_get( 'config.authorization.serviceaccount_create' ) is not False: ritem = Object(jsonpatchext.apply_patch( ritem, [ { 'op': 'check', 'path': '/metadata/name', 'cmp': 'equals', 'value': 'rabbitmq' }, { 'op': 'check', 'path': '/metadata/namespace', 'cmp': 'equals', 'value': 'test-rabbitmq' }, { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('service-account') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, ], in_place=False), name=self.BUILDITEM_SERVICE_ACCOUNT, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) elif ritem['kind'] == 'Role': if self.option_get( 'config.authorization.roles_create') is not False: ritem = Object(jsonpatchext.apply_patch( ritem, [ { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('role') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, ], in_place=False), name=self.BUILDITEM_ROLE, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) elif ritem['kind'] == 'RoleBinding': if self.option_get( 'config.authorization.roles_bind') is not False: ritem = Object(jsonpatchext.apply_patch( ritem, [ { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('role-binding') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, { 'op': 'replace', 'path': '/subjects/0/name', 'value': self.object_name('service-account') }, { 'op': 'replace', 'path': '/roleRef/name', 'value': self.object_name('role') }, ], in_place=False), name=self.BUILDITEM_ROLE_BINDING, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) else: raise InvalidNameError( 'Unknown item kind in rbac.yaml: "{}"'.format( ritem['kind'])) self._check_object_must_have(ret, must_have, 'rbac.yaml') return ret
def internal_build_config(self) -> Sequence[ObjectItem]: self._checkdownloaded() ret = [] if self._downloadedfiles is not None: for item in self._downloadedfiles['configmap.yaml']: ritem = item if ritem['kind'] == 'ConfigMap': ritem = Object(jsonpatchext.apply_patch(ritem, [ { 'op': 'check', 'path': '/metadata/name', 'cmp': 'equals', 'value': 'rabbitmq-config' }, { 'op': 'check', 'path': '/metadata/namespace', 'cmp': 'equals', 'value': 'test-rabbitmq' }, { 'op': 'replace', 'path': '/metadata/name', 'value': self.object_name('config') }, { 'op': 'replace', 'path': '/metadata/namespace', 'value': self.namespace() }, { 'op': 'replace', 'path': '/data/enabled_plugins', 'value': LiteralStr('[{}].'.format(', '.join( self.option_get('config.enabled_plugins')))) }, { 'op': 'replace', 'path': '/data/rabbitmq.conf', 'value': LiteralStr(self.configfile_get()) }, ], in_place=False), name=self.BUILDITEM_CONFIG, source=self.SOURCE_NAME, instance=self.basename()) ret.append(ritem) config_secret = {} if not IsKData(self.option_get('config.erlang_cookie')): config_secret.update({ 'erlang_cookie': self.kubragen.secret_data_encode( self.option_get('config.erlang_cookie')), }) if not IsKData(self.option_get('config.admin.username')): config_secret.update({ 'admin.username': self.kubragen.secret_data_encode( self.option_get('config.admin.username')), }) if not IsKData(self.option_get('config.admin.password')): config_secret.update({ 'admin.password': self.kubragen.secret_data_encode( self.option_get('config.admin.password')), }) if not IsKData(self.option_get('config.load_definitions')): if self.option_get('config.load_definitions') is not None: config_secret.update({ 'load_definition.json': self.kubragen.secret_data_encode( self.option_get('config.load_definitions')), }) if len(config_secret) > 0: ret.append( Object( { 'apiVersion': 'v1', 'kind': 'Secret', 'metadata': { 'name': self.object_name('config-secret'), 'namespace': self.namespace(), }, 'type': 'Opaque', 'data': config_secret, }, name=self.BUILDITEM_CONFIG_SECRET, source=self.SOURCE_NAME, instance=self.basename())) return ret
def internal_build_service(self) -> Sequence[ObjectItem]: ret = [] ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': self.object_name('service-headless'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), } }, 'spec': { 'clusterIP': 'None', 'ports': [{ 'port': self.option_get('config.service_port'), 'protocol': 'TCP', 'name': 'http-metrics', 'targetPort': 'http-metrics' }], 'selector': { 'app': self.object_name('pod-label-app'), } } }, name=self.BUILDITEM_SERVICE_HEADLESS, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': self.object_name('service'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'type': 'ClusterIP', 'ports': [{ 'port': self.option_get('config.service_port'), 'protocol': 'TCP', 'name': 'http-metrics', 'targetPort': 'http-metrics' }], 'selector': { 'app': self.object_name('pod-label-app'), }, } }, name=self.BUILDITEM_SERVICE, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'apps/v1', 'kind': 'StatefulSet', 'metadata': { 'name': self.object_name('statefulset'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'podManagementPolicy': 'OrderedReady', 'replicas': 1, 'selector': { 'matchLabels': { 'app': self.object_name('pod-label-app'), } }, 'serviceName': self.object_name('service-headless'), 'updateStrategy': { 'type': 'RollingUpdate' }, 'template': { 'metadata': { 'labels': { 'app': self.object_name('pod-label-app'), }, 'annotations': ValueData( { 'prometheus.io/scrape': QuotedStr('true'), 'prometheus.io/port': QuotedStr('http-metrics'), }, enabled=self.option_get( 'config.prometheus_annotation') is not False), }, 'spec': { 'serviceAccountName': ValueData(self.option_get( 'config.authorization.serviceaccount_use'), disabled_if_none=True), 'securityContext': { 'fsGroup': 10001, 'runAsGroup': 10001, 'runAsNonRoot': True, 'runAsUser': 10001 }, 'containers': [{ 'name': 'loki', 'image': self.option_get('container.loki'), 'args': ['-config.file=/etc/loki/loki.yaml'], 'volumeMounts': [{ 'name': 'config', 'mountPath': '/etc/loki' }, { 'name': 'storage', 'mountPath': '/data', 'subPath': None }], 'ports': [{ 'name': 'http-metrics', 'containerPort': 3100, 'protocol': 'TCP' }], 'livenessProbe': { 'httpGet': { 'path': '/ready', 'port': 'http-metrics' }, 'initialDelaySeconds': 45 }, 'readinessProbe': { 'httpGet': { 'path': '/ready', 'port': 'http-metrics' }, 'initialDelaySeconds': 45 }, 'securityContext': { 'readOnlyRootFilesystem': True }, 'resources': ValueData(value=self.option_get( 'kubernetes.resources.statefulset'), disabled_if_none=True), }], 'terminationGracePeriodSeconds': 4800, 'volumes': [{ 'name': 'config', 'secret': { 'secretName': self.object_name('config-secret'), 'items': [{ 'key': 'loki.yaml', 'path': 'loki.yaml', }] } }, KDataHelper_Volume.info( base_value={ 'name': 'storage', }, value=self.option_get( 'kubernetes.volumes.data')) ] } } } }, name=self.BUILDITEM_STATEFULSET, source=self.SOURCE_NAME, instance=self.basename()), ]) return ret
def internal_build_service(self) -> Sequence[ObjectItem]: ret = [] ret.extend([ Object( { 'kind': 'Service', 'apiVersion': 'v1', 'metadata': { 'name': self.object_name('elasticsearch-service'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('elasticsearch-pod-label-app'), } }, 'spec': { 'selector': { 'app': self.object_name('elasticsearch-pod-label-app'), }, 'clusterIP': 'None', 'ports': [{ 'port': 9200, 'name': 'rest' }, { 'port': 9300, 'name': 'inter-node' }], } }, name=self.BUILDITEM_ELASTICSEARCH_SERVICE, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'apps/v1', 'kind': 'StatefulSet', 'metadata': { 'name': self.object_name('elasticsearch-statefulset'), 'namespace': self.namespace(), }, 'spec': { 'serviceName': self.object_name('elasticsearch-service'), 'replicas': self.option_get('config.elasticsearch.replicas'), 'selector': { 'matchLabels': { 'app': self.object_name( 'elasticsearch-pod-label-app'), } }, 'template': { 'metadata': { 'labels': { 'app': self.object_name( 'elasticsearch-pod-label-app'), } }, 'spec': { 'volumes': [ KDataHelper_Volume.info( base_value={ 'name': 'data', }, value=self.option_get( 'kubernetes.volumes.elasticsearch-data' )), ], 'containers': [{ 'name': 'elasticsearch', 'image': self.option_get('container.elasticsearch'), 'ports': [{ 'containerPort': 9200, 'name': 'rest', 'protocol': 'TCP' }, { 'containerPort': 9300, 'name': 'inter-node', 'protocol': 'TCP' }], 'volumeMounts': [{ 'name': 'data', 'mountPath': '/usr/share/elasticsearch/data' }], 'env': [{ 'name': 'cluster.name', 'value': self.object_name( 'elasticsearch-statefulset'), }, { 'name': 'NODE_NAME', 'valueFrom': { 'fieldRef': { 'fieldPath': 'metadata.name' } }, }, { 'name': 'node.name', 'value': QuotedStr('$(NODE_NAME).{}'.format( self.object_name( 'elasticsearch-service'))), }, { 'name': 'discovery.seed_hosts', 'value': ','.join([ '{}-{}.{}'.format( self.object_name( 'elasticsearch-statefulset' ), rpl, self.object_name( 'elasticsearch-service')) for rpl in range( self.option_get( 'config.elasticsearch.replicas' )) ]), }, { 'name': 'cluster.initial_master_nodes', 'value': ','.join([ '{}-{}.{}'.format( self.object_name( 'elasticsearch-statefulset' ), rpl, self.object_name( 'elasticsearch-service')) for rpl in range( self.option_get( 'config.elasticsearch.replicas' )) ]), }, { 'name': 'ES_JAVA_OPTS', 'value': '-Xms512m ' '-Xmx512m' }], 'resources': ValueData(value=self.option_get( 'kubernetes.resources.elasticsearch-statefulset' ), disabled_if_none=True), }], 'initContainers': [{ 'name': 'fix-permissions', 'image': 'busybox', 'command': [ 'sh', '-c', 'chown -R ' '1000:1000 ' '/usr/share/elasticsearch/data' ], 'securityContext': { 'privileged': True }, 'volumeMounts': [{ 'name': 'data', 'mountPath': '/usr/share/elasticsearch/data' }], }, { 'name': 'increase-vm-max-map', 'image': 'busybox', 'command': [ 'sysctl', '-w', 'vm.max_map_count=262144' ], 'securityContext': { 'privileged': True }, }, { 'name': 'increase-fd-ulimit', 'image': 'busybox', 'command': ['sh', '-c', 'ulimit -n ' '65536'], 'securityContext': { 'privileged': True }, }] } }, } }, name=self.BUILDITEM_ELASTICSEARCH_STATEFULSET, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'apps/v1', 'kind': 'DaemonSet', 'metadata': { 'name': self.object_name('fluentd-daemonset'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('fluentd-pod-label-app'), } }, 'spec': { 'selector': { 'matchLabels': { 'app': self.object_name('fluentd-pod-label-app'), } }, 'template': { 'metadata': { 'labels': { 'app': self.object_name('fluentd-pod-label-app'), } }, 'spec': { 'serviceAccount': self.object_name('service-account'), 'serviceAccountName': self.object_name('service-account'), 'tolerations': [{ 'key': 'node-role.kubernetes.io/master', 'effect': 'NoSchedule' }], 'containers': [{ 'name': 'fluentd', 'image': self.option_get('container.fluentd'), 'env': [ { 'name': 'FLUENT_ELASTICSEARCH_HOST', 'value': '{}.{}.svc.cluster.local'.format( self.object_name( 'elasticsearch-service'), self.namespace()), }, { 'name': 'FLUENT_ELASTICSEARCH_PORT', 'value': '9200' }, { 'name': 'FLUENT_ELASTICSEARCH_SCHEME', 'value': 'http' }, { 'name': 'FLUENTD_SYSTEMD_CONF', 'value': 'disable' }, ValueData(value={ 'name': 'FLUENT_CONTAINER_TAIL_PARSER_TYPE', 'value': '/^(?<time>.+) (?<stream>stdout|stderr) [^ ]* (?<log>.*)$/', }, enabled=self.kubragen. provider.provider == PROVIDER_K3D or self.kubragen.provider. provider == PROVIDER_K3S) ], 'volumeMounts': [{ 'name': 'varlog', 'mountPath': '/var/log' }, { 'name': 'varlibdockercontainers', 'mountPath': '/var/lib/docker/containers', 'readOnly': True }], 'resources': ValueData(value=self.option_get( 'kubernetes.resources.fluentd-daemonset' ), disabled_if_none=True), }], 'terminationGracePeriodSeconds': 30, 'volumes': [{ 'name': 'varlog', 'hostPath': { 'path': '/var/log' } }, { 'name': 'varlibdockercontainers', 'hostPath': { 'path': '/var/lib/docker/containers' } }] } } } }, name=self.BUILDITEM_FLUENTD_DAEMONSET, source=self.SOURCE_NAME, instance=self.basename()), ]) if self.option_get('enable.kibana'): ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': self.object_name('kibana-service'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('kibana-pod-label-app'), }, }, 'spec': { 'ports': [{ 'port': self.option_get('config.kibana.service_port'), 'targetPort': 5601, }], 'selector': { 'app': self.object_name('kibana-pod-label-app'), } } }, name=self.BUILDITEM_KIBANA_SERVICE, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': { 'name': self.object_name('kibana-deployment'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('kibana-pod-label-app'), } }, 'spec': { # 'replicas': 1, 'selector': { 'matchLabels': { 'app': self.object_name('kibana-pod-label-app'), } }, 'template': { 'metadata': { 'labels': { 'app': self.object_name( 'kibana-pod-label-app'), } }, 'spec': { 'containers': [{ 'name': 'kibana', 'image': self.option_get('container.kibana'), 'env': [{ 'name': 'ELASTICSEARCH_HOSTS', 'value': 'http://{}:9200'.format( self.object_name( 'elasticsearch-service')), }], 'ports': [{ 'containerPort': 5601 }], 'livenessProbe': ValueData(value={ 'httpGet': { 'path': '/api/status', 'port': 5601, }, 'initialDelaySeconds': 30, 'timeoutSeconds': 20, }, enabled=self.option_get( 'config.probes')), 'readinessProbe': ValueData(value={ 'httpGet': { 'path': '/api/status', 'port': 5601, }, 'initialDelaySeconds': 30, 'timeoutSeconds': 20, }, enabled=self.option_get( 'config.probes')), 'resources': ValueData(value=self.option_get( 'kubernetes.resources.kibana-deployment' ), disabled_if_none=True), }] } } } }, name=self.BUILDITEM_KIBANA_DEPLOYMENT, source=self.SOURCE_NAME, instance=self.basename()), ]) return ret
def internal_build_service(self) -> Sequence[ObjectItem]: ret = [ Object( { 'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': { 'name': self.object_name('deployment'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'replicas': 1, 'selector': { 'matchLabels': { 'app': self.object_name('pod-label-app'), } }, 'template': { 'metadata': { 'labels': { 'app': self.object_name('pod-label-app'), } }, 'spec': { 'serviceAccountName': self.object_name('service-account'), 'containers': [{ 'name': 'kube-resource-report', 'image': self.option_get( 'container.kube-resource-report'), 'args': [ '--update-interval-minutes=1', '--additional-cost-per-cluster=30.0', '/output' ], 'volumeMounts': [{ 'mountPath': '/output', 'name': 'report-data' }], 'securityContext': { 'readOnlyRootFilesystem': True, 'runAsNonRoot': True, 'runAsUser': 1000 }, 'resources': ValueData(value=self.option_get( 'kubernetes.resources.deployment'), disabled_if_none=True), }, { 'name': 'nginx', 'image': self.option_get('container.nginx'), 'volumeMounts': [{ 'mountPath': '/usr/share/nginx/html', 'name': 'report-data', 'readOnly': True }], 'ports': [{ 'containerPort': 80 }], 'readinessProbe': { 'httpGet': { 'path': '/', 'port': 80 } }, 'resources': ValueData(value=self.option_get( 'kubernetes.resources.deployment-nginx' ), disabled_if_none=True), }], 'volumes': [{ 'name': 'report-data', 'emptyDir': { 'sizeLimit': '500Mi' } }] } } } }, name=self.BUILDITEM_DEPLOYMENT, source=self.SOURCE_NAME, instance=self.basename()), Object( { 'apiVersion': 'v1', 'kind': 'Service', 'metadata': { 'name': self.object_name('service'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'selector': { 'app': self.object_name('pod-label-app'), }, 'type': 'ClusterIP', 'ports': [ { 'name': 'kube-resource-report-frontend', 'port': self.option_get('config.service_port'), 'protocol': 'TCP', 'targetPort': 80 } ] } }, name=self.BUILDITEM_SERVICE, source=self.SOURCE_NAME, instance=self.basename()), ] return ret
def internal_build_accesscontrol(self) -> Sequence[ObjectItem]: ret = [] if self.option_get( 'config.authorization.serviceaccount_create') is not False: ret.extend([ Object( { 'apiVersion': 'v1', 'kind': 'ServiceAccount', 'metadata': { 'name': self.object_name('service-account'), 'namespace': self.namespace(), } }, name=self.BUILDITEM_SERVICE_ACCOUNT, source=self.SOURCE_NAME, instance=self.basename()) ]) if self.option_get('config.authorization.roles_create') is not False: ret.extend([ Object( { 'kind': 'ClusterRole', 'apiVersion': 'rbac.authorization.k8s.io/v1', 'metadata': { 'name': self.object_name('cluster-role'), }, 'rules': [{ 'apiGroups': [''], 'resources': ['nodes', 'pods', 'namespaces', 'services'], 'verbs': ['get', 'list'] }, { 'apiGroups': ['networking.k8s.io'], 'resources': ['ingresses'], 'verbs': ['list'] }, { 'apiGroups': ['metrics.k8s.io'], 'resources': ['nodes', 'pods'], 'verbs': ['get', 'list'] }, { 'apiGroups': [''], 'resources': ['services/proxy'], 'resourceNames': ['heapster'], 'verbs': ['get'] }, { 'apiGroups': ['autoscaling.k8s.io'], 'resources': ['verticalpodautoscalers'], 'verbs': ['get', 'list'] }, { 'apiGroups': ['apps'], 'resources': [ 'deployments', 'statefulsets', 'replicasets', 'daemonsets' ], 'verbs': ['get', 'list'] }] }, name=self.BUILDITEM_CLUSTER_ROLE, source=self.SOURCE_NAME, instance=self.basename()) ]) if self.option_get('config.authorization.roles_bind') is not False: ret.extend([ Object( { 'apiVersion': 'rbac.authorization.k8s.io/v1', 'kind': 'ClusterRoleBinding', 'metadata': { 'name': self.object_name('cluster-role-binding'), }, 'roleRef': { 'apiGroup': 'rbac.authorization.k8s.io', 'kind': 'ClusterRole', 'name': self.object_name('cluster-role'), }, 'subjects': [{ 'kind': 'ServiceAccount', 'name': self.object_name('service-account'), 'namespace': self.namespace(), }] }, name=self.BUILDITEM_CLUSTER_ROLE_BINDING, source=self.SOURCE_NAME, instance=self.basename()) ]) return ret
def internal_build_service(self) -> Sequence[ObjectItem]: ret = [] ret.extend([ Object( { 'apiVersion': 'apps/v1', 'kind': 'DaemonSet', 'metadata': { 'name': self.object_name('daemonset'), 'namespace': self.namespace(), 'labels': { 'app': self.object_name('pod-label-app'), }, }, 'spec': { 'selector': { 'matchLabels': { 'app': self.object_name('pod-label-app'), } }, 'template': { 'metadata': { 'labels': { 'app': self.object_name('pod-label-app'), }, 'annotations': ValueData( { 'prometheus.io/scrape': QuotedStr('true'), 'prometheus.io/port': QuotedStr('http-metrics'), }, enabled=self.option_get( 'config.prometheus_annotation') is not False), }, 'spec': { 'serviceAccountName': self.object_name('service-account'), 'containers': [{ 'name': 'promtail', 'image': self.option_get('container.promtail'), 'args': [ '-config.file=/etc/promtail/promtail.yaml', ValueData( '-client.url={}/loki/api/v1/push'. format( self.option_get( 'config.loki_url')), enabled=self.option_get( 'config.loki_url') is not None), ], 'volumeMounts': [ { 'name': 'config', 'mountPath': '/etc/promtail' }, { 'name': 'run', 'mountPath': '/run/promtail' }, { 'mountPath': '/var/lib/docker/containers', 'name': 'docker', 'readOnly': True }, { 'mountPath': '/var/log/pods', 'name': 'pods', 'readOnly': True } ], 'env': [{ 'name': 'HOSTNAME', 'valueFrom': { 'fieldRef': { 'fieldPath': 'spec.nodeName' } }, }], 'ports': [{ 'containerPort': 3101, 'name': 'http-metrics' }], 'securityContext': { 'readOnlyRootFilesystem': True, 'runAsGroup': 0, 'runAsUser': 0 }, 'readinessProbe': { 'failureThreshold': 5, 'httpGet': { 'path': '/ready', 'port': 'http-metrics' }, 'initialDelaySeconds': 10, 'periodSeconds': 10, 'successThreshold': 1, 'timeoutSeconds': 1 }, 'resources': ValueData(value=self.option_get( 'kubernetes.resources.daemonset'), disabled_if_none=True), }], 'tolerations': [{ 'effect': 'NoSchedule', 'key': 'node-role.kubernetes.io/master', 'operator': 'Exists' }], 'volumes': [{ 'name': 'config', 'configMap': { 'name': self.object_name('config'), 'items': [{ 'key': 'promtail.yaml', 'path': 'promtail.yaml', }] } }, { 'name': 'run', 'hostPath': { 'path': '/run/promtail' } }, { 'hostPath': { 'path': '/var/lib/docker/containers' }, 'name': 'docker' }, { 'hostPath': { 'path': '/var/log/pods' }, 'name': 'pods' }] } } } }, name=self.BUILDITEM_DAEMONSET, source=self.SOURCE_NAME, instance=self.basename()), ]) return ret