From b892ddd4da59b941bb0184e4925bf72da28d6105 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Mon, 20 Nov 2023 22:11:32 +0530 Subject: [PATCH 01/10] added architecture image --- assets/architecture.png | Bin 0 -> 39548 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/architecture.png diff --git a/assets/architecture.png b/assets/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..8d86c9bcd18b4269f5d37f45aed4e39ee470480a GIT binary patch literal 39548 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 Up>)f0X;8R%y85}Sb4q9e0KKcZ?*IS* literal 0 HcmV?d00001 From ea3228f5e34e6483c281baff719906bb13abc43e Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Mon, 20 Nov 2023 22:12:35 +0530 Subject: [PATCH 02/10] carving --- go.mod | 20 +++++++++-- go.sum | 55 +++++++++++++++++++++++++++++++ internal/core/application.go | 52 +++++++++++++++++++++++++++++ internal/core/application_set.go | 21 ++++++++++++ internal/core/application_spec.go | 8 +++++ internal/core/setup.go | 9 +++++ server/routes.go | 7 ++++ todo.md | 13 ++++++++ 8 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 internal/core/application.go create mode 100644 internal/core/application_set.go create mode 100644 internal/core/application_spec.go create mode 100644 internal/core/setup.go create mode 100644 todo.md diff --git a/go.mod b/go.mod index fa0ef68..6513222 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,29 @@ go 1.21.0 require github.com/spf13/cobra v1.8.0 +require ( + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/net v0.16.0 // indirect + golang.org/x/tools v0.14.0 // indirect +) + require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/lipgloss v0.9.1 // indirect - github.com/charmbracelet/log v0.3.0 + github.com/charmbracelet/log v0.3.0 github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/gofiber/fiber/v2 v2.51.0 + github.com/gofiber/fiber/v2 v2.51.0 github.com/google/uuid v1.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect diff --git a/go.sum b/go.sum index 6a9e677..82946cb 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -7,14 +9,28 @@ github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9 github.com/charmbracelet/log v0.3.0 h1:u5aB2KJDgNZo4WOfOC8C+KvGIkJ2rCFNlPWDu6xhnqI= github.com/charmbracelet/log v0.3.0/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -33,6 +49,12 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -47,13 +69,46 @@ github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/core/application.go b/internal/core/application.go new file mode 100644 index 0000000..f96d6fa --- /dev/null +++ b/internal/core/application.go @@ -0,0 +1,52 @@ +/* +Copyright 2023 - PRESENT Meltred + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package core + +import "github.com/docker/docker/api/types/swarm" + +type Application struct { + Name string `json:"name"` + RefreshTimer uint64 `json:"sync_timer"` // Timer to check for Sync + Health ApplicationHealth `json:"health"` + LiveState swarm.ServiceSpec `json:"live_state"` +} + +type ApplicationHealth int + +const ( + Healthy ApplicationHealth = iota + Progressing + Degraded + Suspended +) + +// SyncStatus Check if LiveState = TargetState +// +// Whether or not the live state matches the target state. +// Is the deployed application the same as Git says it should be? +func (app *Application) SyncStatus(targetState swarm.ServiceSpec) bool { + //TODO + return false +} + +// Sync +// The process of making an application move to its target state. +// E.g. by applying changes to a docker swarm cluster. +func (app *Application) Sync(targetState swarm.ServiceSpec) error { + //TODO + return nil +} diff --git a/internal/core/application_set.go b/internal/core/application_set.go new file mode 100644 index 0000000..0e9ece8 --- /dev/null +++ b/internal/core/application_set.go @@ -0,0 +1,21 @@ +/* +Copyright 2023 - PRESENT Meltred + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package core + +type ApplicationSet struct { + applications []Application +} diff --git a/internal/core/application_spec.go b/internal/core/application_spec.go new file mode 100644 index 0000000..41012ab --- /dev/null +++ b/internal/core/application_spec.go @@ -0,0 +1,8 @@ +package core + +type ApplicationSpec struct{} + +// parse an application from yaml source +func parseSpec(source string) ApplicationSpec { + return ApplicationSpec{} +} diff --git a/internal/core/setup.go b/internal/core/setup.go new file mode 100644 index 0000000..3bb2b3d --- /dev/null +++ b/internal/core/setup.go @@ -0,0 +1,9 @@ +package core + +// Setup will setup require +// settings to make use of MeltCD +// like setting up admin password in docker secret +// setting up docker volume for persistent storage +func Setup() error { + return nil +} diff --git a/server/routes.go b/server/routes.go index eaad745..f74be91 100644 --- a/server/routes.go +++ b/server/routes.go @@ -19,6 +19,7 @@ package server import ( "embed" "fmt" + "meltred/meltcd/internal/core" "meltred/meltcd/version" "net" "net/http" @@ -78,6 +79,12 @@ func Serve(ln net.Listener, origins string, verboseOutput bool) error { return c.Status(200).SendString(fmt.Sprintf("MeltCD is running (version: %s)\n", version.Version)) }) + err := core.Setup() + if err != nil { + log.Error(err) + os.Exit(1) + } + log.Infof("Listening on %s (version: %s)", ln.Addr(), version.Version) signals := make(chan os.Signal, 1) diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..7378e09 --- /dev/null +++ b/todo.md @@ -0,0 +1,13 @@ +# CLI Commands + +1. Create a new `Application` + +```bash +meltcd app create --repo --path +``` + +2. Get details about `Application` + +```bash +meltcd app get +``` From 144417e372ca70455072142989e540e144335c9f Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 13:32:30 +0530 Subject: [PATCH 03/10] implemeing core --- cmd/meltcd/app.go | 63 +++++++++++++++++++ cmd/meltcd/cmd.go | 24 ++++++- .../{application.go => application/app.go} | 19 +++++- .../set.go} | 2 +- internal/core/application/spec.go | 57 +++++++++++++++++ internal/core/application_spec.go | 8 --- internal/core/setup.go | 16 +++++ main.go | 2 +- todo.md | 8 ++- 9 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 cmd/meltcd/app.go rename internal/core/{application.go => application/app.go} (78%) rename internal/core/{application_set.go => application/set.go} (96%) create mode 100644 internal/core/application/spec.go delete mode 100644 internal/core/application_spec.go diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go new file mode 100644 index 0000000..0e278aa --- /dev/null +++ b/cmd/meltcd/app.go @@ -0,0 +1,63 @@ +/* +Copyright 2023 - PRESENT Meltred + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meltcd + +import ( + "fmt" + "meltred/meltcd/internal/core/application" + + "github.com/spf13/cobra" +) + +func createNewApplication(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + // Creating application without application name + // means using a file + file, err := cmd.Flags().GetString("file") + if err != nil { + return err + } + //TODO + + fmt.Println(file) + } else { + // Creating application with application name + // means using arguments + name := args[0] + + repo, err := cmd.Flags().GetString("repo") + if err != nil { + return err + } + + path, err := cmd.Flags().GetString("path") + if err != nil { + return err + } + + refresh, _ := cmd.Flags().GetDuration("refresh") + + spec, err := application.ParseSpecFromValue(name, repo, path, refresh) + if err != nil { + return err + } + + _ = application.New(spec) + // TODO: run the + } + return nil +} diff --git a/cmd/meltcd/cmd.go b/cmd/meltcd/cmd.go index 1baf65d..fc8dfbb 100644 --- a/cmd/meltcd/cmd.go +++ b/cmd/meltcd/cmd.go @@ -19,6 +19,7 @@ package meltcd import ( "log" "meltred/meltcd/version" + "time" "github.com/spf13/cobra" ) @@ -26,7 +27,7 @@ import ( // NewApplication creates a new cli app // This cli app can be used to start the api server // as well as a client -func NewApplication() *cobra.Command { +func NewCLI() *cobra.Command { // Log time, date, and file name log.SetFlags(log.Ldate | log.Lshortfile) @@ -54,7 +55,28 @@ func NewApplication() *cobra.Command { serveCmd.Flags().Bool("verbose", false, "verbose is used to get extra logs/info about process") + // Application + appCmd := &cobra.Command{ + Use: "app", + Short: "Work with Applications", + } + + appCreateCmd := &cobra.Command{ + Use: "create", + Short: "Create a new application", + Args: cobra.RangeArgs(0, 1), + RunE: createNewApplication, + } + + appCreateCmd.Flags().String("repo", "", "The git repository where the compose file is hosted") + appCreateCmd.Flags().String("path", "", "The path to compose file") + appCreateCmd.Flags().Duration("refresh", time.Minute*3, "The refresh time for sync") + appCreateCmd.Flags().String("file", "", "Application schema file") + + appCmd.AddCommand(appCreateCmd) + rootCmd.AddCommand(serveCmd) + rootCmd.AddCommand(appCmd) return rootCmd } diff --git a/internal/core/application.go b/internal/core/application/app.go similarity index 78% rename from internal/core/application.go rename to internal/core/application/app.go index f96d6fa..b95ed80 100644 --- a/internal/core/application.go +++ b/internal/core/application/app.go @@ -14,13 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package core +package application -import "github.com/docker/docker/api/types/swarm" +import ( + "time" + + "github.com/docker/docker/api/types/swarm" +) type Application struct { Name string `json:"name"` - RefreshTimer uint64 `json:"sync_timer"` // Timer to check for Sync + Source Source `json:"source"` + RefreshTimer time.Duration `json:"refresh_timer"` // Timer to check for Sync Health ApplicationHealth `json:"health"` LiveState swarm.ServiceSpec `json:"live_state"` } @@ -34,6 +39,14 @@ const ( Suspended ) +func New(spec ApplicationSpec) Application { + return Application{ + Name: spec.Name, + RefreshTimer: spec.RefreshTimer, + Source: spec.Source, + } +} + // SyncStatus Check if LiveState = TargetState // // Whether or not the live state matches the target state. diff --git a/internal/core/application_set.go b/internal/core/application/set.go similarity index 96% rename from internal/core/application_set.go rename to internal/core/application/set.go index 0e9ece8..98de258 100644 --- a/internal/core/application_set.go +++ b/internal/core/application/set.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package core +package application type ApplicationSet struct { applications []Application diff --git a/internal/core/application/spec.go b/internal/core/application/spec.go new file mode 100644 index 0000000..e78a260 --- /dev/null +++ b/internal/core/application/spec.go @@ -0,0 +1,57 @@ +/* +Copyright 2023 - PRESENT Meltred + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package application + +import ( + "errors" + "time" +) + +type ApplicationSpec struct { + Name string `json:"name" yaml:"name"` + RefreshTimer time.Duration `json:"refresh_timer" yaml:"refresh_timer"` // number of minutes + Source Source `json:"source" yaml:"source"` +} + +type Source struct { + Repo string `json:"repo" yaml:"repo"` + Path string `json:"path" yaml:"path"` +} + +// parse an application from yaml source +func ParseSpecFromFile(file string) (ApplicationSpec, error) { + return ApplicationSpec{}, nil +} + +func ParseSpecFromValue(name, repo, path string, refresh time.Duration) (ApplicationSpec, error) { + if repo == "" { + return ApplicationSpec{}, errors.New("The git repository not specified") + } + + if path == "" { + return ApplicationSpec{}, errors.New("The path to compose file not specified") + } + + return ApplicationSpec{ + Name: name, + RefreshTimer: refresh, + Source: Source{ + Repo: repo, + Path: path, + }, + }, nil +} diff --git a/internal/core/application_spec.go b/internal/core/application_spec.go deleted file mode 100644 index 41012ab..0000000 --- a/internal/core/application_spec.go +++ /dev/null @@ -1,8 +0,0 @@ -package core - -type ApplicationSpec struct{} - -// parse an application from yaml source -func parseSpec(source string) ApplicationSpec { - return ApplicationSpec{} -} diff --git a/internal/core/setup.go b/internal/core/setup.go index 3bb2b3d..27efc9a 100644 --- a/internal/core/setup.go +++ b/internal/core/setup.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 - PRESENT Meltred + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package core // Setup will setup require diff --git a/main.go b/main.go index 63159cf..48064f0 100644 --- a/main.go +++ b/main.go @@ -24,5 +24,5 @@ import ( ) func main() { - cobra.CheckErr(meltcd.NewApplication().ExecuteContext(context.Background())) + cobra.CheckErr(meltcd.NewCLI().ExecuteContext(context.Background())) } diff --git a/todo.md b/todo.md index 7378e09..d60de0b 100644 --- a/todo.md +++ b/todo.md @@ -6,7 +6,13 @@ meltcd app create --repo --path ``` -2. Get details about `Application` +2. Create a new `Application` with file + +```bash +meltcd app create --file +``` + +3. Get details about `Application` ```bash meltcd app get From 09785c42f72bbf2bdda83d1c3f1b0d2663ab71d6 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 13:44:11 +0530 Subject: [PATCH 04/10] paring application spec file --- cmd/meltcd/app.go | 18 +++++++++++------- internal/core/application/spec.go | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index 0e278aa..a339692 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -24,6 +24,8 @@ import ( ) func createNewApplication(cmd *cobra.Command, args []string) error { + var spec application.ApplicationSpec + if len(args) == 0 { // Creating application without application name // means using a file @@ -31,9 +33,10 @@ func createNewApplication(cmd *cobra.Command, args []string) error { if err != nil { return err } - //TODO - - fmt.Println(file) + spec, err = application.ParseSpecFromFile(file) + if err != nil { + return err + } } else { // Creating application with application name // means using arguments @@ -51,13 +54,14 @@ func createNewApplication(cmd *cobra.Command, args []string) error { refresh, _ := cmd.Flags().GetDuration("refresh") - spec, err := application.ParseSpecFromValue(name, repo, path, refresh) + spec, err = application.ParseSpecFromValue(name, repo, path, refresh) if err != nil { return err } - - _ = application.New(spec) - // TODO: run the } + + app := application.New(spec) + fmt.Println(app.Name) + fmt.Println(app.Source) return nil } diff --git a/internal/core/application/spec.go b/internal/core/application/spec.go index e78a260..a41a80f 100644 --- a/internal/core/application/spec.go +++ b/internal/core/application/spec.go @@ -34,6 +34,10 @@ type Source struct { // parse an application from yaml source func ParseSpecFromFile(file string) (ApplicationSpec, error) { + if file == "" { + return ApplicationSpec{}, errors.New("Application specification file not specified") + } + return ApplicationSpec{}, nil } From e310e069a4535927118ab7633cacee502897aa8d Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 16:05:46 +0530 Subject: [PATCH 05/10] skeleton getting service from git --- cmd/meltcd/app.go | 13 +++-- cmd/meltcd/cmd.go | 5 +- go.mod | 20 ++++++- go.sum | 92 +++++++++++++++++++++++++++++++ internal/core/application/app.go | 31 +++++++++++ internal/core/application/spec.go | 19 +++++-- internal/core/register.go | 15 +++++ 7 files changed, 180 insertions(+), 15 deletions(-) create mode 100644 internal/core/register.go diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index a339692..dba8b79 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -17,9 +17,9 @@ limitations under the License. package meltcd import ( - "fmt" "meltred/meltcd/internal/core/application" + "github.com/charmbracelet/log" "github.com/spf13/cobra" ) @@ -27,6 +27,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { var spec application.ApplicationSpec if len(args) == 0 { + log.Info("Creating application with Specification file") // Creating application without application name // means using a file file, err := cmd.Flags().GetString("file") @@ -38,8 +39,9 @@ func createNewApplication(cmd *cobra.Command, args []string) error { return err } } else { - // Creating application with application name + // creating application with application name // means using arguments + log.Info("Creating application using arguments") name := args[0] repo, err := cmd.Flags().GetString("repo") @@ -53,15 +55,14 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } refresh, _ := cmd.Flags().GetDuration("refresh") + revision, _ := cmd.Flags().GetString("revision") - spec, err = application.ParseSpecFromValue(name, repo, path, refresh) + spec, err = application.ParseSpecFromValue(name, repo, revision, path, refresh) if err != nil { return err } } - app := application.New(spec) - fmt.Println(app.Name) - fmt.Println(app.Source) + _ = application.New(spec) return nil } diff --git a/cmd/meltcd/cmd.go b/cmd/meltcd/cmd.go index fc8dfbb..7673269 100644 --- a/cmd/meltcd/cmd.go +++ b/cmd/meltcd/cmd.go @@ -68,8 +68,9 @@ func NewCLI() *cobra.Command { RunE: createNewApplication, } - appCreateCmd.Flags().String("repo", "", "The git repository where the compose file is hosted") - appCreateCmd.Flags().String("path", "", "The path to compose file") + appCreateCmd.Flags().String("repo", "", "The git repository where the service file is hosted") + appCreateCmd.Flags().String("revision", "HEAD", "The git repository revision") + appCreateCmd.Flags().String("path", "", "The path to service file") appCreateCmd.Flags().Duration("refresh", time.Minute*3, "The refresh time for sync") appCreateCmd.Flags().String("file", "", "Application schema file") diff --git a/go.mod b/go.mod index 6513222..9452ade 100644 --- a/go.mod +++ b/go.mod @@ -5,19 +5,37 @@ go 1.21.0 require github.com/spf13/cobra v1.8.0 require ( + dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-git/v5 v5.10.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.16.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/tools v0.14.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( diff --git a/go.sum b/go.sum index 82946cb..67640c6 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,28 @@ +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= github.com/charmbracelet/log v0.3.0 h1:u5aB2KJDgNZo4WOfOC8C+KvGIkJ2rCFNlPWDu6xhnqI= github.com/charmbracelet/log v0.3.0/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= @@ -19,22 +33,40 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git/v5 v5.10.0 h1:F0x3xXrAWmhwtzoCokU4IMPcBdncG+HAAqi9FcOOjbQ= +github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYvhWHvZGhoo= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -53,57 +85,112 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -111,4 +198,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/core/application/app.go b/internal/core/application/app.go index b95ed80..bf8e3e9 100644 --- a/internal/core/application/app.go +++ b/internal/core/application/app.go @@ -17,9 +17,13 @@ limitations under the License. package application import ( + "errors" "time" + "github.com/charmbracelet/log" "github.com/docker/docker/api/types/swarm" + git "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/storage/memory" ) type Application struct { @@ -47,6 +51,33 @@ func New(spec ApplicationSpec) Application { } } +func (app *Application) GetService() (swarm.ServiceSpec, error) { + log.Info("Getting service from git repo", "repo", app.Source.RepoURL, "app_name", app.Name) + + // TODO: IMPROVEMENT + // Use Docker Volumes to clone repository + // and then only fetch & pull if already exists + // and check if specified path is modified then apply the changes + storage := memory.NewStorage() + + // defer clear storage + _, err := git.Clone(storage, nil, &git.CloneOptions{ + URL: app.Source.RepoURL, + }) + if errors.Is(err, git.ErrRepositoryAlreadyExists) { + // fetch & pull request + // don't clone again + } + if err != nil { + return swarm.ServiceSpec{}, err + } + + // convert it into service spec + + // return + return swarm.ServiceSpec{}, nil +} + // SyncStatus Check if LiveState = TargetState // // Whether or not the live state matches the target state. diff --git a/internal/core/application/spec.go b/internal/core/application/spec.go index a41a80f..4ab70ce 100644 --- a/internal/core/application/spec.go +++ b/internal/core/application/spec.go @@ -19,6 +19,8 @@ package application import ( "errors" "time" + + "github.com/charmbracelet/log" ) type ApplicationSpec struct { @@ -28,34 +30,39 @@ type ApplicationSpec struct { } type Source struct { - Repo string `json:"repo" yaml:"repo"` - Path string `json:"path" yaml:"path"` + RepoURL string `json:"repo" yaml:"repoURL"` + TargetRevision string `json:"revision" yaml:"targetRevision"` + Path string `json:"path" yaml:"path"` } // parse an application from yaml source func ParseSpecFromFile(file string) (ApplicationSpec, error) { if file == "" { + log.Error("Application specification file not specified") return ApplicationSpec{}, errors.New("Application specification file not specified") } + log.Info("Using file", "Service file", file) + return ApplicationSpec{}, nil } -func ParseSpecFromValue(name, repo, path string, refresh time.Duration) (ApplicationSpec, error) { +func ParseSpecFromValue(name, repo, revision, path string, refresh time.Duration) (ApplicationSpec, error) { if repo == "" { return ApplicationSpec{}, errors.New("The git repository not specified") } if path == "" { - return ApplicationSpec{}, errors.New("The path to compose file not specified") + return ApplicationSpec{}, errors.New("The path to Service file not specified") } return ApplicationSpec{ Name: name, RefreshTimer: refresh, Source: Source{ - Repo: repo, - Path: path, + RepoURL: repo, + TargetRevision: revision, + Path: path, }, }, nil } diff --git a/internal/core/register.go b/internal/core/register.go new file mode 100644 index 0000000..2218d34 --- /dev/null +++ b/internal/core/register.go @@ -0,0 +1,15 @@ +package core + +import ( + "meltred/meltcd/internal/core/application" + + "github.com/charmbracelet/log" +) + +func Register(app *application.Application) error { + log.Info("Registering application", "name", app.Name) + + //TODO: check if application with name already exists + + return nil +} From b873d7b739c908e186a09687e0dbc84dc3e601e7 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 16:37:22 +0530 Subject: [PATCH 06/10] running the app --- cmd/meltcd/app.go | 8 +++++++- internal/core/application/app.go | 4 ++++ internal/core/register.go | 15 --------------- internal/core/registery.go | 32 ++++++++++++++++++++++++++++++++ internal/core/setup.go | 2 ++ server/routes.go | 4 ++++ 6 files changed, 49 insertions(+), 16 deletions(-) delete mode 100644 internal/core/register.go create mode 100644 internal/core/registery.go diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index dba8b79..8fc9a62 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -17,6 +17,7 @@ limitations under the License. package meltcd import ( + "meltred/meltcd/internal/core" "meltred/meltcd/internal/core/application" "github.com/charmbracelet/log" @@ -63,6 +64,11 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } } - _ = application.New(spec) + app := application.New(spec) + + if err := core.Register(&app); err != nil { + return err + } + return nil } diff --git a/internal/core/application/app.go b/internal/core/application/app.go index bf8e3e9..65a37fb 100644 --- a/internal/core/application/app.go +++ b/internal/core/application/app.go @@ -51,6 +51,10 @@ func New(spec ApplicationSpec) Application { } } +func (app *Application) Run() { + log.Info("Running Application", "name", app.Name) +} + func (app *Application) GetService() (swarm.ServiceSpec, error) { log.Info("Getting service from git repo", "repo", app.Source.RepoURL, "app_name", app.Name) diff --git a/internal/core/register.go b/internal/core/register.go deleted file mode 100644 index 2218d34..0000000 --- a/internal/core/register.go +++ /dev/null @@ -1,15 +0,0 @@ -package core - -import ( - "meltred/meltcd/internal/core/application" - - "github.com/charmbracelet/log" -) - -func Register(app *application.Application) error { - log.Info("Registering application", "name", app.Name) - - //TODO: check if application with name already exists - - return nil -} diff --git a/internal/core/registery.go b/internal/core/registery.go new file mode 100644 index 0000000..3788ad5 --- /dev/null +++ b/internal/core/registery.go @@ -0,0 +1,32 @@ +package core + +import ( + "errors" + "fmt" + "meltred/meltcd/internal/core/application" + + "github.com/charmbracelet/log" +) + +var Applications []*application.Application + +func Register(app *application.Application) error { + log.Info("Registering application", "name", app.Name) + + for _, regApp := range Applications { + if regApp.Name == app.Name { + return errors.New(fmt.Sprintf("App already exists with name: %s\n", app.Name)) + } + } + + go app.Run() + Applications = append(Applications, app) + + return nil +} + +func Run() { + for _, app := range Applications { + go app.Run() + } +} diff --git a/internal/core/setup.go b/internal/core/setup.go index 27efc9a..d0c75ec 100644 --- a/internal/core/setup.go +++ b/internal/core/setup.go @@ -20,6 +20,8 @@ package core // settings to make use of MeltCD // like setting up admin password in docker secret // setting up docker volume for persistent storage +// +// fill the Applications from the volume func Setup() error { return nil } diff --git a/server/routes.go b/server/routes.go index f74be91..4a2a4b7 100644 --- a/server/routes.go +++ b/server/routes.go @@ -85,6 +85,10 @@ func Serve(ln net.Listener, origins string, verboseOutput bool) error { os.Exit(1) } + go func() { + core.Run() + }() + log.Infof("Listening on %s (version: %s)", ln.Addr(), version.Version) signals := make(chan os.Signal, 1) From d8f582e6bad57f280f34915558babbddd644d4b0 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 22:27:42 +0530 Subject: [PATCH 07/10] api+ /api/application/register --- api/register.go | 26 ++++++++++++++++++++++++++ cmd/meltcd/app.go | 9 ++------- cmd/meltcd/cmd.go | 3 +-- internal/core/application/app.go | 16 +++++++++++++++- internal/core/application/spec.go | 9 ++++----- internal/core/registery.go | 6 ------ server/routes.go | 9 ++++----- 7 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 api/register.go diff --git a/api/register.go b/api/register.go new file mode 100644 index 0000000..1294144 --- /dev/null +++ b/api/register.go @@ -0,0 +1,26 @@ +package api + +import ( + "meltred/meltcd/internal/core" + "meltred/meltcd/internal/core/application" + "net/http" + + "github.com/gofiber/fiber/v2" +) + +func Register(c *fiber.Ctx) error { + var app application.Application + + if err := c.BodyParser(&app); err != nil { + return &fiber.Error{ + Code: fiber.StatusBadRequest, + Message: err.Error(), + } + } + + if err := core.Register(&app); err != nil { + return err + } + + return c.SendStatus(http.StatusAccepted) +} diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index 8fc9a62..b3b8a77 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -17,7 +17,6 @@ limitations under the License. package meltcd import ( - "meltred/meltcd/internal/core" "meltred/meltcd/internal/core/application" "github.com/charmbracelet/log" @@ -55,7 +54,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { return err } - refresh, _ := cmd.Flags().GetDuration("refresh") + refresh, _ := cmd.Flags().GetString("refresh") revision, _ := cmd.Flags().GetString("revision") spec, err = application.ParseSpecFromValue(name, repo, revision, path, refresh) @@ -64,11 +63,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } } - app := application.New(spec) - - if err := core.Register(&app); err != nil { - return err - } + _ = application.New(spec) return nil } diff --git a/cmd/meltcd/cmd.go b/cmd/meltcd/cmd.go index 7673269..c3a549d 100644 --- a/cmd/meltcd/cmd.go +++ b/cmd/meltcd/cmd.go @@ -19,7 +19,6 @@ package meltcd import ( "log" "meltred/meltcd/version" - "time" "github.com/spf13/cobra" ) @@ -71,7 +70,7 @@ func NewCLI() *cobra.Command { appCreateCmd.Flags().String("repo", "", "The git repository where the service file is hosted") appCreateCmd.Flags().String("revision", "HEAD", "The git repository revision") appCreateCmd.Flags().String("path", "", "The path to service file") - appCreateCmd.Flags().Duration("refresh", time.Minute*3, "The refresh time for sync") + appCreateCmd.Flags().String("refresh", "3m0s", "The refresh time for sync") appCreateCmd.Flags().String("file", "", "Application schema file") appCmd.AddCommand(appCreateCmd) diff --git a/internal/core/application/app.go b/internal/core/application/app.go index 65a37fb..0dc71e6 100644 --- a/internal/core/application/app.go +++ b/internal/core/application/app.go @@ -29,7 +29,7 @@ import ( type Application struct { Name string `json:"name"` Source Source `json:"source"` - RefreshTimer time.Duration `json:"refresh_timer"` // Timer to check for Sync + RefreshTimer string `json:"refresh_timer"` // Timer to check for Sync format of "3m50s" Health ApplicationHealth `json:"health"` LiveState swarm.ServiceSpec `json:"live_state"` } @@ -53,6 +53,20 @@ func New(spec ApplicationSpec) Application { func (app *Application) Run() { log.Info("Running Application", "name", app.Name) + + refreshTime, err := time.ParseDuration(app.RefreshTimer) + if err != nil { + app.Health = Suspended + log.Error("Failed to parse refresh_time, it must be like \"3m30s\"", "name", app.Name) + return + } + + timer := time.NewTicker(refreshTime) + + for range timer.C { + // check for sync + log.Info(" +", "name", app.Name) + } } func (app *Application) GetService() (swarm.ServiceSpec, error) { diff --git a/internal/core/application/spec.go b/internal/core/application/spec.go index 4ab70ce..f7974db 100644 --- a/internal/core/application/spec.go +++ b/internal/core/application/spec.go @@ -18,15 +18,14 @@ package application import ( "errors" - "time" "github.com/charmbracelet/log" ) type ApplicationSpec struct { - Name string `json:"name" yaml:"name"` - RefreshTimer time.Duration `json:"refresh_timer" yaml:"refresh_timer"` // number of minutes - Source Source `json:"source" yaml:"source"` + Name string `json:"name" yaml:"name"` + RefreshTimer string `json:"refresh_timer" yaml:"refresh_timer"` // number of minutes + Source Source `json:"source" yaml:"source"` } type Source struct { @@ -47,7 +46,7 @@ func ParseSpecFromFile(file string) (ApplicationSpec, error) { return ApplicationSpec{}, nil } -func ParseSpecFromValue(name, repo, revision, path string, refresh time.Duration) (ApplicationSpec, error) { +func ParseSpecFromValue(name, repo, revision, path, refresh string) (ApplicationSpec, error) { if repo == "" { return ApplicationSpec{}, errors.New("The git repository not specified") } diff --git a/internal/core/registery.go b/internal/core/registery.go index 3788ad5..759e67a 100644 --- a/internal/core/registery.go +++ b/internal/core/registery.go @@ -24,9 +24,3 @@ func Register(app *application.Application) error { return nil } - -func Run() { - for _, app := range Applications { - go app.Run() - } -} diff --git a/server/routes.go b/server/routes.go index 4a2a4b7..9c0fe47 100644 --- a/server/routes.go +++ b/server/routes.go @@ -19,6 +19,7 @@ package server import ( "embed" "fmt" + meltcd_api "meltred/meltcd/api" "meltred/meltcd/internal/core" "meltred/meltcd/version" "net" @@ -71,7 +72,6 @@ func Serve(ln net.Listener, origins string, verboseOutput bool) error { })) api := app.Group("api") - api.Get("/", func(c *fiber.Ctx) error { return c.JSON(app.Stack()) }) @@ -79,16 +79,15 @@ func Serve(ln net.Listener, origins string, verboseOutput bool) error { return c.Status(200).SendString(fmt.Sprintf("MeltCD is running (version: %s)\n", version.Version)) }) + application := api.Group("application") + application.Post("/register", meltcd_api.Register) + err := core.Setup() if err != nil { log.Error(err) os.Exit(1) } - go func() { - core.Run() - }() - log.Infof("Listening on %s (version: %s)", ln.Addr(), version.Version) signals := make(chan os.Signal, 1) From 14e4591875f9307967bc2f81622bd2d346b9f2ce Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Tue, 21 Nov 2023 23:25:13 +0530 Subject: [PATCH 08/10] added cmd for registering an application --- cmd/meltcd/app.go | 32 ++++++++++++++++++++++++++++---- cmd/meltcd/util.go | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 cmd/meltcd/util.go diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index b3b8a77..8b8cae1 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -17,9 +17,13 @@ limitations under the License. package meltcd import ( + "bytes" + "encoding/json" + "errors" + "fmt" "meltred/meltcd/internal/core/application" + "net/http" - "github.com/charmbracelet/log" "github.com/spf13/cobra" ) @@ -27,7 +31,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { var spec application.ApplicationSpec if len(args) == 0 { - log.Info("Creating application with Specification file") + info("Creating application with Specification file") // Creating application without application name // means using a file file, err := cmd.Flags().GetString("file") @@ -41,7 +45,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } else { // creating application with application name // means using arguments - log.Info("Creating application using arguments") + info("Creating application using arguments") name := args[0] repo, err := cmd.Flags().GetString("repo") @@ -63,7 +67,27 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } } - _ = application.New(spec) + app := application.New(spec) + payload, err := json.Marshal(app) + if err != nil { + return err + } + + res, err := http.Post(fmt.Sprintf("%s/api/application/register", getHost()), "application/json", bytes.NewReader(payload)) + if err != nil { + return err + } + + var responseBody struct { + Code int `json:"code"` + Message string `json:"message"` + } + + if res.StatusCode != 202 { + error_msg("Server not respond with 202: Error %s", responseBody.Message) + return errors.New("Something went wrong") + } + info("New Application created") return nil } diff --git a/cmd/meltcd/util.go b/cmd/meltcd/util.go new file mode 100644 index 0000000..65e6e94 --- /dev/null +++ b/cmd/meltcd/util.go @@ -0,0 +1,26 @@ +package meltcd + +import ( + "fmt" + "os" +) + +func getHost() string { + // TODO: remove edge case like `/` in ending of env var + // but we are add `/` so this will make the url invalid + // MAKE IT MORE NEAT + server := "http://127.0.0.1:11771" + if os.Getenv("MELTCD_SERVER") != "" { + server = os.Getenv("MELTCD_SERVER") + } + + return server +} + +func info(text string, args ...any) { + fmt.Printf(text+"\n", args...) +} + +func error_msg(text string, args ...any) { + fmt.Printf(text+"\n", args...) +} From 1f353b7f63f9ed141d33fbbd758c109c15e59ff4 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Wed, 22 Nov 2023 00:10:07 +0530 Subject: [PATCH 09/10] refactor(cmd): removeing / from MELTCD_SERVER env var with strings.CutSuffix Signed-off-by: Kunal Singh --- cmd/meltcd/util.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/meltcd/util.go b/cmd/meltcd/util.go index 65e6e94..f016f73 100644 --- a/cmd/meltcd/util.go +++ b/cmd/meltcd/util.go @@ -3,15 +3,13 @@ package meltcd import ( "fmt" "os" + "strings" ) func getHost() string { - // TODO: remove edge case like `/` in ending of env var - // but we are add `/` so this will make the url invalid - // MAKE IT MORE NEAT server := "http://127.0.0.1:11771" if os.Getenv("MELTCD_SERVER") != "" { - server = os.Getenv("MELTCD_SERVER") + server, _ = strings.CutSuffix(os.Getenv("MELTCD_SERVER"), "/") } return server From 5b83c67069682c132f7ee57834496d4ae5a22c79 Mon Sep 17 00:00:00 2001 From: Kunal Singh Date: Wed, 22 Nov 2023 00:19:19 +0530 Subject: [PATCH 10/10] fix: lint Signed-off-by: Kunal Singh --- cmd/meltcd/app.go | 7 ++++--- cmd/meltcd/util.go | 2 +- internal/core/application/app.go | 17 +++++++++-------- internal/core/application/set.go | 4 ++-- internal/core/application/spec.go | 16 ++++++++-------- internal/core/registery.go | 3 +-- 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/cmd/meltcd/app.go b/cmd/meltcd/app.go index 8b8cae1..232e469 100644 --- a/cmd/meltcd/app.go +++ b/cmd/meltcd/app.go @@ -28,7 +28,7 @@ import ( ) func createNewApplication(cmd *cobra.Command, args []string) error { - var spec application.ApplicationSpec + var spec application.Spec if len(args) == 0 { info("Creating application with Specification file") @@ -77,6 +77,7 @@ func createNewApplication(cmd *cobra.Command, args []string) error { if err != nil { return err } + defer res.Body.Close() var responseBody struct { Code int `json:"code"` @@ -84,8 +85,8 @@ func createNewApplication(cmd *cobra.Command, args []string) error { } if res.StatusCode != 202 { - error_msg("Server not respond with 202: Error %s", responseBody.Message) - return errors.New("Something went wrong") + errorMsg("server not respond with 202: error %s", responseBody.Message) + return errors.New("something went wrong") } info("New Application created") diff --git a/cmd/meltcd/util.go b/cmd/meltcd/util.go index f016f73..3f0e50c 100644 --- a/cmd/meltcd/util.go +++ b/cmd/meltcd/util.go @@ -19,6 +19,6 @@ func info(text string, args ...any) { fmt.Printf(text+"\n", args...) } -func error_msg(text string, args ...any) { +func errorMsg(text string, args ...any) { fmt.Printf(text+"\n", args...) } diff --git a/internal/core/application/app.go b/internal/core/application/app.go index 0dc71e6..5a3f7eb 100644 --- a/internal/core/application/app.go +++ b/internal/core/application/app.go @@ -30,20 +30,20 @@ type Application struct { Name string `json:"name"` Source Source `json:"source"` RefreshTimer string `json:"refresh_timer"` // Timer to check for Sync format of "3m50s" - Health ApplicationHealth `json:"health"` + Health Health `json:"health"` LiveState swarm.ServiceSpec `json:"live_state"` } -type ApplicationHealth int +type Health int const ( - Healthy ApplicationHealth = iota + Healthy Health = iota Progressing Degraded Suspended ) -func New(spec ApplicationSpec) Application { +func New(spec Spec) Application { return Application{ Name: spec.Name, RefreshTimer: spec.RefreshTimer, @@ -85,6 +85,7 @@ func (app *Application) GetService() (swarm.ServiceSpec, error) { if errors.Is(err, git.ErrRepositoryAlreadyExists) { // fetch & pull request // don't clone again + log.Info("Repo already exits", "repo", app.Source.RepoURL) } if err != nil { return swarm.ServiceSpec{}, err @@ -100,15 +101,15 @@ func (app *Application) GetService() (swarm.ServiceSpec, error) { // // Whether or not the live state matches the target state. // Is the deployed application the same as Git says it should be? -func (app *Application) SyncStatus(targetState swarm.ServiceSpec) bool { - //TODO +func (app *Application) SyncStatus(_ swarm.ServiceSpec) bool { + // TODO return false } // Sync // The process of making an application move to its target state. // E.g. by applying changes to a docker swarm cluster. -func (app *Application) Sync(targetState swarm.ServiceSpec) error { - //TODO +func (app *Application) Sync(_ swarm.ServiceSpec) error { + // TODO return nil } diff --git a/internal/core/application/set.go b/internal/core/application/set.go index 98de258..8654fa3 100644 --- a/internal/core/application/set.go +++ b/internal/core/application/set.go @@ -16,6 +16,6 @@ limitations under the License. package application -type ApplicationSet struct { - applications []Application +type Set struct { + Applications []Application } diff --git a/internal/core/application/spec.go b/internal/core/application/spec.go index f7974db..ae1bd6a 100644 --- a/internal/core/application/spec.go +++ b/internal/core/application/spec.go @@ -22,7 +22,7 @@ import ( "github.com/charmbracelet/log" ) -type ApplicationSpec struct { +type Spec struct { Name string `json:"name" yaml:"name"` RefreshTimer string `json:"refresh_timer" yaml:"refresh_timer"` // number of minutes Source Source `json:"source" yaml:"source"` @@ -35,27 +35,27 @@ type Source struct { } // parse an application from yaml source -func ParseSpecFromFile(file string) (ApplicationSpec, error) { +func ParseSpecFromFile(file string) (Spec, error) { if file == "" { log.Error("Application specification file not specified") - return ApplicationSpec{}, errors.New("Application specification file not specified") + return Spec{}, errors.New("Application specification file not specified") } log.Info("Using file", "Service file", file) - return ApplicationSpec{}, nil + return Spec{}, nil } -func ParseSpecFromValue(name, repo, revision, path, refresh string) (ApplicationSpec, error) { +func ParseSpecFromValue(name, repo, revision, path, refresh string) (Spec, error) { if repo == "" { - return ApplicationSpec{}, errors.New("The git repository not specified") + return Spec{}, errors.New("the git repository not specified") } if path == "" { - return ApplicationSpec{}, errors.New("The path to Service file not specified") + return Spec{}, errors.New("the path to Service file not specified") } - return ApplicationSpec{ + return Spec{ Name: name, RefreshTimer: refresh, Source: Source{ diff --git a/internal/core/registery.go b/internal/core/registery.go index 759e67a..e56f94f 100644 --- a/internal/core/registery.go +++ b/internal/core/registery.go @@ -1,7 +1,6 @@ package core import ( - "errors" "fmt" "meltred/meltcd/internal/core/application" @@ -15,7 +14,7 @@ func Register(app *application.Application) error { for _, regApp := range Applications { if regApp.Name == app.Name { - return errors.New(fmt.Sprintf("App already exists with name: %s\n", app.Name)) + return fmt.Errorf("app already exists with name: %s", app.Name) } }