Adding git key and trigger tools to app-create

Changed BaseException to CommandException for
python34 test compatibility

Change-Id: Id5db4950a06a0875dc6485758318f0bc9090f6f2
This commit is contained in:
Ed Cranford
2015-03-04 17:40:42 -06:00
parent e1d9fdda70
commit e6ecac7ab0
2 changed files with 140 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
# Copyright (c) 2015 Rackspace
#
# 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.
# Tools for interacting with Github.
import base64
import getpass
import json
import random
import re
import string
import httplib2
class GitHubAuth(object):
username = None
password = None
full_repo_name = None
git_url = None
_token = None
_auth_url = 'https://api.github.com/authorizations'
def __init__(self, git_url):
self.git_url = git_url
user_org_name, repo = '', ''
github_regex = r'github\.com[:/](.+?)/(.+?)($|/$|\.git$|\.git/$)'
repo_pat = re.compile(github_regex)
match = repo_pat.search(self.git_url)
if match:
user_org_name, repo = match.group(1), match.group(2)
else:
raise ValueError("Failed to parse %s." % git_url)
self.full_repo_name = '/'.join([user_org_name, repo])
prompt = ("Username for repo '%s' [%s]:" %
(self.full_repo_name, user_org_name))
username = raw_input(prompt) or user_org_name
password = getpass.getpass("Password: ")
self.username = username
self.password = password
@property
def _auth_header(self):
authstring = '%s:%s' % (self.username, self.password)
auth = base64.encodestring(authstring)
return {
'Authorization': 'Basic %s' % auth,
'Content-Type': 'application/json',
}
@property
def token(self):
if self._token is None:
self._get_repo_token()
return self._token
def _get_repo_token(self):
note = ''.join(random.sample(string.lowercase, 5))
auth_info = {
'scopes': 'repo',
'note': 'Solum-status-%s' % note,
}
resp, content = httplib2.Http().request(
self._auth_url,
'POST',
headers=self._auth_header,
body=json.dumps(auth_info))
if resp.get('status') in ['200', '201']:
response_body = json.loads(content)
self._token = response_body.get('token')
def create_webhook(self, trigger_uri):
hook_url = ('https://api.github.com/repos/%s/hooks' %
self.full_repo_name)
hook_info = {
'name': 'web',
'events': ['pull_request', 'commit_comment'],
'config': {
'content_type': 'json',
'url': trigger_uri,
}
}
resp, content = httplib2.Http().request(
hook_url,
'POST',
headers=self._auth_header,
body=json.dumps(hook_info))
if resp.get('status') not in ['200', '201']:
pass
def add_ssh_key(self, public_key=None, is_private=False):
if not public_key:
return
api_url = ('https://api.github.com/repos/%s/keys' %
self.full_repo_name)
if is_private:
api_url = 'https://api.github.com/user/keys'
key_info = {
'title': 'devops@Solum',
'key': public_key,
}
resp, content = httplib2.Http().request(
api_url,
'POST',
headers=self._auth_header,
body=json.dumps(key_info))
if resp.get('status') not in ['200', '201']:
pass

View File

@@ -47,6 +47,7 @@ import sys
from solumclient.common import cli_utils from solumclient.common import cli_utils
from solumclient.common import exc from solumclient.common import exc
from solumclient.common import github
from solumclient.common import yamlutils from solumclient.common import yamlutils
from solumclient.openstack.common.apiclient import exceptions from solumclient.openstack.common.apiclient import exceptions
from solumclient.openstack.common import cliutils from solumclient.openstack.common import cliutils
@@ -515,6 +516,7 @@ Available commands:
solum app create [--plan-file <PLANFILE>] [--git-url <GIT_URL>] solum app create [--plan-file <PLANFILE>] [--git-url <GIT_URL>]
[--langpack <LANGPACK>] [--run-cmd <RUN_CMD>] [--langpack <LANGPACK>] [--run-cmd <RUN_CMD>]
[--name <NAME>] [--desc <DESCRIPTION>] [--name <NAME>] [--desc <DESCRIPTION>]
[--setup-triggers]
Register a new application with Solum. Register a new application with Solum.
solum app deploy <APP> solum app deploy <APP>
@@ -618,6 +620,10 @@ Available commands:
help="A yaml file containing custom" help="A yaml file containing custom"
" parameters to be used in the" " parameters to be used in the"
" application") " application")
self.parser.add_argument('--setup-triggers',
action='store_true',
dest='setup_triggers',
help="Set up app triggers on git repo")
args = self.parser.parse_args() args = self.parser.parse_args()
@@ -671,6 +677,7 @@ Available commands:
git_url = None git_url = None
if args.git_url is not None: if args.git_url is not None:
git_url = args.git_url
plan_definition['artifacts'][0]['content']['href'] = args.git_url plan_definition['artifacts'][0]['content']['href'] = args.git_url
if plan_definition['artifacts'][0]['content'].get('href') is None: if plan_definition['artifacts'][0]['content'].get('href') is None:
git_url = raw_input("Please specify a git repository URL for " git_url = raw_input("Please specify a git repository URL for "
@@ -727,6 +734,16 @@ Available commands:
cliutils.print_dict(data, wrap=72) cliutils.print_dict(data, wrap=72)
self._show_public_keys(artifacts) self._show_public_keys(artifacts)
if artifacts and args.setup_triggers:
gha = github.GitHubAuth(git_url)
content = artifacts[0].content
public_key = content.get('public_key', '')
private_repo = content.get('private', False)
gha.add_ssh_key(public_key=public_key, is_private=private_repo)
trigger_url = vars(plan).get('trigger_url', '')
if trigger_url:
gha.create_webhook(trigger_url)
def deploy(self): def deploy(self):
"""Deploy an application, building any applicable artifacts first.""" """Deploy an application, building any applicable artifacts first."""
# This is just "assembly create" with a little bit of introspection. # This is just "assembly create" with a little bit of introspection.