Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

work in progress - remote run #3986

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions paasta_tools/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ def make_app(global_config=None):
"service.instance.tasks.task",
"/v1/services/{service}/{instance}/tasks/{task_id}",
)
config.add_route(
"service.instance.remote_run",
"/v1/services/{service}/{instance}/remote_run",
)
Qmando marked this conversation as resolved.
Show resolved Hide resolved
config.add_route("service.list", "/v1/services/{service}")
config.add_route("services", "/v1/services")
config.add_route(
Expand Down
46 changes: 46 additions & 0 deletions paasta_tools/api/api_docs/oapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,52 @@ paths:
summary: Get mesos task of service_name.instance_name by task_id
tags:
- service
/services/{service}/{instance}/remote_run:
post:
operationId: remote_run
requestBody:
content:
application/json:
schema:
type: object
properties:
interactive:
type: bool
user:
type: string
image:
type: string
required:
- interactive
Qmando marked this conversation as resolved.
Show resolved Hide resolved
- user
required: true
parameters:
- description: Service name
in: path
name: service
required: true
schema:
type: string
- description: Instance name
in: path
name: instance
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
type: string
description: The service is delayed for these possible reasons
"404":
description: Deployment key not found
"500":
description: Failure
summary: Launch a remote-run pod
tags:
- service
/version:
get:
operationId: showVersion
Expand Down
46 changes: 46 additions & 0 deletions paasta_tools/api/api_docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,52 @@
}
]
}
},
"/services/{service}/{instance}/remote_run": {
"post": {
"responses": {
"200": {
"description": "It worked!",
"schema": {
"type": "string"
}
},
"404": {
"description": "Deployment key not found"
},
"500": {
"description": "Failure"
}
},
"summary": "Do a remote run",
"operationId": "remote_run",
"tags": [
"service"
],
"parameters": [
{
"in": "path",
"description": "Service name",
"name": "service",
"required": true,
"type": "string"
},
{
"in": "path",
"description": "Instance name",
"name": "instance",
"required": true,
"type": "string"
},
{
"in": "query",
"description": "Username",
"name": "user",
"required": true,
"type": "string"
}
]
}
}
},
"definitions": {
Expand Down
22 changes: 22 additions & 0 deletions paasta_tools/api/views/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import paasta_tools.mesos.exceptions as mesos_exceptions
from paasta_tools import paasta_remote_run
from paasta_tools import paasta_remote_run_2
from paasta_tools import tron_tools
from paasta_tools.api import settings
from paasta_tools.api.views.exception import ApiFailure
Expand Down Expand Up @@ -385,3 +386,24 @@ def instance_mesh_status(request):
raise ApiFailure(error_message, 500)

return instance_mesh


@view_config(
route_name="service.instance.remote_run", request_method="POST", renderer="json"
)
def remote_run(request):
service = request.swagger_data.get("service")
instance = request.swagger_data.get("instance")
user = request.swagger_data.get("user")
interactive = request.swagger_data.get("interactive", True)
recreate = request.swagger_data.get("recreate", True)

try:
response = paasta_remote_run_2.remote_run_start(
service, instance, user, settings.cluster, interactive, recreate
)
except Exception:
error_message = traceback.format_exc()
raise ApiFailure(error_message, 500)

return response
1 change: 1 addition & 0 deletions paasta_tools/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def add_subparser(command, subparsers):
"pause_service_autoscaler": "pause_service_autoscaler",
"push-to-registry": "push_to_registry",
"remote-run": "remote_run",
"remote-run-2": "remote_run_2",
"rollback": "rollback",
"secret": "secret",
"security-check": "security_check",
Expand Down
180 changes: 180 additions & 0 deletions paasta_tools/cli/cmds/remote_run_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#!/usr/bin/env python
# Copyright 2015-2016 Yelp Inc.
#
# 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.
import json
import os
import subprocess
import sys
import time

from paasta_tools.api.client import get_paasta_oapi_client
from paasta_tools.cli.cmds.check import makefile_responds_to
from paasta_tools.cli.cmds.cook_image import paasta_cook_image
from paasta_tools.cli.utils import get_paasta_oapi_api_clustername
from paasta_tools.cli.utils import lazy_choices_completer
from paasta_tools.utils import DEFAULT_SOA_DIR
from paasta_tools.utils import get_username
from paasta_tools.utils import list_services
from paasta_tools.utils import load_system_paasta_config
from paasta_tools.utils import PaastaColors
from paasta_tools.utils import SystemPaastaConfig


def add_common_args_to_parser(parser):
parser.add_argument(
"-s",
"--service",
help="The name of the service you wish to inspect. Required.",
required=True,
).completer = lazy_choices_completer(list_services)
parser.add_argument(
"-i",
"--instance",
help=(
"Simulate a docker run for a particular instance of the "
"service, like 'main' or 'canary'. Required."
),
required=True,
)
parser.add_argument(
"-c",
"--cluster",
help=(
"The name of the cluster you wish to run your task on. "
"If omitted, uses the default cluster defined in the paasta "
f"remote-run configs."
),
)


def add_subparser(
subparsers,
) -> None:
remote_run_parser = subparsers.add_parser(
"remote-run-2",
help="Run stuff remotely.",
description=("'paasta remote-run' runs stuff remotely "),
)
remote_run_parser.add_argument(
"-b",
"--build",
dest="build",
help="Build the image from current directory",
action="store_true",
)
remote_run_parser.add_argument(
"-y",
"--yelpsoa-config-root",
dest="yelpsoa_config_root",
help="A directory from which yelpsoa-configs should be read from",
default=DEFAULT_SOA_DIR,
)
remote_run_parser.add_argument(
"-I",
"--interactive",
help=(
'Run container in interactive mode. If interactive is set the default command will be "bash" '
'unless otherwise set by the "--cmd" flag'
),
action="store_true",
required=False,
default=False,
)
add_common_args_to_parser(remote_run_parser)
remote_run_parser.set_defaults(command=remote_run)


def paasta_remote_run(
cluster: str,
service: str,
instance: str,
system_paasta_config: SystemPaastaConfig,
verbose: int,
is_eks: bool = False,
build: bool = False,
) -> int:

output = []
ret_code = 0

# TODO: Build
if build and not makefile_responds_to("cook-image"):
print(
"A local Makefile with a 'cook-image' target is required for --build",
file=sys.stderr,
)
default_tag = "paasta-remote-run-{}-{}".format(service, get_username())
os.environ["DOCKER_TAG"] = default_tag
paasta_cook_image(args=None, service=service, soa_dir=soa_dir)
# TODO Actually push the image

client = get_paasta_oapi_client(
cluster=get_paasta_oapi_api_clustername(cluster=cluster, is_eks=is_eks),
system_paasta_config=system_paasta_config,
)
if not client:
print("Cannot get a paasta-api client")
exit(1)

try:
# TODO add image argument if build
response = client.service.remote_run(
service=service,
instance=instance,
user=get_username(),
)
print("Reponse was: ", response)
response = json.loads(response)
except client.api_error as exc:
print(exc, file=sys.stderr)
output.append(PaastaColors.red(exc.reason))
ret_code = exc.status
except (client.connection_error, client.timeout_error) as exc:
output.append(
PaastaColors.red(f"Could not connect to API: {exc.__class__.__name__}")
)
ret_code = 1
except Exception as e:
output.append(PaastaColors.red(f"Exception when talking to the API:"))
output.append(str(e))
ret_code = 1

if ret_code:
print("\n".join(output))
return ret_code

pod_name, namespace = response["pod_name"], response["namespace"]
exec_command_tmpl = "kubectl{eks}-{cluster} exec -it -n {namespace} {pod} /bin/bash"
exec_command = exec_command_tmpl.format(
eks="-eks" if is_eks else "", cluster=cluster, namespace=namespace, pod=pod_name
)
print("Pod launched successfully:", pod_name)

# TODO figure out how to get this to work
# print('Attaching shell')
# cmd = subprocess.Popen(exec_command.split(' '))
Qmando marked this conversation as resolved.
Show resolved Hide resolved
print("Run the following command to enter your service pod")
print(exec_command)

return ret_code


def remote_run(args) -> int:
"""Run stuff, but remotely!"""
system_paasta_config = load_system_paasta_config(
"/nail/home/qlo/paasta_config/paasta/"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was using this to override the API endpoint

)
return paasta_remote_run(
args.cluster, args.service, args.instance, system_paasta_config, 1, False
)
Loading
Loading