Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Modify deploy setup and run command
  • Loading branch information
DaeunYim committed May 3, 2021
commit 8fc7a447257c3ddea81675124497abb086a60fce
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,33 @@
# --------------------------------------------------------------------------------------------

# pylint: disable=unused-argument, line-too-long
import json
import os
import sys
import yaml
import datetime as dt
from datetime import datetime
import random
import subprocess
from knack.log import get_logger
from azure.core.paging import ItemPaged
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.core.commands import LongRunningOperation, _is_poller
from azure.cli.core.azclierror import RequiredArgumentMissingError, InvalidArgumentValueError
from azure.cli.command_modules.role.custom import create_service_principal_for_rbac
from azure.mgmt.resource.resources.models import ResourceGroup
from msrestazure.tools import parse_resource_id
from msrestazure.azure_exceptions import CloudError
from ._client_factory import resource_client_factory, cf_mysql_flexible_location_capabilities, cf_postgres_flexible_location_capabilities
from .flexible_server_custom_common import firewall_rule_create_func

logger = get_logger(__name__)

DEFAULT_LOCATION_PG = 'eastus' # For testing: 'eastus2euap'
DEFAULT_LOCATION_MySQL = 'westus2'
AZURE_CREDENTIALS = 'AZURE_CREDENTIALS'
AZURE_POSTGRESQL_CONNECTION_STRING = 'AZURE_POSTGRESQL_CONNECTION_STRING'
GITHUB_ACTION_PATH = '/.github/workflows/'


def resolve_poller(result, cli_ctx, name):
Expand Down Expand Up @@ -343,12 +353,104 @@ def _resolve_api_version(client, provider_namespace, resource_type, parent_path)
.format(resource_type))


def run_subprocess(command):
commands = command.split()
subprocess.run(commands, shell=True)
def run_subprocess(command, stdout_show=None):
if stdout_show:
process = subprocess.Popen(command, shell=True)
else:
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.wait()
if process.returncode:
print(process.stderr.read().strip().decode('UTF-8'))


def run_subprocess_get_output(command):
commands = command.split()
process = subprocess.Popen(commands, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.wait()
return process
return process


def register_secrets(cmd, server, database_name, administrator_login, administrator_login_password, repository):
resource_group = parse_resource_id(server.id)["resource_group"]
scope = "/subscriptions/{}/resourceGroups/{}".format(get_subscription_id(cmd.cli_ctx), resource_group)

app = create_service_principal_for_rbac(cmd, name=server.name, role='contributor', scopes=[scope])
app['clientId'], app['clientSecret'], app['tenantId'] = app.pop('appId'), app.pop('password'), app.pop('tenant')
app['subscriptionId'] = get_subscription_id(cmd.cli_ctx)
app.pop('displayName')
app.pop('name')

app_json = json.dumps(app)
app = {"clientId": "52ceada6-9651-4497-b463-82546a0e625f",
"clientSecret": "MyiV5uPZQlTPFZ5ORUgQEGdDws_8aF-yB6",
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"subscriptionId": "7fec3109-5b78-4a24-b834-5d47d63e2596"}
app_key_val = []
for key, val in app.items():
app_key_val.append('"{}": "{}"'.format(key, val))
print(app_key_val)
app_json = ',\n '.join(app_key_val)
app_json = '{\n ' + app_json + '\n}'
credential_file = "./temp_app_credential.txt"
with open(credential_file, "w") as f:
f.write(app_json)
run_subprocess('gh secret set {} --repo {} < {}'.format(AZURE_CREDENTIALS, repository, credential_file))
os.remove(credential_file)

connection_string = "host={} port=5432 dbname={} user={} password={} sslmode=require".format(server.fully_qualified_domain_name, database_name, administrator_login, administrator_login_password)
run_subprocess('gh secret set {} --repo {} -b"{}"'.format(AZURE_POSTGRESQL_CONNECTION_STRING, repository, connection_string))


def fill_action_template(cmd, server, database_name, administrator_login, administrator_login_password, file_name, action_name, repository):

action_dir = get_git_root_dir() + GITHUB_ACTION_PATH
if not os.path.exists(action_dir):
os.makedirs(action_dir)

process = run_subprocess_get_output("gh secret list --repo {}".format(repository))
secrets = process.stdout.read().strip().decode('UTF-8')
print(secrets)
# if AZURE_CREDENTIALS not in secrets and AZURE_POSTGRESQL_CONNECTION_STRING not in secrets:
register_secrets(cmd,
server=server,
database_name=database_name,
administrator_login=administrator_login,
administrator_login_password=administrator_login_password,
repository=repository)

condition = "on: [push, workflow_dispatch]\n"
yml_content = {
'jobs': {
'build':{
'runs-on': 'ubuntu-latest',
'steps':[
{
'uses': 'actions/[email protected]'
},
{
'uses': 'azure/login@v1',
'with': {
'creds': '${{secrets.AZURE_CREDENTIALS}}'
}
},
{
'uses': 'azure/postgresql@v1',
'with': {
'connection-string': '${{secrets.AZURE_POSTGRESQL_CONNECTION_STRING}}',
'server-name': server.fully_qualified_domain_name,
'plsql-file': file_name,
}
}
],
}
}
}

with open(action_dir + action_name + '.yml', 'w') as yml_file:
yml_file.write(condition)
yaml.dump(yml_content, yml_file)


def get_git_root_dir():
process = run_subprocess_get_output("git rev-parse --show-toplevel")
return process.stdout.read().strip().decode('UTF-8')
15 changes: 10 additions & 5 deletions src/azure-cli/azure/cli/command_modules/rdbms/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,16 +466,21 @@ def _flexible_server_params(command_group):
c.argument('server_name', options_list=['--name', '-n'], help='Name of the replica server.')

with self.argument_context('{} deploy setup'.format(command_group)) as c:
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('server_name', id_part='name', options_list=['--server-name', '-s'], arg_type=server_name_arg_type)
c.argument('database_name', options_list=['--database-name', '-d'], help='the name of the database')
c.argument('database_name', options_list=['--database-name', '-d'], help='The name of the database')
c.argument('administrator_login', options_list=['--admin-user', '-u'], arg_group='Authentication', arg_type=administrator_login_arg_type,
help='Administrator username for the server.')
c.argument('administrator_login_password', options_list=['--admin-password', '-p'], help='The password of the administrator.')
c.argument('file_path', options_list=['--file-path', '-f'], help='the name of file')
c.argument('action_name', options_list=['--action-name'], help='the')
c.argument('administrator_login_password', options_list=['--admin-password', '-p'], arg_group='Authentication', help='The password of the administrator.')
c.argument('sql_file_path', options_list=['--sql-file'], help='The path of the sql file. The sql file should be already in the repository')
c.argument('action_name', options_list=['--action-name'], help='The name of the github action')
c.argument('repository', options_list=['--repo'], help='The name of your github username and repository e.g., Azure/azure-cli ')
c.argument('branch', options_list=['--branch'], help='The name of the branch you want upload github action file. The default will be your current branch.')
c.argument('allow_push', default=False, options_list=['--allow-push'], arg_type=get_three_state_flag(), help='Push the action yml file to the remote repository. The changes will be pushed to origin repository, speicified branch or current branch if not specified.')

with self.argument_context('{} deploy run'.format(command_group)) as c:
c.argument('action_name', options_list=['--action-name'], help='the')
c.argument('action_name', options_list=['--action-name'], help='The name of the github action')
c.argument('branch', options_list=['--branch'], help='The name of the branch you want upload github action file. The default will be your current branch.')

_flexible_server_params('postgres')
_flexible_server_params('mysql')
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,9 @@ def load_flexibleserver_command_table(self, _):
g.custom_command('create', 'flexible_replica_create', supports_no_wait=True)
g.custom_command('stop-replication', 'flexible_replica_stop', confirmation=True)

with self.command_group('postgres deploy',
with self.command_group('postgres deploy', postgres_flexible_servers_sdk,
custom_command_type=flexible_servers_custom_postgres,
client_factory=cf_postgres_flexible_servers,
is_preview=True) as g:
g.custom_command('setup', 'github_actions_setup')
g.custom_command('run', 'github_actions_run')
g.custom_command('run', 'github_actions_run')
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
from .flexible_server_custom_common import user_confirmation
from ._flexible_server_util import generate_missing_parameters, resolve_poller, create_firewall_rule, \
parse_public_access_input, generate_password, parse_maintenance_window, get_postgres_list_skus_info, \
DEFAULT_LOCATION_PG, run_subprocess, run_subprocess_get_output
DEFAULT_LOCATION_PG, run_subprocess, run_subprocess_get_output, fill_action_template, get_git_root_dir, \
GITHUB_ACTION_PATH
from .flexible_server_virtual_network import prepare_private_network, prepare_private_dns_zone
from .validators import pg_arguments_validator, validate_server_name


logger = get_logger(__name__)
DEFAULT_DB_NAME = 'flexibleserverdb'
DELEGATION_SERVICE_NAME = "Microsoft.DBforPostgreSQL/flexibleServers"
Expand Down Expand Up @@ -471,22 +473,49 @@ def _update_local_contexts(cmd, server_name, resource_group_name, location, user
cmd.cli_ctx.local_context.set([ALL], 'resource_group_name', resource_group_name)


def github_actions_setup(cmd, server_name, database_name, administrator_login, file_path, action_name, administrator_login_password=None):

output = run_subprocess_get_output("gh")
if output.returncode:
raise ClientRequestError('Please install "Github CLI" to run this command.')
def github_actions_setup(cmd, client, resource_group_name, server_name, database_name, administrator_login, administrator_login_password, sql_file_path, repository, action_name=None, branch=None, allow_push=None):

run_subprocess("gh auth login")
if allow_push and not branch:
raise RequiredArgumentMissingError("Provide remote branch name to allow pushing the action file to your remote branch.")
if action_name is None:
action_name = server.name + '_' + database_name + "_deploy"
gitcli_check_and_login()

server = client.get(resource_group_name, server_name)
fill_action_template(cmd,
server=server,
database_name=database_name,
administrator_login=administrator_login,
administrator_login_password=administrator_login_password,
file_name=sql_file_path,
repository=repository,
action_name=action_name)


# action_path = get_git_root_dir() + GITHUB_ACTION_PATH + action_name + '.yml'
# run_subprocess("git add {}".format(action_path))
# run_subprocess("git commit -m \"Add github action file\"")

if allow_push:
# logger.warning("Pushing the created action file to origin {} branch".format(branch))
# run_subprocess("git push origin {}".format(branch))
github_actions_run(action_name, branch)

def github_actions_run(cmd, action_name):
def github_actions_run(action_name, branch):

gitcli_check_and_login()
logger.warning("Created event for {}.yml in branch {}".format(action_name, branch))
run_subprocess("gh workflow run {}.yml --ref {}".format(action_name, branch))


def gitcli_check_and_login():
output = run_subprocess_get_output("gh")
if output.returncode:
raise ClientRequestError('Please install "Github CLI" to run this command.')

run_subprocess("gh auth login")
output = run_subprocess_get_output("gh auth status")
if output.returncode:
run_subprocess("gh auth login", stdout_show=True)


# pylint: disable=too-many-instance-attributes, too-few-public-methods, useless-object-inheritance
Expand Down