Skip to content

Commit e8d72c3

Browse files
committed
Fix bug with tui not exiting and use absolute paths for dockerfile+context in sample
1 parent 08b463a commit e8d72c3

File tree

7 files changed

+144
-19
lines changed

7 files changed

+144
-19
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,6 @@ __debug_bin*
5252

5353
__pycache__
5454
*.egg-info
55+
56+
57+
Pipfile.lock

.vscode/launch.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
"up",
122122
"-v=3",
123123
"-o=${workspaceFolder}/out",
124-
"--profiling=${workspaceFolder}/out/k2.prof",
124+
"--profiling=${workspaceFolder}/out/deploy.prof",
125125
"${file}"
126126
],
127127
"env": {
@@ -141,7 +141,7 @@
141141
"down",
142142
"-v=3",
143143
"-o=${workspaceFolder}/out",
144-
"--profiling=${workspaceFolder}/out/k2.prof",
144+
"--profiling=${workspaceFolder}/out/destroy.prof",
145145
"${file}"
146146
],
147147
"env": {

Pipfile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[[source]]
2+
url = "https://pypi.org/simple"
3+
verify_ssl = true
4+
name = "pypi"
5+
6+
[packages]
7+
klotho = {file = "./pkg/k2/language_host/python/klothosdk"}
8+
9+
[dev-packages]
10+
debugpy = "*"
11+
12+
[requires]
13+
python_version = "3.12"

cmd/k2/down.go

+107-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
package main
22

33
import (
4+
"context"
5+
"errors"
46
"fmt"
57
"os"
68
"path/filepath"
9+
"time"
710

811
"github.com/klothoplatform/klotho/pkg/engine/debug"
12+
"github.com/klothoplatform/klotho/pkg/k2/language_host"
13+
pb "github.com/klothoplatform/klotho/pkg/k2/language_host/go"
914
"github.com/klothoplatform/klotho/pkg/k2/model"
1015
"github.com/klothoplatform/klotho/pkg/k2/orchestration"
1116
"github.com/klothoplatform/klotho/pkg/k2/stack"
17+
"github.com/klothoplatform/klotho/pkg/logging"
1218
"github.com/spf13/afero"
1319
"github.com/spf13/cobra"
20+
"go.uber.org/zap"
21+
"google.golang.org/grpc"
22+
"google.golang.org/grpc/credentials/insecure"
1423
)
1524

1625
var downConfig struct {
1726
outputPath string
27+
debugMode string
28+
debugPort int
1829
}
1930

2031
func newDownCmd() *cobra.Command {
@@ -25,10 +36,86 @@ func newDownCmd() *cobra.Command {
2536
}
2637
flags := downCommand.Flags()
2738
flags.StringVarP(&downConfig.outputPath, "output", "o", "", "Output directory")
39+
flags.StringVarP(&upConfig.debugMode, "debug", "d", "", "Debug mode")
40+
flags.IntVarP(&upConfig.debugPort, "debug-port", "p", 5678, "Language Host Debug port")
2841
return downCommand
2942

3043
}
3144

45+
func getProjectPath(ctx context.Context, inputPath string) (string, error) {
46+
langHost, addr, err := language_host.StartPythonClient(ctx, language_host.DebugConfig{
47+
Enabled: upConfig.debugMode != "",
48+
Port: upConfig.debugPort,
49+
Mode: upConfig.debugMode,
50+
}, filepath.Dir(inputPath))
51+
if err != nil {
52+
return "", err
53+
}
54+
55+
defer func() {
56+
if err := langHost.Process.Kill(); err != nil {
57+
zap.L().Warn("failed to kill Python client", zap.Error(err))
58+
}
59+
}()
60+
61+
log := logging.GetLogger(ctx).Sugar()
62+
63+
log.Debug("Waiting for Python server to start")
64+
if upConfig.debugMode != "" {
65+
// Don't add a timeout in case there are breakpoints in the language host before an address is printed
66+
<-addr.HasAddr
67+
} else {
68+
select {
69+
case <-addr.HasAddr:
70+
case <-time.After(30 * time.Second):
71+
return "", errors.New("timeout waiting for Python server to start")
72+
}
73+
}
74+
conn, err := grpc.NewClient(addr.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
75+
if err != nil {
76+
return "", fmt.Errorf("failed to connect to Python server: %w", err)
77+
}
78+
79+
defer func(conn *grpc.ClientConn) {
80+
err = conn.Close()
81+
if err != nil {
82+
zap.L().Error("failed to close connection", zap.Error(err))
83+
}
84+
}(conn)
85+
86+
client := pb.NewKlothoServiceClient(conn)
87+
88+
// make sure the ctx used later doesn't have the timeout (which is only for the IR request)
89+
irCtx := ctx
90+
if upConfig.debugMode == "" {
91+
var cancel context.CancelFunc
92+
irCtx, cancel = context.WithTimeout(irCtx, time.Second*10)
93+
defer cancel()
94+
}
95+
96+
req := &pb.IRRequest{Filename: inputPath}
97+
res, err := client.SendIR(irCtx, req)
98+
if err != nil {
99+
return "", fmt.Errorf("error sending IR request: %w", err)
100+
}
101+
102+
ir, err := model.ParseIRFile([]byte(res.GetYamlPayload()))
103+
if err != nil {
104+
return "", fmt.Errorf("error parsing IR file: %w", err)
105+
}
106+
107+
appUrn, err := model.ParseURN(ir.AppURN)
108+
if err != nil {
109+
return "", fmt.Errorf("error parsing app URN: %w", err)
110+
}
111+
112+
appUrnPath, err := model.UrnPath(*appUrn)
113+
if err != nil {
114+
return "", fmt.Errorf("error getting URN path: %w", err)
115+
}
116+
return appUrnPath, nil
117+
}
118+
32119
func down(cmd *cobra.Command, args []string) error {
33120
filePath := args[0]
34121
if _, err := os.Stat(filePath); os.IsNotExist(err) {
@@ -38,9 +125,24 @@ func down(cmd *cobra.Command, args []string) error {
38125
if err != nil {
39126
return err
40127
}
41-
project := args[1]
42-
app := args[2]
43-
env := args[3]
128+
129+
var projectPath string
130+
switch len(args) {
131+
case 1:
132+
projectPath, err = getProjectPath(cmd.Context(), absolutePath)
133+
if err != nil {
134+
return fmt.Errorf("error getting project path: %w", err)
135+
}
136+
137+
case 4:
138+
project := args[1]
139+
app := args[2]
140+
env := args[3]
141+
projectPath = filepath.Join(project, app, env)
142+
143+
default:
144+
return fmt.Errorf("invalid number of arguments (%d) expected 4", len(args))
145+
}
44146

45147
if downConfig.outputPath == "" {
46148
downConfig.outputPath = filepath.Join(filepath.Dir(absolutePath), ".k2")
@@ -52,8 +154,7 @@ func down(cmd *cobra.Command, args []string) error {
52154
cmd.SetContext(debug.WithDebugDir(cmd.Context(), debugDir))
53155
}
54156

55-
projectPath := filepath.Join(downConfig.outputPath, project, app, env)
56-
stateFile := filepath.Join(projectPath, "state.yaml")
157+
stateFile := filepath.Join(downConfig.outputPath, projectPath, "state.yaml")
57158
sm := model.NewStateManager(afero.NewOsFs(), stateFile)
58159

59160
if !sm.CheckStateFileExists() {
@@ -67,7 +168,7 @@ func down(cmd *cobra.Command, args []string) error {
67168

68169
var stackReferences []stack.Reference
69170
for name, construct := range sm.GetAllConstructs() {
70-
constructPath := filepath.Join(projectPath, name)
171+
constructPath := filepath.Join(downConfig.outputPath, projectPath, name)
71172
stackReference := stack.Reference{
72173
ConstructURN: *construct.URN,
73174
Name: name,

cmd/k2/main.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var commonCfg struct {
1818
dryRun clicommon.LevelledFlag
1919
}
2020

21-
func cli() {
21+
func cli() int {
2222
// Set up signal and panic handling to ensure cleanup is executed
2323
defer func() {
2424
if r := recover(); r != nil {
@@ -42,6 +42,12 @@ func cli() {
4242
dryRunFlag.NoOptDefVal = "true" // Allow -n to be used without a value
4343

4444
var cleanupFuncs []func()
45+
defer func() {
46+
for _, f := range cleanupFuncs {
47+
f()
48+
}
49+
}()
50+
4551
initCommand := newInitCommand()
4652

4753
upCommand := newUpCmd()
@@ -50,12 +56,6 @@ func cli() {
5056
downCommand := newDownCmd()
5157
cleanupFuncs = append(cleanupFuncs, clicommon.SetupCoreCommand(downCommand, &commonCfg.CommonConfig))
5258

53-
defer func() {
54-
for _, f := range cleanupFuncs {
55-
f()
56-
}
57-
}()
58-
5959
var irCommand = &cobra.Command{
6060
Use: "ir [file path]",
6161
Short: "Run the IR command",
@@ -77,10 +77,11 @@ func cli() {
7777

7878
if err := rootCmd.Execute(); err != nil {
7979
logging.GetLogger(rootCmd.Context()).Error("Failed to execute command", zap.Error(err))
80-
os.Exit(1)
80+
return 1
8181
}
82+
return 0
8283
}
8384

8485
func main() {
85-
cli()
86+
os.Exit(cli())
8687
}

pkg/k2/language_host/python/samples/infra-api.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
import klotho.aws as aws
33

44
api = aws.Api("my-api")
5-
api.route_to("/hello", infra.container)
5+
api.route_to("/", infra.container)

pkg/k2/language_host/python/samples/infra.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from pathlib import Path
23

34
import klotho
45
import klotho.aws as aws
@@ -16,4 +17,10 @@
1617
), # Default to 'us-east-1' or the environment variable value
1718
)
1819

19-
container = aws.Container("my-container", dockerfile="Dockerfile")
20+
dir = Path(__file__).parent.absolute()
21+
22+
container = aws.Container(
23+
"my-container",
24+
dockerfile=str(dir / "Dockerfile"),
25+
context=str(dir),
26+
)

0 commit comments

Comments
 (0)