diff --git a/client/src/app/ctl/document/document.component.css b/client/src/app/ctl/document/document.component.css index 1537b5e..5c55609 100644 --- a/client/src/app/ctl/document/document.component.css +++ b/client/src/app/ctl/document/document.component.css @@ -19,6 +19,15 @@ width: 20px; } +.docless-phase { + padding-left: 20px; +} + +.docless-phase-btn { + padding-left: 20px; + padding-right: 0px; +} + .phase-tree-invisible { display: none; } diff --git a/client/src/app/ctl/document/document.component.html b/client/src/app/ctl/document/document.component.html index 175fd87..0194e66 100644 --- a/client/src/app/ctl/document/document.component.html +++ b/client/src/app/ctl/document/document.component.html @@ -17,10 +17,20 @@ {{node.name}} -
- +
+ + +
diff --git a/client/src/app/ctl/document/document.component.ts b/client/src/app/ctl/document/document.component.ts index 350d6f4..e28d63b 100644 --- a/client/src/app/ctl/document/document.component.ts +++ b/client/src/app/ctl/document/document.component.ts @@ -69,9 +69,6 @@ export class DocumentComponent implements WSReceiver { case 'getPhaseTree': this.handleGetPhaseTree(message.data); break; - case 'getPhaseDocs': - this.handleGetPhaseDocs(message); - break; case 'getYaml': this.handleGetYaml(message); break; @@ -91,13 +88,6 @@ export class DocumentComponent implements WSReceiver { this.dataSource.data = this.phaseTree; } - handleGetPhaseDocs(message: WebsocketMessage): void { - const tmp: KustomNode[] = []; - Object.assign(tmp, message.data); - this.cache[message.id] = tmp; - console.dir(this.cache[message.id]); - } - handleGetYaml(message: WebsocketMessage): void { this.changeEditorContents((message.yaml)); this.setTitle(message.name); @@ -118,12 +108,6 @@ export class DocumentComponent implements WSReceiver { this.editorTitle = str[str.length - 1]; } - refreshTreeData(): void { - const tmpdata = this.dataSource.data; - this.dataSource.data = null; - this.dataSource.data = tmpdata; - } - changeEditorContents(yaml: string): void { this.code = atob(yaml); } @@ -142,12 +126,6 @@ export class DocumentComponent implements WSReceiver { this.websocketService.sendMessage(websocketMessage); } - getPhaseDocs(id: string): void { - const websocketMessage = this.constructDocumentWsMessage('getPhaseDocs'); - websocketMessage.id = id; - this.websocketService.sendMessage(websocketMessage); - } - viewPhaseDocs(id: string): void { // show document viewer } diff --git a/client/src/app/ctl/document/document.models.ts b/client/src/app/ctl/document/document.models.ts index 53ccf71..6a152f5 100644 --- a/client/src/app/ctl/document/document.models.ts +++ b/client/src/app/ctl/document/document.models.ts @@ -1,5 +1,6 @@ export class KustomNode { id: string; + phaseid: { name: string, namespace: string}; name: string; canLoadChildren: boolean; children: KustomNode[]; diff --git a/go.mod b/go.mod index 11d2567..afd710d 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,12 @@ require ( github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.0.0 github.com/stretchr/testify v1.6.1 - opendev.org/airship/airshipctl v0.0.0-20200812155702-f61953bcf558 + opendev.org/airship/airshipctl v0.0.0-20200917132506-1660efc23150 sigs.k8s.io/kustomize/api v0.5.1 ) replace ( k8s.io/client-go => k8s.io/client-go v0.0.0-20191114101535-6c5935290e33 k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd + sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.4.1 ) diff --git a/go.sum b/go.sum index 67827c6..c79d7f2 100644 --- a/go.sum +++ b/go.sum @@ -512,6 +512,7 @@ github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEo github.com/gophercloud/gophercloud v0.6.0 h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU= github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU= github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= @@ -627,6 +628,7 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/jsonnet-bundler/jsonnet-bundler v0.2.0/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -645,10 +647,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -940,8 +944,10 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1300,6 +1306,8 @@ golang.org/x/tools v0.0.0-20200327195553-82bb89366a1e/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk= golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb h1:/7SQoPdMxZ0c/Zu9tBJgMbRE/BmK6i9QXflNJXKAmw0= +golang.org/x/tools v0.0.0-20200619210111-0f592d2728bb/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -1363,6 +1371,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1521,16 +1530,16 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= -opendev.org/airship/airshipctl v0.0.0-20200812155702-f61953bcf558 h1:nCR2asZynFP5/7pLmSLBBdEMrL1mkMkfTd2lMsL8zuc= -opendev.org/airship/airshipctl v0.0.0-20200812155702-f61953bcf558/go.mod h1:x6OuTS7vmRVbNtPRqwVAqS1YuBvySsvWyVr6dvxq/Ic= +opendev.org/airship/airshipctl v0.0.0-20200917132506-1660efc23150 h1:tPr3sCzRipDWdRbIEWjr76x93MrwZRdk6Qt/5f4d6wg= +opendev.org/airship/airshipctl v0.0.0-20200917132506-1660efc23150/go.mod h1:VkcG7mjbe9zpyAgsAR8iLDpiJzofh9wqtteUtKhufYw= opendev.org/airship/go-redfish v0.0.0-20200318103738-db034d1d753a h1:4ggAMTwpfu/w3ZXOIJ9tfYF37JIYn+eNCA4O10NduZ0= opendev.org/airship/go-redfish v0.0.0-20200318103738-db034d1d753a/go.mod h1:FEjYcb3bYBWGpQIqtvVM0NrT5eyjlCOCj5JNf4lI+6s= opendev.org/airship/go-redfish/client v0.0.0-20200318103738-db034d1d753a h1:S1dmsP5Cc6OQjAd6OgIKMcNPBiGjh5TDbijVjNE/VGU= opendev.org/airship/go-redfish/client v0.0.0-20200318103738-db034d1d753a/go.mod h1:s0hwuUpBsRXOrhN0NR+fNVivXGyWgHKpqtyq7qYjpew= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= -sigs.k8s.io/cli-utils v0.15.0 h1:QiGX8wfBaegKQhejZg2EsqCPYGtyavIpEjNTMdpzUlY= -sigs.k8s.io/cli-utils v0.15.0/go.mod h1:H35YA5iJIM7EVNgqDTjX2dgt4wE23zmnXOTSTlyD+PE= +sigs.k8s.io/cli-utils v0.18.1 h1:K4usJmMlI98mL+z+TdAnKfzng64/m8bRXZKPwy3ZCWw= +sigs.k8s.io/cli-utils v0.18.1/go.mod h1:B7KdqkSkHNIUn3cFbaR4aKUZMKtr+Benboi1w/HW/Fg= sigs.k8s.io/cluster-api v0.3.5 h1:XPCuwrGL73x82a6spCHwkHHeGiQF+L4zntaoDg2qMzo= sigs.k8s.io/cluster-api v0.3.5/go.mod h1:IoP66q4g92I/2f/9hltbE/FWG3RakIwRdYpY+6mqvtE= sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= @@ -1541,10 +1550,8 @@ sigs.k8s.io/controller-tools v0.2.8/go.mod h1:9VKHPszmf2DHz/QmHkcfZoewO6BL7pPs9u sigs.k8s.io/kind v0.7.1-0.20200303021537-981bd80d3802/go.mod h1:HIZ3PWUezpklcjkqpFbnYOqaqsAE1JeCTEwkgvPLXjk= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/kustomize/api v0.3.1/go.mod h1:A+ATnlHqzictQfQC1q3KB/T6MSr0UWQsrrLxMWkge2E= sigs.k8s.io/kustomize/api v0.5.1 h1:iHGTs5LcnJGqHstUSxWD/kX6XZgmd82x79LLlZwDU0I= sigs.k8s.io/kustomize/api v0.5.1/go.mod h1:LGqJ9ZWOnWDqlECqrFgNUyEqSJc6ooA9ZiWZ4KFZv+I= -sigs.k8s.io/kustomize/kyaml v0.1.4/go.mod h1:461i94nj0h0ylJ6w83jLkR4SqqVhn1iY6fjD0JSTQeE= sigs.k8s.io/kustomize/kyaml v0.4.1 h1:NEqA/35upoAjb+I5vh1ODUqxoX4DOrezeQa9BhhG5Co= sigs.k8s.io/kustomize/kyaml v0.4.1/go.mod h1:XJL84E6sOFeNrQ7CADiemc1B0EjIxHo3OhW4o1aJYNw= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/pkg/configs/configs.go b/pkg/configs/configs.go index 51caf6e..2065dd7 100644 --- a/pkg/configs/configs.go +++ b/pkg/configs/configs.go @@ -106,18 +106,16 @@ const ( Validate WsSubComponentType = "validate" // ctl components - GetDefaults WsSubComponentType = "getDefaults" - GenerateISO WsSubComponentType = "generateISO" - DocPull WsSubComponentType = "docPull" - Yaml WsSubComponentType = "yaml" - YamlWrite WsSubComponentType = "yamlWrite" - GetYaml WsSubComponentType = "getYaml" - GetSource WsSubComponentType = "getSource" - GetRendered WsSubComponentType = "getRendered" - GetPhaseTree WsSubComponentType = "getPhaseTree" - GetPhaseSourceFiles WsSubComponentType = "getPhaseSource" - GetPhaseDocuments WsSubComponentType = "getPhaseDocs" - GetTarget WsSubComponentType = "getTarget" + GetDefaults WsSubComponentType = "getDefaults" + GenerateISO WsSubComponentType = "generateISO" + DocPull WsSubComponentType = "docPull" + Yaml WsSubComponentType = "yaml" + YamlWrite WsSubComponentType = "yamlWrite" + GetYaml WsSubComponentType = "getYaml" + GetSource WsSubComponentType = "getSource" + GetRendered WsSubComponentType = "getRendered" + GetPhaseTree WsSubComponentType = "getPhaseTree" + GetTarget WsSubComponentType = "getTarget" ) // WsMessage is a request / return structure used for websockets @@ -143,11 +141,9 @@ type WsMessage struct { Authentication *Authentication `json:"authentication,omitempty"` // information related to the init of the UI - Dashboards []Dashboard `json:"dashboards,omitempty"` - AuthMethod *AuthMethod `json:"authMethod,omitempty"` - AuthInfoOptions *config.AuthInfoOptions `json:"authInfoOptions,omitempty"` - ContextOptions *config.ContextOptions `json:"contextOptions,omitempty"` - ClusterOptions *config.ClusterOptions `json:"clusterOptions,omitempty"` + Dashboards []Dashboard `json:"dashboards,omitempty"` + AuthMethod *AuthMethod `json:"authMethod,omitempty"` + ContextOptions *config.ContextOptions `json:"contextOptions,omitempty"` } // SetUIConfig sets the UIConfig object with values obtained from diff --git a/pkg/ctl/airshipctl.go b/pkg/ctl/airshipctl.go index 05ebd3d..af2c161 100644 --- a/pkg/ctl/airshipctl.go +++ b/pkg/ctl/airshipctl.go @@ -15,13 +15,21 @@ package ctl import ( - "opendev.org/airship/airshipctl/pkg/environment" + "opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipctl/pkg/log" "opendev.org/airship/airshipui/pkg/configs" uiLog "opendev.org/airship/airshipui/pkg/log" "opendev.org/airship/airshipui/pkg/webservice" ) +// AirshipConfigPath location of airship config (default $HOME/.airship.config) +// TODO(mfuller): are we going to retrieve these from the environment / cli options? +// leaving them both unset (nil) for now so that the default locations will be used +var AirshipConfigPath *string + +// KubeConfigPath location of kubeconfig used by airshipctl (default $HOME/.airship/kubeconfig) +var KubeConfigPath *string + // CTLFunctionMap is a function map for the CTL functions that is referenced in the webservice var CTLFunctionMap = map[configs.WsComponentType]func(configs.WsMessage) configs.WsMessage{ configs.Baremetal: HandleBaremetalRequest, @@ -34,7 +42,8 @@ var runningRequests map[configs.WsSubComponentType]bool = make(map[configs.WsSub // Client provides a library of functions that enable external programs (e.g. Airship UI) to perform airshipctl // functionality in exactly the same manner as the CLI. type Client struct { - settings *environment.AirshipCTLSettings + Config *config.Config + Debug bool // this is a placeholder until I figure out how / where to set this in airshipctl } // LogInterceptor is just a struct to hold a pointer to the remote channel @@ -52,31 +61,36 @@ func Init() { } // NewDefaultClient initializes the airshipctl client for external usage with default logging. -func NewDefaultClient() *Client { - settings := &environment.AirshipCTLSettings{} - // ensure no error if airship config doesn't exist - settings.Create = true - settings.InitConfig() +func NewDefaultClient(airshipConfigPath, kubeConfigPath *string) (*Client, error) { + cfgFactory := config.CreateFactory(airshipConfigPath, kubeConfigPath) - client := &Client{ - settings: settings, + conf, err := cfgFactory() + if err != nil { + return nil, err } - // set verbosity to true - client.settings.Debug = true + client := &Client{ + Config: conf, + } - return client + // TODO(mfuller): how do you do this now? + // set verbosity to true + + return client, nil } // NewClient initializes the airshipctl client for external usage with the logging overridden. -func NewClient(request configs.WsMessage) *Client { - client := NewDefaultClient() +func NewClient(airshipConfigPath, kubeConfigPath *string, request configs.WsMessage) (*Client, error) { + client, err := NewDefaultClient(airshipConfigPath, kubeConfigPath) + if err != nil { + return nil, err + } // init the interceptor to send messages to the UI // TODO: Unsure how this will be handled with overlapping runs - log.Init(client.settings.Debug, NewLogInterceptor(request)) + log.Init(client.Debug, NewLogInterceptor(request)) - return client + return client, nil } // NewLogInterceptor will construct a channel writer for use with the logger diff --git a/pkg/ctl/baremetal.go b/pkg/ctl/baremetal.go index 0c12f87..ce46ce6 100644 --- a/pkg/ctl/baremetal.go +++ b/pkg/ctl/baremetal.go @@ -18,6 +18,7 @@ import ( "fmt" "opendev.org/airship/airshipctl/pkg/bootstrap/isogen" + "opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipui/pkg/configs" ) @@ -32,13 +33,19 @@ func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage { var err error var message string + + client, err := NewClient(AirshipConfigPath, KubeConfigPath, request) + if err != nil { + response.Error = err.Error() + return response + } + subComponent := request.SubComponent switch subComponent { case configs.GenerateISO: // since this is long running cache it up // TODO: Test before running the geniso runningRequests[subComponent] = true - client := NewClient(request) message, err = client.generateIso() // now that we're done forget we did anything delete(runningRequests, subComponent) @@ -57,7 +64,8 @@ func HandleBaremetalRequest(request configs.WsMessage) configs.WsMessage { func (c *Client) generateIso() (string, error) { var message string - err := isogen.GenerateBootstrapIso(c.settings) + cfgFactory := config.CreateFactory(AirshipConfigPath, KubeConfigPath) + err := isogen.GenerateBootstrapIso(cfgFactory) if err == nil { message = fmt.Sprintf("Success") } diff --git a/pkg/ctl/baremetal_test.go b/pkg/ctl/baremetal_test.go index bf506ae..434240e 100644 --- a/pkg/ctl/baremetal_test.go +++ b/pkg/ctl/baremetal_test.go @@ -28,6 +28,12 @@ func TestHandleUnknownBaremetalSubComponent(t *testing.T) { SubComponent: "fake_subcomponent", } + acp := "testdata/testairshipconfig" + kcp := "testdata/testkubeconfig" + + AirshipConfigPath = &acp + KubeConfigPath = &kcp + response := HandleBaremetalRequest(request) expected := configs.WsMessage{ diff --git a/pkg/ctl/document.go b/pkg/ctl/document.go index 1fdda89..8ee2c0c 100644 --- a/pkg/ctl/document.go +++ b/pkg/ctl/document.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" + "opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipctl/pkg/document" "opendev.org/airship/airshipctl/pkg/document/pull" "opendev.org/airship/airshipui/pkg/configs" @@ -42,7 +43,11 @@ func HandleDocumentRequest(request configs.WsMessage) configs.WsMessage { var message string var id string - client := NewClient(request) + client, err := NewClient(AirshipConfigPath, KubeConfigPath, request) + if err != nil { + response.Error = err.Error() + return response + } switch request.SubComponent { case configs.DocPull: @@ -56,12 +61,6 @@ func HandleDocumentRequest(request configs.WsMessage) configs.WsMessage { response.Name, response.YAML, err = client.getYaml(id) case configs.GetPhaseTree: response.Data, err = client.GetPhaseTree() - case configs.GetPhaseDocuments: - id = request.ID - response.Data, err = GetPhaseDocuments(request.ID) - case configs.GetPhaseSourceFiles: - id = request.ID - response.Data, err = client.GetPhaseSourceFiles(request.ID) case configs.GetTarget: message = client.getTarget() default: @@ -79,7 +78,7 @@ func HandleDocumentRequest(request configs.WsMessage) configs.WsMessage { } func (c *Client) getTarget() string { - m, err := c.settings.Config.CurrentContextManifest() + m, err := c.Config.CurrentContextManifest() if err != nil { return "unknown" } @@ -110,7 +109,7 @@ func getDocumentYaml(doc document.Document) (string, string, error) { } func (c *Client) getFileYaml(path string) (string, string, error) { - ccm, err := c.settings.Config.CurrentContextManifest() + ccm, err := c.Config.CurrentContextManifest() if err != nil { return "", "", err } @@ -163,8 +162,8 @@ func (c *Client) writeYamlFile(id, yaml64 string) (string, string, error) { func (c *Client) docPull() (string, error) { var message string - settings := pull.Settings{AirshipCTLSettings: c.settings} - err := settings.Pull() + cfgFactory := config.CreateFactory(AirshipConfigPath, KubeConfigPath) + err := pull.Pull(cfgFactory) if err == nil { message = fmt.Sprintf("Success") } diff --git a/pkg/ctl/document_test.go b/pkg/ctl/document_test.go index af5701e..6996a38 100644 --- a/pkg/ctl/document_test.go +++ b/pkg/ctl/document_test.go @@ -28,6 +28,12 @@ func TestHandleUnknownDocumentSubComponent(t *testing.T) { SubComponent: "fake_subcomponent", } + acp := "testdata/testairshipconfig" + kcp := "testdata/testkubeconfig" + + AirshipConfigPath = &acp + KubeConfigPath = &kcp + response := HandleDocumentRequest(request) expected := configs.WsMessage{ diff --git a/pkg/ctl/testdata/testairshipconfig b/pkg/ctl/testdata/testairshipconfig new file mode 100644 index 0000000..df5ab2f --- /dev/null +++ b/pkg/ctl/testdata/testairshipconfig @@ -0,0 +1,37 @@ +apiVersion: airshipit.org/v1alpha1 +contexts: + dummy_context: + contextKubeconf: dummy_cluster_ephemeral + encryptionConfig: dummy_encryption_config + managementConfiguration: dummy_management_config + manifest: dummy_manifest +currentContext: dummy_context +encryptionConfigs: + dummy_encryption_config: + decryptionKeyPath: /tmp/decryption.pub + encryptionKeyPath: /tmp/encryption.key +kind: Config +managementConfiguration: + dummy_management_config: + insecure: true + type: redfish +manifests: + dummy_manifest: + metadataPath: manifests/site/test-site/metadata.yaml + primaryRepositoryName: primary + repositories: + primary: + auth: + sshKey: testdata/test-key.pem + type: ssh-key + checkout: + branch: "" + commitHash: "" + force: false + tag: v1.0.1 + url: http://dummy.url.com/manifests.git + subPath: manifests/site/test-site + targetPath: /var/tmp/ +permissions: + DirectoryPermission: 488 + FilePermission: 416 diff --git a/pkg/ctl/testdata/testkubeconfig b/pkg/ctl/testdata/testkubeconfig new file mode 100644 index 0000000..2cf3ee4 --- /dev/null +++ b/pkg/ctl/testdata/testkubeconfig @@ -0,0 +1,57 @@ +apiVersion: v1 +clusters: +- cluster: + insecure-skip-tls-verify: true + server: http://5.6.7.8 + name: def_ephemeral +- cluster: + insecure-skip-tls-verify: true + server: http://1.2.3.4 + name: def_target +- cluster: + insecure-skip-tls-verify: true + server: http://9.10.11.12 + name: onlyinkubeconf_target +- cluster: + certificate-authority: cert_file + server: "" + name: wrongonlyinkubeconf_target +- cluster: + insecure-skip-tls-verify: true + server: http://9.10.11.12 + name: invalidName +- cluster: + insecure-skip-tls-verify: true + server: http://9.10.11.12 + name: clustertypenil_target +contexts: +- context: + cluster: def_ephemeral + user: k-admin + name: def_ephemeral +- context: + cluster: def_target + user: k-admin + name: def_target +- context: + cluster: onlyinkubeconf_target + user: k-other + name: onlyink +current-context: "" +kind: Config +preferences: {} +users: +users: +- name: def-user + user: + username: dummy_username + password: ZHVtbXlfcGFzc3dvcmQK +- name: k-admin + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= +- name: k-other + user: + client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJQXhEdzk2RUY4SXN3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB4T1RBNU1qa3hOekF6TURsYUZ3MHlNREE1TWpneE56QXpNVEphTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXV6R0pZdlBaNkRvaTQyMUQKSzhXSmFaQ25OQWQycXo1cC8wNDJvRnpRUGJyQWd6RTJxWVZrek9MOHhBVmVSN1NONXdXb1RXRXlGOEVWN3JyLwo0K0hoSEdpcTVQbXF1SUZ5enpuNi9JWmM4alU5eEVmenZpa2NpckxmVTR2UlhKUXdWd2dBU05sMkFXQUloMmRECmRUcmpCQ2ZpS1dNSHlqMFJiSGFsc0J6T3BnVC9IVHYzR1F6blVRekZLdjJkajVWMU5rUy9ESGp5UlJKK0VMNlEKQlltR3NlZzVQNE5iQzllYnVpcG1NVEFxL0p1bU9vb2QrRmpMMm5acUw2Zkk2ZkJ0RjVPR2xwQ0IxWUo4ZnpDdApHUVFaN0hUSWJkYjJ0cDQzRlZPaHlRYlZjSHFUQTA0UEoxNSswV0F5bVVKVXo4WEE1NDRyL2J2NzRKY0pVUkZoCmFyWmlRd0lEQVFBQm95Y3dKVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMMmhIUmVibEl2VHJTMFNmUVg1RG9ueVVhNy84aTg1endVWApSd3dqdzFuS0U0NDJKbWZWRGZ5b0hRYUM4Ti9MQkxyUXM0U0lqU1JYdmFHU1dSQnRnT1RRV21Db1laMXdSbjdwCndDTXZQTERJdHNWWm90SEZpUFl2b1lHWFFUSXA3YlROMmg1OEJaaEZ3d25nWUovT04zeG1rd29IN1IxYmVxWEYKWHF1TTluekhESk41VlZub1lQR09yRHMwWlg1RnNxNGtWVU0wVExNQm9qN1ZIRDhmU0E5RjRYNU4yMldsZnNPMAo4aksrRFJDWTAyaHBrYTZQQ0pQS0lNOEJaMUFSMG9ZakZxT0plcXpPTjBqcnpYWHh4S2pHVFVUb1BldVA5dCtCCjJOMVA1TnI4a2oxM0lrend5Q1NZclFVN09ZM3ltZmJobHkrcXZxaFVFa014MlQ1SkpmQT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= + client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBdXpHSll2UFo2RG9pNDIxREs4V0phWkNuTkFkMnF6NXAvMDQyb0Z6UVBickFnekUyCnFZVmt6T0w4eEFWZVI3U041d1dvVFdFeUY4RVY3cnIvNCtIaEhHaXE1UG1xdUlGeXp6bjYvSVpjOGpVOXhFZnoKdmlrY2lyTGZVNHZSWEpRd1Z3Z0FTTmwyQVdBSWgyZERkVHJqQkNmaUtXTUh5ajBSYkhhbHNCek9wZ1QvSFR2MwpHUXpuVVF6Rkt2MmRqNVYxTmtTL0RIanlSUkorRUw2UUJZbUdzZWc1UDROYkM5ZWJ1aXBtTVRBcS9KdW1Pb29kCitGakwyblpxTDZmSTZmQnRGNU9HbHBDQjFZSjhmekN0R1FRWjdIVEliZGIydHA0M0ZWT2h5UWJWY0hxVEEwNFAKSjE1KzBXQXltVUpVejhYQTU0NHIvYnY3NEpjSlVSRmhhclppUXdJREFRQUJBb0lCQVFDU0pycjlaeVpiQ2dqegpSL3VKMFZEWCt2aVF4c01BTUZyUjJsOE1GV3NBeHk1SFA4Vk4xYmc5djN0YUVGYnI1U3hsa3lVMFJRNjNQU25DCm1uM3ZqZ3dVQWlScllnTEl5MGk0UXF5VFBOU1V4cnpTNHRxTFBjM3EvSDBnM2FrNGZ2cSsrS0JBUUlqQnloamUKbnVFc1JpMjRzT3NESlM2UDE5NGlzUC9yNEpIM1M5bFZGbkVuOGxUR2c0M1kvMFZoMXl0cnkvdDljWjR5ZUNpNwpjMHFEaTZZcXJZaFZhSW9RRW1VQjdsbHRFZkZzb3l4VDR6RTE5U3pVbkRoMmxjYTF1TzhqcmI4d2xHTzBoQ2JyClB1R1l2WFFQa3Q0VlNmalhvdGJ3d2lBNFRCVERCRzU1bHp6MmNKeS9zSS8zSHlYbEMxcTdXUmRuQVhhZ1F0VzkKOE9DZGRkb0JBb0dCQU5NcUNtSW94REtyckhZZFRxT1M1ZFN4cVMxL0NUN3ZYZ0pScXBqd2Y4WHA2WHo0KzIvTAozVXFaVDBEL3dGTkZkc1Z4eFYxMnNYMUdwMHFWZVlKRld5OVlCaHVSWGpTZ0ZEWldSY1Z1Y01sNVpPTmJsbmZGCjVKQ0xnNXFMZ1g5VTNSRnJrR3A0R241UDQxamg4TnhKVlhzZG5xWE9xNTFUK1RRT1UzdkpGQjc1QW9HQkFPTHcKalp1cnZtVkZyTHdaVGgvRDNpWll5SVV0ZUljZ2NKLzlzbTh6L0pPRmRIbFd4dGRHUFVzYVd1MnBTNEhvckFtbgpqTm4vSTluUXd3enZ3MWUzVVFPbUhMRjVBczk4VU5hbk5TQ0xNMW1yaXZHRXJ1VHFnTDM1bU41eFZPdTUxQU5JCm4yNkFtODBJT2JDeEtLa0R0ZXJSaFhHd3g5c1pONVJCbG9VRThZNGJBb0dBQ3ZsdVhMZWRxcng5VkE0bDNoNXUKVDJXRVUxYjgxZ1orcmtRc1I1S0lNWEw4cllBTElUNUpHKzFuendyN3BkaEFXZmFWdVV2SDRhamdYT0h6MUs5aQpFODNSVTNGMG9ldUg0V01PY1RwU0prWm0xZUlXcWRiaEVCb1FGdUlWTXRib1BsV0d4ZUhFRHJoOEtreGp4aThSCmdEcUQyajRwY1IzQ0g5QjJ5a0lqQjVFQ2dZRUExc0xXLys2enE1c1lNSm14K1JXZThhTXJmL3pjQnVTSU1LQWgKY0dNK0wwMG9RSHdDaUU4TVNqcVN1ajV3R214YUFuanhMb3ZwSFlRV1VmUEVaUW95UE1YQ2VhRVBLOU4xbk8xMwp0V2lHRytIZkIxaU5PazFCc0lhNFNDbndOM1FRVTFzeXBaeEgxT3hueS9LYmkvYmEvWEZ5VzNqMGFUK2YvVWxrCmJGV1ZVdWtDZ1lFQTBaMmRTTFlmTjV5eFNtYk5xMWVqZXdWd1BjRzQxR2hQclNUZEJxdHFac1doWGE3aDdLTWEKeHdvamh5SXpnTXNyK2tXODdlajhDQ2h0d21sQ1p5QU92QmdOZytncnJ1cEZLM3FOSkpKeU9YREdHckdpbzZmTQp5aXB3Q2tZVGVxRThpZ1J6UkI5QkdFUGY4eVpjMUtwdmZhUDVhM0lRZmxiV0czbGpUemNNZVZjPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= + diff --git a/pkg/ctl/tree.go b/pkg/ctl/tree.go index c3f84f5..63c5760 100644 --- a/pkg/ctl/tree.go +++ b/pkg/ctl/tree.go @@ -23,64 +23,31 @@ import ( "strings" "github.com/google/uuid" - "opendev.org/airship/airshipctl/pkg/document" "opendev.org/airship/airshipctl/pkg/phase" + "opendev.org/airship/airshipctl/pkg/phase/ifc" "opendev.org/airship/airshipui/pkg/log" "sigs.k8s.io/kustomize/api/types" ) -var phaseIndex map[string]PhaseObj = buildPhaseIndex() +// TODO(mfuller): new helper each time? or once here? +var helper ifc.Helper -// PhaseObj lightweight structure to hold the name and document -// entrypoint for airshipctl phases -type PhaseObj struct { - Group string - Name string - Entrypoint string -} +func getHelper() (ifc.Helper, error) { + if helper != nil { + return helper, nil + } -func buildPhaseIndex() map[string]PhaseObj { - client := NewDefaultClient() - return client.buildPhaseIndex() -} - -func (client *Client) buildPhaseIndex() map[string]PhaseObj { - idx := map[string]PhaseObj{} - - // get target path from ctl settings - tp, err := client.settings.Config.CurrentContextTargetPath() + c, err := NewDefaultClient(AirshipConfigPath, KubeConfigPath) if err != nil { - log.Errorf("Error building phase index: %s", err) - return nil + return nil, err } - cmd := phase.Cmd{AirshipCTLSettings: client.settings} - - plan, err := cmd.Plan() + h, err := phase.NewHelper(c.Config) if err != nil { - log.Errorf("Error building phase index: %s", err) - return nil + return nil, err } - for grp, phases := range plan { - for _, phase := range phases { - p, err := cmd.GetPhase(phase) - if err != nil { - log.Errorf("Error building phase index: %s", err) - return nil - } - - entrypoint := fmt.Sprintf("%s/kustomization.yaml", - filepath.Join(tp, p.Config.DocumentEntryPoint)) - - idx[uuid.New().String()] = PhaseObj{ - Group: grp, - Name: phase, - Entrypoint: entrypoint, - } - } - } - return idx + return h, nil } // GetPhaseTree builds the initial structure of the phase tree @@ -89,176 +56,115 @@ func (client *Client) buildPhaseIndex() map[string]PhaseObj { func (client *Client) GetPhaseTree() ([]KustomNode, error) { nodes := []KustomNode{} - grpMap := map[string][]KustomNode{} - for id, po := range phaseIndex { - pNode := KustomNode{ - ID: id, - Name: fmt.Sprintf("Phase: %s", po.Name), - IsPhaseNode: true, - } - - children, err := client.GetPhaseSourceFiles(id) - if err != nil { - // TODO(mfuller): push an error to UI so it can be handled by - // toastr service, pending refactor of webservice and configs pkgs - log.Errorf("Error building tree for phase '%s': %s", po.Name, err) - pNode.HasError = true - } else { - pNode.Children = children - } - - grpMap[po.Group] = append(grpMap[po.Group], pNode) + helper, err := getHelper() + if err != nil { + return nil, err } - for name, phases := range grpMap { - gNode := KustomNode{ - ID: uuid.New().String(), - Name: fmt.Sprintf("Group: %s", name), - Children: phases, + phases, err := helper.ListPhases() + if err != nil { + return nil, err + } + + for _, p := range phases { + pNode := KustomNode{ + ID: uuid.New().String(), + PhaseID: ifc.ID{Name: p.Name, Namespace: p.Namespace}, + Name: fmt.Sprintf("Phase: %s", p.Name), + IsPhaseNode: true, + Children: []KustomNode{}, } - nodes = append(nodes, gNode) + + // some phases don't have any associated documents, so don't look + // for children unless a DocumentEntryPoint has been specified + if p.Config.DocumentEntryPoint != "" { + children, err := client.GetPhaseSourceFiles(pNode.PhaseID) + if err != nil { + // TODO(mfuller): push an error to UI so it can be handled by + // toastr service, pending refactor of webservice and configs pkgs + log.Errorf("Error building tree for phase '%s': %s", p.Name, err) + pNode.HasError = true + } else { + pNode.Children = children + } + } + nodes = append(nodes, pNode) } return nodes, nil } -// GetPhaseDocuments returns a slice of KustomNodes representing -// all of the rendered documents making up a phase bundle. -// Ordering is k8s Namespace -> k8s Kind -> document name -func GetPhaseDocuments(id string) ([]KustomNode, error) { - if index == nil { - index = map[string]interface{}{} - } - nsNodes := []KustomNode{} - - if p, ok := phaseIndex[id]; ok { - // get map of all docs associated with this bundle - docs, err := sortDocuments(p.Entrypoint) - if err != nil { - return nil, err - } - // namespace node - for ns, kinds := range docs { - nsNode := KustomNode{ - ID: uuid.New().String(), - Name: ns, - Children: []KustomNode{}, - } - // kind node - for kind, docs := range kinds { - kNode := KustomNode{ - ID: uuid.New().String(), - Name: kind, - Children: []KustomNode{}, - } - // doc node - for _, d := range docs { - id := uuid.New().String() - dNode := KustomNode{ - ID: id, - Name: d.GetName(), - } - index[id] = d - kNode.Children = append(kNode.Children, dNode) - } - nsNode.Children = append(nsNode.Children, kNode) - } - nsNodes = append(nsNodes, nsNode) - } - } - return nsNodes, nil -} - -// sort a bundle's docs into namespace, kind -func sortDocuments(path string) (map[string]map[string][]document.Document, error) { - docMap := map[string]map[string][]document.Document{} - - bundle, err := document.NewBundleByPath(filepath.Dir(path)) - if err != nil { - return nil, err - } - - docs, err := bundle.GetAllDocuments() - if err != nil { - return nil, err - } - - for _, doc := range docs { - ns := doc.GetNamespace() - if ns == "" { - ns = "[no namespace]" - } - kind := doc.GetKind() - - if docMap[ns] == nil { - docMap[ns] = map[string][]document.Document{} - } - - docMap[ns][kind] = append(docMap[ns][kind], doc) - } - - return docMap, nil -} - // GetPhaseSourceFiles returns a slice of KustomNodes representing // all of the directories that will be traversed when kustomize // builds the document bundle. The tree hierarchy is: // kustomize "type" (like function) -> directory name -> file name -func (client *Client) GetPhaseSourceFiles(id string) ([]KustomNode, error) { +func (client *Client) GetPhaseSourceFiles(id ifc.ID) ([]KustomNode, error) { if index == nil { index = map[string]interface{}{} } + + helper, err := getHelper() + if err != nil { + return nil, err + } + + phase, err := helper.Phase(id) + if err != nil { + return nil, err + } + + dirs, err := getKustomizeDirs( + filepath.Join(helper.TargetPath(), + phase.Config.DocumentEntryPoint, + "kustomization.yaml")) + if err != nil { + return nil, err + } + + dm, err := client.createDirsMap(dirs) + if err != nil { + return nil, err + } + dirNodes := []KustomNode{} - if p, ok := phaseIndex[id]; ok { - dirs, err := getKustomizeDirs(p.Entrypoint) - if err != nil { - return nil, err + // kustomize "type" node + for t, data := range dm { + tNode := KustomNode{ + ID: uuid.New().String(), + Name: t, } - dm, err := client.createDirsMap(dirs) - if err != nil { - return nil, err - } - - // kustomize "type" node - for t, data := range dm { - tNode := KustomNode{ - ID: uuid.New().String(), - Name: t, + // directory node + for _, d := range data { + name := d[0] + abs := d[1] + dNode := KustomNode{ + ID: uuid.New().String(), + Name: name, + Children: []KustomNode{}, } - // directory node - for _, d := range data { - name := d[0] - abs := d[1] - dNode := KustomNode{ - ID: uuid.New().String(), - Name: name, - Children: []KustomNode{}, - } - - files, err := ioutil.ReadDir(abs) - if err != nil { - return nil, err - } - // file (leaf) node - for _, f := range files { - if !f.IsDir() { - id := uuid.New().String() - path := filepath.Join(abs, f.Name()) - dNode.Children = append(dNode.Children, - KustomNode{ - ID: id, - Name: f.Name(), - }) - index[id] = path - } - } - tNode.Children = append(tNode.Children, dNode) + files, err := ioutil.ReadDir(abs) + if err != nil { + return nil, err } - dirNodes = append(dirNodes, tNode) + // file (leaf) node + for _, f := range files { + if !f.IsDir() { + id := uuid.New().String() + path := filepath.Join(abs, f.Name()) + dNode.Children = append(dNode.Children, + KustomNode{ + ID: id, + Name: f.Name(), + }) + index[id] = path + } + } + tNode.Children = append(tNode.Children, dNode) } + dirNodes = append(dirNodes, tNode) } return dirNodes, nil } @@ -266,7 +172,8 @@ func (client *Client) GetPhaseSourceFiles(id string) ([]KustomNode, error) { // KustomNode structure to represent the kustomization tree for a given phase // bundle to be consumed by the UI frontend type KustomNode struct { - ID string `json:"id"` // UUID for backend node index + ID string `json:"id"` // UUID for backend node index + PhaseID ifc.ID `json:"phaseid"` Name string `json:"name"` // name used for display purposes (cli, ui) IsPhaseNode bool `json:"isPhaseNode"` HasError bool `json:"hasError"` @@ -332,7 +239,7 @@ func getKustomizeDirs(entrypoint string) ([]string, error) { func (client *Client) createDirsMap(dirs []string) (map[string][][]string, error) { dm := map[string][][]string{} - tp, err := client.settings.Config.CurrentContextTargetPath() + tp, err := client.Config.CurrentContextTargetPath() if err != nil { return nil, err }