import { Observable , throwError } from 'rxjs' ; import { ClusterCreateSettings , createClusterArgsFromSettings } from '../commands/createClusterSettings' ; import { EnsureMode , getOrInstallK3D } from '../installer/installer' ; import '../utils/array' ; import { Errorable , failed } from '../utils/errorable' ; import * as kubectl from '../utils/kubectl' ; import { logChannel } from '../utils/log' ; import * as shell from '../utils/shell' ; import { minDate } from '../utils/time' ; import { K3dClusterInfo , K3dRegistryInfo } from "./k3d.objectmodel" ; async function invokeK3DCommandObj < T > ( sh , command , args , fn ) { const k3dExe = getOrInstallK3D ( EnsureMode . Alert ) ; if ( failed ( k3dExe ) ) { return k3dExe ; } const exe = k3dExe . result ; const kubeconfig = await kubectl . getKubeconfigPath ( ) ; let opts = shell . defExecOpts ( ) ; opts . env [ "KUBECONFIG" ] = kubeconfig ; const cmd = `${ exe } ${ command } ${ args }` ; logChannel . appendLine ( `$ ${ cmd }` ) ; function andLog < T > ( fn ) { return ( s ) => { logChannel . appendLine ( strippedLines ( s ) . join ( "\n" ) ) ; return fn ( s ) ; } ; } return await sh . execObj < T > ( cmd , `${ exe } ${ command }` , opts , andLog ( fn ) ) ; } function invokeK3DCommandTracking ( sh , command , args , kubeconfig ? ) { const k3dExe = getOrInstallK3D ( EnsureMode . Alert ) ; if ( failed ( k3dExe ) ) { return throwError ( new Error ( k3dExe . error [ 0 ] ) ) ; } const exe = k3dExe . result ; let opts = shell . defExecOpts ( ) ; if ( kubeconfig ) { opts . env [ "KUBECONFIG" ] = kubeconfig ; } const cmd = [ ... ( command . split ( ' ' ) ) , ... args ] ; logChannel . appendLine ( `$ ${ exe } ${ cmd . join ( ' ' ) }` ) ; return sh . execTracking ( exe , cmd , opts ) ; } export function createCluster ( sh , settings , kubeconfig , switchContext = true ) { const args = createClusterArgsFromSettings ( settings , switchContext ) ; if ( settings . name ) { return invokeK3DCommandTracking ( sh , `cluster create ${ settings . name }` , args , kubeconfig ) ; } else { logChannel . appendLine ( `[ERROR] no cluster name provided in 'createCluster'` ) ; return throwError ( new Error ( `[ERROR] no cluster name provided in 'createCluster'` ) ) ; } } export function deleteCluster ( sh , clusterName ) { return invokeK3DCommandObj ( sh , 'cluster delete' , `${ clusterName }` , ( _ ) => null ) ; } export async function getClusters ( sh ) { function parse ( stdout ) { return JSON . parse ( stdout ) . map ( ( cluster ) => ( { name : cluster . name , nodes : cluster . nodes . map ( ( node ) => ( { name : node . name , network : node . Network , role : node . role , running : new String ( node . State . Running ) . trim ( ) . toLowerCase ( ) === 'true' , image : node . image , created : new Date ( node . created ) , cmd : node . Cmd } ) ) , agentsCount : cluster . agentsCount , agentsRunning : cluster . agentsRunning , serversCount : cluster . serversCount , serversRunning : cluster . serversRunning , hasLoadBalancer : new String ( cluster . hasLoadbalancer ) . trim ( ) . toLowerCase ( ) === 'true' , imageVolume : cluster . imageVolume , created : minDate ( cluster . nodes . map ( ( node ) => new Date ( node . created ) ) ) } ) ) . orderBy ( ( cluster ) => cluster . name ) ; } return invokeK3DCommandObj ( sh , 'cluster list -o json' , '' , parse ) ; } export async function getClusterInfo ( sh , clusterName ) { const clusters = await getClusters ( sh ) ; if ( clusters . succeeded ) { for ( const cluster of clusters . result ) { if ( cluster . name === clusterName ) { return { succeeded : true , result : cluster } ; } } } return { succeeded : false , error : [ `cluster ${ clusterName } not found` ] } ; } export async function getClustersNetworks ( sh ) { const clusters = await getClusters ( sh ) ; if ( ! clusters . succeeded ) { return clusters ; } let res = [ ] ; clusters . result . forEach ( ( cluster ) => res = res . concat ( cluster . nodes . map ( ( node ) => node . network ) ) ) ; res = res . filter ( ( thing , i , arr ) => arr . findIndex ( t => t === thing ) === i ) ; return { succeeded : true , result : res } ; } export async function getRegistries ( sh ) { function parse ( stdout ) { return JSON . parse ( stdout ) . map ( ( registry ) => ( { name : registry . name , network : registry . Network , created : new Date ( registry . created ) , status : registry . State . Status } ) ) . orderBy ( ( registry ) => registry . name ) ; } return invokeK3DCommandObj ( sh , 'registry list -o json' , '' , parse ) ; } export async function getKubeconfig ( sh , clusterName ) { return invokeK3DCommandObj ( sh , `kubeconfig get` , `${ clusterName }` , ( s ) => s ) ; } export async function addNodeTo ( sh , clusterName , nodeName , role ) { return invokeK3DCommandObj ( sh , `node create ${ nodeName } --cluster ${ clusterName } --role ${ role }` , `` , ( s ) => s ) ; } export async function deleteNodeFrom ( sh , clusterName , nodeName ) { return invokeK3DCommandObj ( sh , `node delete ${ nodeName }` , `` , ( s ) => s ) ; } export async function version ( sh ) { return invokeK3DCommandObj ( sh , `version` , '' , ( s ) => s . trim ( ) ) ; } export async function getCurrentCluster ( ) { const context = await kubectl . getContext ( ) ; return { succeeded : true , result : kubectl . getClusterForContext ( context ) } ; } export function strippedLines ( s ) { return s . split ( /\r?\n/ ) . map ( ( l ) => l . substring ( 20 ) ) . map ( ( l ) => l . trim ( ) ) . filter ( ( l ) => l . length > 0 ) ; } export function getClusterGrowServers ( clusterInfo ) { if ( clusterInfo . serversCount >= 2 ) { return true ; } if ( clusterInfo . nodes . filter ( ( node ) => node . role === "server" ) . map ( ( node ) => node . cmd . join ( " " ) ) . join ( " " ) . includes ( "cluster-init" ) ) { return true ; } return false ; }