Skip to content

Commit

Permalink
feat: done k8s support
Browse files Browse the repository at this point in the history
  • Loading branch information
vndee committed Jul 9, 2024
1 parent 6f431d6 commit 4dbbc1c
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 60 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ Here is a list of things you can do to contribute:
- [x] Add support for Go.
- [ ] Add support for Ruby.
- [x] Add remote Docker host support.
- [ ] Add remote Kubernetes cluster support.
- [x] Add remote Kubernetes cluster support.
- [ ] Commit the last container state to the image before closing kubernetes session.
- [ ] Release version 1.0.0.

### License
Expand Down
22 changes: 11 additions & 11 deletions examples/code_runner_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
def run_python_code():
with SandboxSession(lang="python", keep_template=True, verbose=True) as session:
output = session.run("print('Hello, World!')")
print(output)
print(output.text)

output = session.run(
"import numpy as np\nprint(np.random.rand())", libraries=["numpy"]
)
print(output)
print(output.text)

session.execute_command("pip install pandas")
output = session.run("import pandas as pd\nprint(pd.__version__)")
print(output)
print(output.text)

session.copy_to_runtime("README.md", "/sandbox/data.csv")

Expand All @@ -29,13 +29,13 @@ def run_java_code():
}
""",
)
print(output)
print(output.text)


def run_javascript_code():
with SandboxSession(lang="javascript", keep_template=True, verbose=True) as session:
output = session.run("console.log('Hello, World!')")
print(output)
print(output.text)

output = session.run(
"""
Expand All @@ -45,7 +45,7 @@ def run_javascript_code():
""",
libraries=["axios"],
)
print(output)
print(output.text)


def run_cpp_code():
Expand All @@ -59,7 +59,7 @@ def run_cpp_code():
}
""",
)
print(output)
print(output.text)

output = session.run(
"""
Expand All @@ -75,7 +75,7 @@ def run_cpp_code():
}
""",
)
print(output)
print(output.text)

# run with libraries
output = session.run(
Expand All @@ -95,7 +95,7 @@ def run_cpp_code():
""",
libraries=["libstdc++"],
)
print(output)
print(output.text)


def run_go_code():
Expand All @@ -109,7 +109,7 @@ def run_go_code():
}
""",
)
print(output)
print(output.text)

# run with libraries
output = session.run(
Expand All @@ -136,7 +136,7 @@ def run_go_code():
""",
libraries=["github.com/spyzhov/ajson"],
)
print(output)
print(output.text)


if __name__ == "__main__":
Expand Down
146 changes: 141 additions & 5 deletions examples/code_runner_k8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,157 @@


def run_python_code():
with SandboxSession(lang="python", keep_template=True, verbose=True, use_kubernetes=True) as session:
with SandboxSession(
lang="python", keep_template=True, verbose=True, use_kubernetes=True
) as session:
output = session.run("print('Hello, World!')")
print(output)
print(output.text)

output = session.run(
"import numpy as np\nprint(np.random.rand())", libraries=["numpy"]
)
print(output)
print(output.text)

session.execute_command("pip install pandas")
output = session.run("import pandas as pd\nprint(pd.__version__)")
print(output)
print(output.text)

session.copy_to_runtime("README.md", "/sandbox/data.csv")


def run_java_code():
with SandboxSession(
lang="java", keep_template=True, verbose=True, use_kubernetes=True
) as session:
output = session.run(
"""
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
""",
)
print(output.text)


def run_javascript_code():
with SandboxSession(
lang="javascript", keep_template=True, verbose=True, use_kubernetes=True
) as session:
output = session.run("console.log('Hello, World!')")
print(output.text)

# TODO: Fix this
# output = session.run(
# """
# const axios = require('axios');
# axios.get('https://jsonplaceholder.typicode.com/posts/1')
# .then(response => console.log(response.data));
# """,
# libraries=["axios"],
# )
# print(output.text)


def run_cpp_code():
with SandboxSession(
lang="cpp", keep_template=True, verbose=True, use_kubernetes=True
) as session:
output = session.run(
"""
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
""",
)
print(output.text)

output = session.run(
"""
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
for (int i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
""",
)
print(output.text)

# run with libraries
output = session.run(
"""
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::reverse(v.begin(), v.end());
for (int i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
""",
libraries=["libstdc++"],
)
print(output.text)


def run_go_code():
with SandboxSession(
lang="go", keep_template=True, verbose=True, use_kubernetes=True
) as session:
output = session.run(
"""
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
""",
)
print(output.text)

# run with libraries
output = session.run(
"""
package main
import (
"fmt"
"github.com/spyzhov/ajson"
)
func main() {
fmt.Println("Hello, World!")
json := []byte(`{"price": 100}`)
root, _ := ajson.Unmarshal(json)
nodes, _ := root.JSONPath("$..price")
for _, node := range nodes {
node.SetNumeric(node.MustNumeric() * 1.25)
node.Parent().AppendObject("currency", ajson.StringNode("", "EUR"))
}
result, _ := ajson.Marshal(root)
fmt.Printf("%s", result)
}
""",
libraries=["github.com/spyzhov/ajson"],
)
print(output.text)


if __name__ == "__main__":
run_python_code()
# run_python_code()
# run_java_code()
run_javascript_code()
# run_cpp_code()
# run_go_code()
23 changes: 22 additions & 1 deletion llm_sandbox/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@
from typing import Optional, List


class ConsoleOutput:
def __init__(self, text: str):
self._text = text

@property
def text(self):
return self._text

def __str__(self):
return f"ConsoleOutput(text={self.text})"


class KubernetesConsoleOutput(ConsoleOutput):
def __init__(self, exit_code: int, text: str):
super().__init__(text)
self.exit_code = exit_code

def __str__(self):
return f"KubernetesConsoleOutput(text={self.text}, exit_code={self.exit_code})"


class Session(ABC):
def __init__(self, lang: str, verbose: bool = True, *args, **kwargs):
self.lang = lang
Expand All @@ -17,7 +38,7 @@ def close(self):
raise NotImplementedError

@abstractmethod
def run(self, code: str, libraries: Optional[List] = None):
def run(self, code: str, libraries: Optional[List] = None) -> ConsoleOutput:
raise NotImplementedError

@abstractmethod
Expand Down
40 changes: 22 additions & 18 deletions llm_sandbox/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
get_code_file_extension,
get_code_execution_command,
)
from llm_sandbox.base import Session
from llm_sandbox.base import Session, ConsoleOutput
from llm_sandbox.const import (
SupportedLanguage,
SupportedLanguageValues,
Expand Down Expand Up @@ -137,7 +137,7 @@ def close(self):
f"Image {self.image.tags[-1]} is in use by other containers. Skipping removal.."
)

def run(self, code: str, libraries: Optional[List] = None):
def run(self, code: str, libraries: Optional[List] = None) -> ConsoleOutput:
if not self.container:
raise RuntimeError(
"Session is not open. Please call open() method before running code."
Expand All @@ -151,16 +151,16 @@ def run(self, code: str, libraries: Optional[List] = None):

if self.lang == SupportedLanguage.GO:
self.execute_command("mkdir -p /example")
self.execute_command("go mod init example", worKdir="/example")
self.execute_command("go mod tidy", worKdir="/example")
self.execute_command("go mod init example", workdir="/example")
self.execute_command("go mod tidy", workdir="/example")

for lib in libraries:
command = get_libraries_installation_command(self.lang, lib)
self.execute_command(command, worKdir="/example")
for library in libraries:
command = get_libraries_installation_command(self.lang, library)
_ = self.execute_command(command, workdir="/example")
else:
for lib in libraries:
command = get_libraries_installation_command(self.lang, lib)
self.execute_command(command)
for library in libraries:
command = get_libraries_installation_command(self.lang, library)
_ = self.execute_command(command)

code_file = f"/tmp/code.{get_code_file_extension(self.lang)}"
if self.lang == SupportedLanguage.GO:
Expand All @@ -173,11 +173,11 @@ def run(self, code: str, libraries: Optional[List] = None):

self.copy_to_runtime(code_file, code_dest_file)

output = ""
output = ConsoleOutput("")
commands = get_code_execution_command(self.lang, code_dest_file)
for command in commands:
if self.lang == SupportedLanguage.GO:
output = self.execute_command(command, worKdir="/example")
output = self.execute_command(command, workdir="/example")
else:
output = self.execute_command(command)

Expand Down Expand Up @@ -224,7 +224,9 @@ def copy_to_runtime(self, src: str, dest: str):
tarstream.seek(0)
self.container.put_archive(os.path.dirname(dest), tarstream)

def execute_command(self, command: Optional[str], worKdir: Optional[str] = None):
def execute_command(
self, command: Optional[str], workdir: Optional[str] = None
) -> ConsoleOutput:
if not command:
raise ValueError("Command cannot be empty")

Expand All @@ -236,12 +238,14 @@ def execute_command(self, command: Optional[str], worKdir: Optional[str] = None)
if self.verbose:
print(f"Executing command: {command}")

if worKdir:
_, exec_log = self.container.exec_run(
command, stream=True, tty=True, workdir=worKdir
if workdir:
exit_code, exec_log = self.container.exec_run(
command, stream=True, tty=True, workdir=workdir
)
else:
_, exec_log = self.container.exec_run(command, stream=True, tty=True)
exit_code, exec_log = self.container.exec_run(
command, stream=True, tty=True
)

output = ""
if self.verbose:
Expand All @@ -253,4 +257,4 @@ def execute_command(self, command: Optional[str], worKdir: Optional[str] = None)
if self.verbose:
print(chunk_str, end="")

return output
return ConsoleOutput(output)
Loading

0 comments on commit 4dbbc1c

Please sign in to comment.