UNPKG

@gati-framework/cli

Version:

CLI tool for Gati framework - create, develop, build and deploy cloud-native applications

360 lines 13.4 kB
/** * @module plugins/aws/eks * @description AWS EKS cluster management */ /** * Generate CloudFormation template for EKS cluster */ export function generateEKSClusterTemplate(config) { const template = { AWSTemplateFormatVersion: '2010-09-09', Description: `Gati EKS Cluster: ${config.clusterName}`, Parameters: { ClusterName: { Type: 'String', Default: config.clusterName, Description: 'Name of the EKS cluster', }, }, Resources: { ClusterSecurityGroup: { Type: 'AWS::EC2::SecurityGroup', Properties: { GroupDescription: `Security group for ${config.clusterName} EKS cluster`, VpcId: { 'Fn::ImportValue': `${config.clusterName}-VpcId` }, Tags: [ { Key: 'Name', Value: `${config.clusterName}-cluster-sg` }, { Key: 'kubernetes.io/cluster/' + config.clusterName, Value: 'owned' }, ], }, }, ClusterRole: { Type: 'AWS::IAM::Role', Properties: { RoleName: config.iam.clusterRoleName, AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: { Service: 'eks.amazonaws.com' }, Action: 'sts:AssumeRole', }, ], }, ManagedPolicyArns: [ 'arn:aws:iam::aws:policy/AmazonEKSClusterPolicy', 'arn:aws:iam::aws:policy/AmazonEKSVPCResourceController', ], }, }, EKSCluster: { Type: 'AWS::EKS::Cluster', DependsOn: ['ClusterRole'], Properties: { Name: config.clusterName, Version: config.version, RoleArn: { 'Fn::GetAtt': ['ClusterRole', 'Arn'] }, ResourcesVpcConfig: { SecurityGroupIds: [{ Ref: 'ClusterSecurityGroup' }], SubnetIds: { 'Fn::Split': [ ',', { 'Fn::Join': [ ',', [ { 'Fn::ImportValue': `${config.clusterName}-PublicSubnetIds` }, { 'Fn::ImportValue': `${config.clusterName}-PrivateSubnetIds` }, ], ], }, ], }, EndpointPublicAccess: true, EndpointPrivateAccess: true, }, Logging: config.logging ? { ClusterLogging: { EnabledTypes: config.logging.types.map((type) => ({ Type: type, })), }, } : undefined, Tags: config.tags ? Object.entries(config.tags).map(([Key, Value]) => ({ Key, Value })) : [], }, }, }, Outputs: { ClusterEndpoint: { Value: { 'Fn::GetAtt': ['EKSCluster', 'Endpoint'] }, Export: { Name: `${config.clusterName}-Endpoint` }, }, ClusterArn: { Value: { 'Fn::GetAtt': ['EKSCluster', 'Arn'] }, Export: { Name: `${config.clusterName}-Arn` }, }, ClusterSecurityGroupId: { Value: { Ref: 'ClusterSecurityGroup' }, Export: { Name: `${config.clusterName}-SecurityGroupId` }, }, }, }; return JSON.stringify(template, null, 2); } /** * Generate CloudFormation template for node group */ export function generateNodeGroupTemplate(clusterName, nodeGroup, nodeRoleName) { const template = { AWSTemplateFormatVersion: '2010-09-09', Description: `Node group ${nodeGroup.name} for cluster ${clusterName}`, Resources: { NodeSecurityGroup: { Type: 'AWS::EC2::SecurityGroup', Properties: { GroupDescription: `Security group for ${nodeGroup.name} node group`, VpcId: { 'Fn::ImportValue': `${clusterName}-VpcId` }, SecurityGroupIngress: [ { Description: 'Allow nodes to communicate with each other', IpProtocol: '-1', SourceSecurityGroupId: { Ref: 'NodeSecurityGroup' }, }, { Description: 'Allow pods to communicate with the cluster API Server', IpProtocol: 'tcp', FromPort: 443, ToPort: 443, SourceSecurityGroupId: { 'Fn::ImportValue': `${clusterName}-SecurityGroupId` }, }, ], SecurityGroupEgress: [ { Description: 'Allow all outbound traffic', IpProtocol: '-1', CidrIp: '0.0.0.0/0', }, ], Tags: [ { Key: 'Name', Value: `${clusterName}-${nodeGroup.name}-sg` }, { Key: 'kubernetes.io/cluster/' + clusterName, Value: 'owned' }, ], }, }, NodeRole: { Type: 'AWS::IAM::Role', Properties: { RoleName: `${nodeRoleName}-${nodeGroup.name}`, AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: { Service: 'ec2.amazonaws.com' }, Action: 'sts:AssumeRole', }, ], }, ManagedPolicyArns: [ 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy', 'arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy', 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly', ], }, }, NodeGroup: { Type: 'AWS::EKS::Nodegroup', DependsOn: ['NodeRole'], Properties: { ClusterName: clusterName, NodegroupName: nodeGroup.name, NodeRole: { 'Fn::GetAtt': ['NodeRole', 'Arn'] }, Subnets: { 'Fn::Split': [',', { 'Fn::ImportValue': `${clusterName}-PrivateSubnetIds` }], }, ScalingConfig: { MinSize: nodeGroup.minSize, MaxSize: nodeGroup.maxSize, DesiredSize: nodeGroup.desiredSize, }, DiskSize: nodeGroup.diskSize, InstanceTypes: [nodeGroup.instanceType], RemoteAccess: nodeGroup.sshKeyName ? { Ec2SshKey: nodeGroup.sshKeyName, SourceSecurityGroups: [{ Ref: 'NodeSecurityGroup' }], } : undefined, Labels: nodeGroup.labels, Taints: nodeGroup.taints, Tags: { Name: `${clusterName}-${nodeGroup.name}`, [`kubernetes.io/cluster/${clusterName}`]: 'owned', }, }, }, }, Outputs: { NodeGroupArn: { Value: { 'Fn::GetAtt': ['NodeGroup', 'Arn'] }, Export: { Name: `${clusterName}-${nodeGroup.name}-Arn` }, }, NodeSecurityGroupId: { Value: { Ref: 'NodeSecurityGroup' }, Export: { Name: `${clusterName}-${nodeGroup.name}-SecurityGroupId` }, }, }, }; return JSON.stringify(template, null, 2); } /** * Generate kubeconfig file content */ export function generateKubeconfig(clusterName, endpoint, certificateAuthority, region) { return `apiVersion: v1 kind: Config clusters: - cluster: server: ${endpoint} certificate-authority-data: ${certificateAuthority} name: ${clusterName} contexts: - context: cluster: ${clusterName} user: ${clusterName} name: ${clusterName} current-context: ${clusterName} users: - name: ${clusterName} user: exec: apiVersion: client.authentication.k8s.io/v1beta1 command: aws args: - eks - get-token - --cluster-name - ${clusterName} - --region - ${region} `; } /** * Validate EKS cluster configuration */ export function validateEKSConfig(config) { const errors = []; // Validate cluster name if (!config.clusterName || config.clusterName.length === 0) { errors.push('Cluster name is required'); } if (config.clusterName.length > 100) { errors.push('Cluster name must be 100 characters or less'); } // Validate version const validVersions = ['1.28', '1.29', '1.30', '1.31']; if (!validVersions.includes(config.version)) { errors.push(`Invalid Kubernetes version: ${config.version}. Supported: ${validVersions.join(', ')}`); } // Validate node groups if (!config.nodeGroups || config.nodeGroups.length === 0) { errors.push('At least one node group is required'); } config.nodeGroups.forEach((ng, index) => { if (!ng.name) { errors.push(`Node group ${index + 1}: name is required`); } if (ng.minSize < 1) { errors.push(`Node group ${ng.name}: minSize must be at least 1`); } if (ng.maxSize < ng.minSize) { errors.push(`Node group ${ng.name}: maxSize must be >= minSize`); } if (ng.desiredSize < ng.minSize || ng.desiredSize > ng.maxSize) { errors.push(`Node group ${ng.name}: desiredSize must be between minSize and maxSize`); } if (ng.diskSize < 20) { errors.push(`Node group ${ng.name}: diskSize must be at least 20 GB`); } }); // Validate IAM configuration if (!config.iam.clusterRoleName) { errors.push('Cluster role name is required'); } if (!config.iam.nodeGroupRoleName) { errors.push('Node group role name is required'); } return { valid: errors.length === 0, errors, }; } /** * Get default EKS cluster configuration */ export function getDefaultEKSConfig(clusterName, region) { return { clusterName, region, version: '1.30', vpc: { cidr: '10.0.0.0/16', availabilityZones: [`${region}a`, `${region}b`], publicSubnets: ['10.0.1.0/24', '10.0.2.0/24'], privateSubnets: ['10.0.10.0/24', '10.0.11.0/24'], enableNat: true, }, nodeGroups: [ { name: 'default', instanceType: 't3.medium', minSize: 2, maxSize: 5, desiredSize: 2, diskSize: 20, }, ], iam: { clusterRoleName: `${clusterName}-cluster-role`, nodeGroupRoleName: `${clusterName}-node-role`, }, logging: { types: ['api', 'audit', 'authenticator'], }, tags: { Environment: 'production', ManagedBy: 'Gati', }, }; } /** * Simulate deployment status (would be replaced with actual AWS SDK calls) */ export async function getDeploymentStatus(clusterName, _options) { // This would make actual AWS API calls in production // For now, return mock status await new Promise((resolve) => setTimeout(resolve, 0)); return [ { type: 'vpc', id: 'vpc-1234567890', name: `${clusterName}-vpc`, status: 'active', message: 'VPC is active', createdAt: new Date(), }, { type: 'eks-cluster', id: `${clusterName}`, name: clusterName, status: 'creating', message: 'Cluster is being created', }, ]; } //# sourceMappingURL=eks.js.map