import { Uri , FileSystemProvider , FileType , FileStat , FileChangeEvent , Event , EventEmitter , Disposable } from 'vscode' ; import * as path from 'path' ; import * as fs from 'fs' ; import * as querystring from 'querystring' ; import { Kubectl } from './kubectl' ; import { Host } from './host' ; import { helmSyntaxVersion , HelmSyntaxVersion , helmInvokeCommandWithFeedback } from './helm.exec' ; import * as config from './components/config/config' ; import { ExecResult } from './binutilplusplus' ; import { Errorable } from './errorable' ; export const K8S_RESOURCE_SCHEME = "k8smsx" ; export const K8S_RESOURCE_SCHEME_READONLY = "k8smsxro" ; export const KUBECTL_RESOURCE_AUTHORITY = "loadkubernetescore" ; export const KUBECTL_DESCRIBE_AUTHORITY = "kubernetesdescribe" ; export const HELM_RESOURCE_AUTHORITY = "helmget" ; export function kubefsUri ( namespace , value , outputFormat , action ? ) { const docname = `${ value . replace ( '/' , '-' ) }${ outputFormat !== '' ? '.' + outputFormat : '' }` ; const nonce = new Date ( ) . getTime ( ) ; const nsquery = namespace ? `ns=${ namespace }&` : '' ; const scheme = action === 'describe' ? K8S_RESOURCE_SCHEME_READONLY : K8S_RESOURCE_SCHEME ; const authority = action === 'describe' ? KUBECTL_DESCRIBE_AUTHORITY : KUBECTL_RESOURCE_AUTHORITY ; const uri = `${ scheme }://${ authority }/${ docname }?${ nsquery }value=${ value }&_=${ nonce }` ; return Uri . parse ( uri ) ; } export class KubernetesResourceVirtualFileSystemProvider implements FileSystemProvider { constructor ( private readonly kubectl , private readonly host ) { } private readonly onDidChangeFileEmitter : EventEmitter < FileChangeEvent [ ] > = new EventEmitter < FileChangeEvent [ ] > ( ) ; onDidChangeFile : Event < FileChangeEvent [ ] > = this . onDidChangeFileEmitter . event ; watch ( _uri , _options ) { return new Disposable ( ( ) => { } ) ; } stat ( _uri ) { return { type : FileType . File , ctime : 0 , mtime : 0 , size : 65536 } ; } readDirectory ( _uri ) { return [ ] ; } createDirectory ( _uri ) { } readFile ( uri ) { return this . readFileAsync ( uri ) ; } async readFileAsync ( uri ) { const content = await this . loadResource ( uri ) ; return new Buffer ( content , 'utf8' ) ; } async loadResource ( uri ) { const query = querystring . parse ( uri . query ) ; const outputFormat = config . getOutputFormat ( ) ; const value = query . value as string ; const revision = query . revision as string | undefined ; const ns = query . ns as string | undefined ; const resourceAuthority = uri . authority ; const eer = await this . execLoadResource ( resourceAuthority , ns , value , revision , outputFormat ) ; if ( Errorable . failed ( eer ) ) { this . host . showErrorMessage ( eer . error [ 0 ] ) ; throw eer . error [ 0 ] ; } const er = eer . result ; if ( ExecResult . failed ( er ) ) { const message = ExecResult . failureMessage ( er , { whatFailed : 'Get command failed' } ) ; if ( er . resultKind === 'exec-bin-not-found' ) { this . kubectl . promptInstallDependencies ( er , message ) ; } else { this . host . showErrorMessage ( message ) ; } throw message ; } return er . stdout ; } async execLoadResource ( resourceAuthority , ns , value , revision , outputFormat ) { const nsarg = ns ? `--namespace ${ ns }` : '' ; switch ( resourceAuthority ) { case KUBECTL_RESOURCE_AUTHORITY : const ker = await this . kubectl . invokeCommandWithFeedback ( `-o ${ outputFormat } ${ nsarg } get ${ value }` , `Loading ${ value }...` ) ; return { succeeded : true , result : ker } ; case HELM_RESOURCE_AUTHORITY : const scopearg = ( ( await helmSyntaxVersion ( ) ) === HelmSyntaxVersion . V2 ) ? '' : 'all' ; const revarg = revision ? ` --revision=${ revision }` : '' ; const her = await helmInvokeCommandWithFeedback ( `get ${ scopearg } ${ value }${ revarg }` , `Loading ${ value }...` ) ; return { succeeded : true , result : her } ; case KUBECTL_DESCRIBE_AUTHORITY : const describe = await this . kubectl . invokeCommandWithFeedback ( `describe ${ value } ${ nsarg }` , `Loading ${ value }...` ) ; return { succeeded : true , result : describe } ; default : return { succeeded : false , error : [ `Internal error: please raise an issue with the error code InvalidObjectLoadURI and report authority ${ resourceAuthority }.` ] } ; } } writeFile ( uri , content , _options ) { return this . saveAsync ( uri , content ) ; } private async saveAsync ( uri , content ) { const rootPath = await this . host . selectRootFolder ( ) ; if ( ! rootPath ) { return ; } const fspath = path . join ( rootPath , uri . fsPath ) ; fs . writeFileSync ( fspath , content ) ; } delete ( _uri , _options ) { } rename ( _oldUri , _newUri , _options ) { } }