diff --git a/go.mod b/go.mod index d283fbd..55b7623 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/daytonaio/daytona-provider-fly go 1.22.2 require ( - github.com/daytonaio/daytona v0.15.0 + github.com/daytonaio/daytona v0.19.0 + github.com/docker/docker v26.1.0+incompatible github.com/hashicorp/go-hclog v1.6.2 github.com/hashicorp/go-plugin v1.6.0 github.com/sirupsen/logrus v1.9.3 @@ -12,16 +13,22 @@ require ( require ( code.gitea.io/sdk/gitea v0.17.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Khan/genqlient v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/PuerkitoBio/rehttp v1.4.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-github v17.0.0+incompatible // indirect github.com/google/go-querystring v1.1.0 // indirect @@ -36,7 +43,12 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/superfly/graphql v0.2.4 // indirect @@ -50,8 +62,11 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/sdk v1.27.0 // indirect go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect @@ -61,8 +76,10 @@ require ( golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect google.golang.org/grpc v1.63.0 // indirect google.golang.org/protobuf v1.34.1 // indirect + gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index 15dd522..bf2bcac 100644 --- a/go.sum +++ b/go.sum @@ -599,11 +599,15 @@ code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2mia dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk= github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM= +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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/rehttp v1.4.0 h1:rIN7A2s+O9fmHUM1vUcInvlHj9Ysql4hE+Y0wcl/xk8= github.com/PuerkitoBio/rehttp v1.4.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= @@ -656,15 +660,29 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= -github.com/daytonaio/daytona v0.15.0 h1:NfO+GVDOI33ES1yIQBRPiQgKEGuHEhKVtridH4CNIpw= -github.com/daytonaio/daytona v0.15.0/go.mod h1:k4zx6Oj4S4NSKAGBplY6wQtpSb0OMBKcdpRsQQEdTaU= +github.com/daytonaio/daytona v0.17.0 h1:O5x/3aFuKt+yENKRRBQ4QF9/vJoIpPZe9a8Ja8N43A0= +github.com/daytonaio/daytona v0.17.0/go.mod h1:sJ4XQY8omQIW9wn37rtY+gyzxVmE1CupsG4QBD085u0= +github.com/daytonaio/daytona v0.19.0 h1:jzCIGykCE3lMrAv2nfyHbj7iEAIuGvspPwzB5hL3XGg= +github.com/daytonaio/daytona v0.19.0/go.mod h1:sJ4XQY8omQIW9wn37rtY+gyzxVmE1CupsG4QBD085u0= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v26.1.0+incompatible h1:W1G9MPNbskA6VZWL7b3ZljTh0pXI68FpINx0GKaOdaM= +github.com/docker/docker v26.1.0+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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -713,6 +731,8 @@ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= @@ -825,9 +845,12 @@ github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2e github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -859,6 +882,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +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/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= @@ -894,8 +918,18 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1: github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +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.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -933,6 +967,8 @@ github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -986,13 +1022,21 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTS go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1186,6 +1230,8 @@ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1352,6 +1398,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1361,6 +1408,7 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1373,6 +1421,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 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= @@ -1594,10 +1644,13 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -1681,6 +1734,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index e9a0f4d..6037451 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -18,22 +18,26 @@ import ( ) type FlyProvider struct { - BasePath *string - ServerDownloadUrl *string - ServerVersion *string - ServerUrl *string - NetworkKey *string - ServerApiUrl *string - LogsDir *string + BasePath *string + DaytonaDownloadUrl *string + DaytonaVersion *string + ServerUrl *string + NetworkKey *string + ApiUrl *string + ApiPort *uint32 + ServerPort *uint32 + LogsDir *string } // Initialize initializes the provider with the given configuration. func (p *FlyProvider) Initialize(req provider.InitializeProviderRequest) (*util.Empty, error) { p.BasePath = &req.BasePath - p.ServerDownloadUrl = &req.ServerDownloadUrl - p.ServerVersion = &req.ServerVersion + p.DaytonaDownloadUrl = &req.DaytonaDownloadUrl + p.DaytonaVersion = &req.DaytonaVersion p.ServerUrl = &req.ServerUrl - p.ServerApiUrl = &req.ServerApiUrl + p.ApiUrl = &req.ApiUrl + p.ApiPort = &req.ApiPort + p.ServerPort = &req.ServerPort p.LogsDir = &req.LogsDir p.NetworkKey = &req.NetworkKey @@ -56,7 +60,22 @@ func (p *FlyProvider) GetDefaultTargets() (*[]provider.ProviderTarget, error) { return new([]provider.ProviderTarget), nil } -func (p *FlyProvider) CreateWorkspace(_ *provider.WorkspaceRequest) (*util.Empty, error) { +func (p *FlyProvider) CreateWorkspace(workspaceReq *provider.WorkspaceRequest) (*util.Empty, error) { + logWriter, cleanupFunc := p.getWorkspaceLogWriter(workspaceReq.Workspace.Id) + defer cleanupFunc() + + targetOptions, err := types.ParseTargetOptions(workspaceReq.TargetOptions) + if err != nil { + logWriter.Write([]byte("Failed to parse target options: " + err.Error() + "\n")) + return nil, err + } + + if err := flyutil.CreateApp(workspaceReq.Workspace, targetOptions); err != nil { + logWriter.Write([]byte("Failed to create workspace: " + err.Error() + "\n")) + return nil, err + } + logWriter.Write([]byte("Workspace created.\n")) + return new(util.Empty), nil } @@ -68,7 +87,22 @@ func (p *FlyProvider) StopWorkspace(_ *provider.WorkspaceRequest) (*util.Empty, return new(util.Empty), nil } -func (p *FlyProvider) DestroyWorkspace(_ *provider.WorkspaceRequest) (*util.Empty, error) { +func (p *FlyProvider) DestroyWorkspace(workspaceReq *provider.WorkspaceRequest) (*util.Empty, error) { + logWriter, cleanupFunc := p.getWorkspaceLogWriter(workspaceReq.Workspace.Id) + defer cleanupFunc() + + targetOptions, err := types.ParseTargetOptions(workspaceReq.TargetOptions) + if err != nil { + logWriter.Write([]byte("Failed to parse target options: " + err.Error() + "\n")) + return nil, err + } + + if err := flyutil.DeleteApp(workspaceReq.Workspace, targetOptions); err != nil { + logWriter.Write([]byte("Failed to destroy workspace: " + err.Error() + "\n")) + return nil, err + } + logWriter.Write([]byte("Workspace destroyed.\n")) + return new(util.Empty), nil } @@ -94,10 +128,10 @@ func (p *FlyProvider) GetWorkspaceInfo(workspaceReq *provider.WorkspaceRequest) } func (p *FlyProvider) CreateProject(projectReq *provider.ProjectRequest) (*util.Empty, error) { - if p.ServerDownloadUrl == nil { - return nil, errors.New("serverDownloadUrl not set. Did you forget to call Initialize") + if p.DaytonaDownloadUrl == nil { + return nil, errors.New("DaytonaDownloadUrl not set. Did you forget to call Initialize") } - logWriter, cleanupFunc := p.getLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) + logWriter, cleanupFunc := p.getProjectLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) targetOptions, err := types.ParseTargetOptions(projectReq.TargetOptions) if err != nil { @@ -105,8 +139,8 @@ func (p *FlyProvider) CreateProject(projectReq *provider.ProjectRequest) (*util. return nil, err } - initScript := util.GetProjectStartScript(*p.ServerDownloadUrl, projectReq.Project.ApiKey) - machine, err := flyutil.CreateMachine(projectReq.Project, targetOptions, initScript) + initScript := util.GetProjectStartScript(*p.DaytonaDownloadUrl, projectReq.Project.ApiKey) + machine, err := flyutil.CreateMachine(projectReq.Project, targetOptions, projectReq.ContainerRegistry, logWriter, initScript) if err != nil { logWriter.Write([]byte("Failed to create machine: " + err.Error() + "\n")) return nil, err @@ -129,7 +163,7 @@ func (p *FlyProvider) CreateProject(projectReq *provider.ProjectRequest) (*util. } func (p *FlyProvider) StartProject(projectReq *provider.ProjectRequest) (*util.Empty, error) { - logWriter, cleanupFunc := p.getLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) + logWriter, cleanupFunc := p.getProjectLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) defer cleanupFunc() targetOptions, err := types.ParseTargetOptions(projectReq.TargetOptions) @@ -148,7 +182,7 @@ func (p *FlyProvider) StartProject(projectReq *provider.ProjectRequest) (*util.E } func (p *FlyProvider) StopProject(projectReq *provider.ProjectRequest) (*util.Empty, error) { - logWriter, cleanupFunc := p.getLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) + logWriter, cleanupFunc := p.getProjectLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) defer cleanupFunc() targetOptions, err := types.ParseTargetOptions(projectReq.TargetOptions) @@ -167,7 +201,7 @@ func (p *FlyProvider) StopProject(projectReq *provider.ProjectRequest) (*util.Em } func (p *FlyProvider) DestroyProject(projectReq *provider.ProjectRequest) (*util.Empty, error) { - logWriter, cleanupFunc := p.getLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) + logWriter, cleanupFunc := p.getProjectLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) defer cleanupFunc() targetOptions, err := types.ParseTargetOptions(projectReq.TargetOptions) @@ -190,7 +224,7 @@ func (p *FlyProvider) GetProjectInfo(projectReq *provider.ProjectRequest) (*work } func (p *FlyProvider) getProjectInfo(projectReq *provider.ProjectRequest) (*workspace.ProjectInfo, error) { - logWriter, cleanupFunc := p.getLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) + logWriter, cleanupFunc := p.getProjectLogWriter(projectReq.Project.WorkspaceId, projectReq.Project.Name) defer cleanupFunc() targetOptions, err := types.ParseTargetOptions(projectReq.TargetOptions) @@ -223,7 +257,21 @@ func (p *FlyProvider) getProjectInfo(projectReq *provider.ProjectRequest) (*work }, nil } -func (p *FlyProvider) getLogWriter(workspaceId string, projectName string) (io.Writer, func()) { +func (p *FlyProvider) getWorkspaceLogWriter(workspaceId string) (io.Writer, func()) { + logWriter := io.MultiWriter(&logwriters.InfoLogWriter{}) + cleanupFunc := func() {} + + if p.LogsDir != nil { + loggerFactory := logger.NewLoggerFactory(*p.LogsDir) + wsLogWriter := loggerFactory.CreateWorkspaceLogger(workspaceId) + logWriter = io.MultiWriter(&logwriters.InfoLogWriter{}, wsLogWriter) + cleanupFunc = func() { wsLogWriter.Close() } + } + + return logWriter, cleanupFunc +} + +func (p *FlyProvider) getProjectLogWriter(workspaceId string, projectName string) (io.Writer, func()) { logWriter := io.MultiWriter(&logwriters.InfoLogWriter{}) cleanupFunc := func() {} diff --git a/pkg/provider/provider_test.go b/pkg/provider/provider_test.go index 2e371f9..4cdd432 100644 --- a/pkg/provider/provider_test.go +++ b/pkg/provider/provider_test.go @@ -107,12 +107,12 @@ func TestDestroyProject(t *testing.T) { func init() { _, err := flyProvider.Initialize(provider.InitializeProviderRequest{ - BasePath: "/tmp/workspaces", - ServerDownloadUrl: "https://download.daytona.io/daytona/install.sh", - ServerVersion: "latest", - ServerUrl: "", - ServerApiUrl: "", - LogsDir: "/tmp/logs", + BasePath: "/tmp/workspaces", + DaytonaDownloadUrl: "https://download.daytona.io/daytona/install.sh", + DaytonaVersion: "latest", + ServerUrl: "", + ApiUrl: "", + LogsDir: "/tmp/logs", }) if err != nil { panic(err) diff --git a/pkg/provider/util/fly.go b/pkg/provider/util/fly.go index dea8502..c5039fe 100644 --- a/pkg/provider/util/fly.go +++ b/pkg/provider/util/fly.go @@ -2,41 +2,91 @@ package util import ( "context" + "crypto/sha256" + "encoding/hex" "fmt" "io" "net/http" + "regexp" "slices" "time" "github.com/daytonaio/daytona-provider-fly/internal" "github.com/daytonaio/daytona-provider-fly/pkg/types" + "github.com/daytonaio/daytona/pkg/containerregistry" + "github.com/daytonaio/daytona/pkg/docker" "github.com/daytonaio/daytona/pkg/workspace" + "github.com/docker/docker/client" log "github.com/sirupsen/logrus" "github.com/superfly/fly-go" "github.com/superfly/fly-go/flaps" "github.com/superfly/fly-go/tokens" ) -// CreateMachine creates a new machine for the provided workspace. -func CreateMachine(project *workspace.Project, opts *types.TargetOptions, initScript string) (*fly.Machine, error) { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) +const ( + registryServer = "registry.fly.io" + registryUser = "x" +) + +// CreateApp creates a new app for the provided workspace. +func CreateApp(workspace *workspace.Workspace, opts *types.TargetOptions) error { + appName := getResourceName(workspace.Id) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { - return nil, err + return err + } + + err = flapsClient.CreateApp(context.Background(), appName, opts.OrgSlug) + if err != nil { + return err + } + + return flapsClient.WaitForApp(context.Background(), appName) +} + +// DeleteApp deletes the app associated with the provided workspace. +func DeleteApp(workspace *workspace.Workspace, opts *types.TargetOptions) error { + appName := getResourceName(workspace.Id) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) + if err != nil { + return err + } + + // TODO: use delete method from flaps client when implemented in sdk + path := fmt.Sprintf("/apps/%s", appName) + req, err := flapsClient.NewRequest(context.Background(), http.MethodDelete, path, nil, nil) + if err != nil { + return err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusAccepted { + return fmt.Errorf("unexpected error while deleting the app status code: %d", resp.StatusCode) } - err = flapsClient.CreateApp(context.Background(), machineName, opts.OrgSlug) + return nil +} + +// CreateMachine creates a new machine for the provided workspace. +func CreateMachine(project *workspace.Project, opts *types.TargetOptions, containerRegistry *containerregistry.ContainerRegistry, logWriter io.Writer, initScript string) (*fly.Machine, error) { + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return nil, err } - err = flapsClient.WaitForApp(context.Background(), machineName) + image, err := deployImage(project, containerRegistry, logWriter, *opts.AuthToken) if err != nil { return nil, err } volume, err := flapsClient.CreateVolume(context.Background(), fly.CreateVolumeRequest{ - Name: getVolumeName(project.WorkspaceId), + Name: getVolumeName(project.Name), SizeGb: &opts.DiskSize, Region: opts.Region, }) @@ -50,10 +100,10 @@ func CreateMachine(project *workspace.Project, opts *types.TargetOptions, initSc } return flapsClient.Launch(context.Background(), fly.LaunchMachineInput{ - Name: machineName, + Name: getResourceName(project.Name), Config: &fly.MachineConfig{ VMSize: opts.Size, - Image: project.Image, + Image: image, Mounts: []fly.MachineMount{ { Name: volume.Name, @@ -75,12 +125,13 @@ func CreateMachine(project *workspace.Project, opts *types.TargetOptions, initSc // It returns true if the machine is in a known state (created, started, or stopped), // otherwise it returns false. func IsMachineReady(project *workspace.Project, opts *types.TargetOptions) bool { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return false } + machineName := getResourceName(project.Name) machine, err := findMachine(flapsClient, machineName) if err != nil { return false @@ -92,17 +143,18 @@ func IsMachineReady(project *workspace.Project, opts *types.TargetOptions) bool // StartMachine starts the machine for the provided workspace. func StartMachine(project *workspace.Project, opts *types.TargetOptions) error { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return err } - err = flapsClient.WaitForApp(context.Background(), machineName) + err = flapsClient.WaitForApp(context.Background(), appName) if err != nil { return fmt.Errorf("there was an issue waiting for the app: %w", err) } + machineName := getResourceName(project.Name) machine, err := findMachine(flapsClient, machineName) if err != nil { return err @@ -121,12 +173,13 @@ func StartMachine(project *workspace.Project, opts *types.TargetOptions) error { // StopMachine stops the machine for the provided workspace. func StopMachine(project *workspace.Project, opts *types.TargetOptions) error { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return err } + machineName := getResourceName(project.Name) machine, err := findMachine(flapsClient, machineName) if err != nil { return err @@ -137,51 +190,44 @@ func StopMachine(project *workspace.Project, opts *types.TargetOptions) error { // DeleteMachine deletes the machine for the provided workspace. func DeleteMachine(project *workspace.Project, opts *types.TargetOptions) error { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) - if err != nil { - return err - } - - // TODO: use delete method from flaps client when implemented in sdk - path := fmt.Sprintf("/apps/%s", machineName) - req, err := flapsClient.NewRequest(context.Background(), http.MethodDelete, path, nil, nil) + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return err } - resp, err := http.DefaultClient.Do(req) + machineName := getResourceName(project.Name) + machine, err := findMachine(flapsClient, machineName) if err != nil { return err } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusAccepted { - return fmt.Errorf("unexpected error while deleting the app status code: %d", resp.StatusCode) - } - return nil + return flapsClient.Destroy(context.Background(), fly.RemoveMachineInput{ + ID: machine.ID, + Kill: true, + }, "") } // GetMachine returns the machine for the provided workspace. func GetMachine(project *workspace.Project, opts *types.TargetOptions) (*fly.Machine, error) { - machineName := getMachineName(project.WorkspaceId) - flapsClient, err := createFlapsClient(machineName, *opts.AuthToken) + appName := getResourceName(project.WorkspaceId) + flapsClient, err := createFlapsClient(appName, *opts.AuthToken) if err != nil { return nil, err } + machineName := getResourceName(project.Name) return findMachine(flapsClient, machineName) } // GetMachineLogs fetches app logs for a specified machine and writes the fetched log entries to the logger. func GetMachineLogs(project *workspace.Project, opts *types.TargetOptions, machineId string, logger io.Writer) error { - machineName := getMachineName(project.WorkspaceId) + appName := getResourceName(project.WorkspaceId) fly.SetBaseURL("https://api.fly.io") client := fly.NewClientFromOptions(fly.ClientOptions{ Tokens: tokens.Parse(*opts.AuthToken), - Name: machineName, + Name: appName, Version: internal.Version, }) @@ -192,13 +238,13 @@ func GetMachineLogs(project *workspace.Project, opts *types.TargetOptions, machi } }() - return pollLogs(outLog, client, machineName, opts.Region, machineId) + return pollLogs(outLog, client, appName, opts.Region, machineId) } // createFlapsClient creates a new flaps client. -func createFlapsClient(machineName string, accessToken string) (*flaps.Client, error) { +func createFlapsClient(appName string, accessToken string) (*flaps.Client, error) { return flaps.NewWithOptions(context.Background(), flaps.NewClientOpts{ - AppName: machineName, + AppName: appName, Tokens: tokens.Parse(accessToken), Logger: log.New(), }) @@ -220,18 +266,22 @@ func findMachine(flapsClient *flaps.Client, machineName string) (*fly.Machine, e return nil, fmt.Errorf("machine %s not found", machineName) } -// getMachineName generates a machine name for the provided workspace. -func getMachineName(workspaceId string) string { - return fmt.Sprintf("daytona-%s", workspaceId) +// getResourceName generates a machine name for the provided workspace. +func getResourceName(identifier string) string { + return fmt.Sprintf("daytona-%s", identifier) } // getVolumeName generates a volume name for the provided workspace. -func getVolumeName(workspaceId string) string { - name := fmt.Sprintf("daytona_%s", workspaceId) - if len(name) > 30 { - return name[:30] +func getVolumeName(name string) string { + name = fmt.Sprintf("daytona_%s", name) + regex := regexp.MustCompile(`[^a-zA-Z0-9_]`) + formatted := regex.ReplaceAllString(name, "") + + if len(formatted) > 30 { + return formatted[:30] } - return name + + return formatted } // pollLogs fetches app logs for a specified app name, region, and machine ID using the provided fly.Client. @@ -272,3 +322,60 @@ func pollLogs(out chan<- string, client *fly.Client, appName, region, machineId } } } + +// deployImage pulls, tags, and pushes the image from private registry to the Fly.io registry. +func deployImage(project *workspace.Project, containerRegistry *containerregistry.ContainerRegistry, logWriter io.Writer, authToken string) (string, error) { + if containerRegistry == nil { + return project.Image, nil + } + + dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return "", err + } + + if isPublicImage(dockerClient, project.Image) { + return project.Image, nil + } + logWriter.Write([]byte(fmt.Sprintf("Using private container registry: %s\n", containerRegistry.Server))) + + daytonaDockerClient := docker.NewDockerClient(docker.DockerClientConfig{ApiClient: dockerClient}) + machineName := getResourceName(project.Name) + + logWriter.Write([]byte(fmt.Sprintf("Pulling private containter image %s\n", machineName))) + if err := daytonaDockerClient.PullImage(project.Image, containerRegistry, logWriter); err != nil { + logWriter.Write([]byte(fmt.Sprintf("Error pulling private containter image: %s\n", err))) + return "", err + } + + imageTag := generateImageTag(project.Image) + flyImageName := fmt.Sprintf("%s/%s:%s", registryServer, getResourceName(project.WorkspaceId), imageTag) + if err := dockerClient.ImageTag(context.Background(), project.Image, flyImageName); err != nil { + return "", err + } + + logWriter.Write([]byte(fmt.Sprintf("Pushing %s to %s make it available to fly instances\n", flyImageName, registryServer))) + flyRegistry := &containerregistry.ContainerRegistry{ + Server: registryServer, + Username: registryUser, + Password: authToken, + } + if err := daytonaDockerClient.PushImage(flyImageName, flyRegistry, logWriter); err != nil { + logWriter.Write([]byte(fmt.Sprintf("Failed to push image: %s\n", err))) + return "", err + } + + return flyImageName, nil +} + +// isPublicImage checks if the given image is a public image. +func isPublicImage(dockerClient *client.Client, imageName string) bool { + _, err := dockerClient.DistributionInspect(context.Background(), imageName, "") + return err == nil +} + +// generateImageTag generates a unique tag for the image based on its hash. +func generateImageTag(image string) string { + hash := sha256.Sum256([]byte(image)) + return hex.EncodeToString(hash[:]) +}