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

Webapps: Support for asp.net, Java & static html #159

Merged
merged 2 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 4 additions & 4 deletions src/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,9 @@
],
"webapp": [
{
"filename": "webapp-0.2.3-py2.py3-none-any.whl",
"sha256Digest": "c6e2c8fff7f3d88f9b7eb77327d67ab525ad9c8b8b27b3b004b565fac391c241",
"downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.3-py2.py3-none-any.whl",
"filename": "webapp-0.2.4-py2.py3-none-any.whl",
"sha256Digest": "28736466d2602516394d3ed3cd784f318013be7624db8f3fe09012927e7e9de7",
"downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.4-py2.py3-none-any.whl",
"metadata": {
"azext.isPreview": true,
"azext.minCliCoreVersion": "2.0.24",
Expand Down Expand Up @@ -366,7 +366,7 @@
"metadata_version": "2.0",
"name": "webapp",
"summary": "An Azure CLI Extension to manage appservice resources",
"version": "0.2.3"
"version": "0.2.4"
}
}
],
Expand Down
9 changes: 7 additions & 2 deletions src/webapp/azext_webapp/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@

NODE_VERSION_DEFAULT = "8.9"
NETCORE_VERSION_DEFAULT = "2.0"
DOTNET_VERSION_DEFAULT = "4.7"
NETCORE_RUNTIME_NAME = "dotnetcore"
DOTNET_RUNTIME_NAME = "aspnet"
JAVA_RUNTIME_NAME = "java"
OS_DEFAULT = "Windows"
STATIC_RUNTIME_NAME = "static" # not an oficial supported runtime but used for CLI logic
# TODO: Remove this once we have the api returning the versions
NODE_VERSIONS = ['4.4', '4.5', '6.2', '6.6', '6.9', '6.11', '8.0', '8.1']
NETCORE_VERSIONS = ['1.0', '1.1', '2.0']
DOTNET_VERSIONS = ['3.5', '4.7']
NODE_RUNTIME_NAME = "node"
NETCORE_RUNTIME_NAME = "dotnetcore"
OS_DEFAULT = "Windows"
76 changes: 70 additions & 6 deletions src/webapp/azext_webapp/create_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
NODE_VERSION_DEFAULT,
NODE_VERSIONS,
NETCORE_RUNTIME_NAME,
NODE_RUNTIME_NAME)
NODE_RUNTIME_NAME,
DOTNET_RUNTIME_NAME,
DOTNET_VERSION_DEFAULT,
DOTNET_VERSIONS,
JAVA_RUNTIME_NAME,
STATIC_RUNTIME_NAME)


def _resource_client_factory(cli_ctx, **_):
Expand Down Expand Up @@ -57,9 +62,16 @@ def get_runtime_version_details(file_path, lang_name):
# method returns list in DESC, pick the first
version_detected = parse_netcore_version(file_path)[0]
version_to_create = detect_netcore_version_tocreate(version_detected)
elif lang_name.lower() == DOTNET_RUNTIME_NAME:
# method returns list in DESC, pick the first
version_detected = parse_dotnet_version(file_path)
version_to_create = detect_dotnet_version_tocreate(version_detected)
elif lang_name.lower() == NODE_RUNTIME_NAME:
version_detected = parse_node_version(file_path)[0]
version_to_create = detect_node_version_tocreate(version_detected)
elif lang_name.lower() == STATIC_RUNTIME_NAME:
version_detected = "-"
version_to_create = "-"
return {'detected': version_detected, 'to_create': version_to_create}


Expand Down Expand Up @@ -107,22 +119,65 @@ def check_app_exists(cmd, rg_name, app_name):
def get_lang_from_content(src_path):
import glob
# NODE: package.json should exist in the application root dir
# NETCORE: *.csproj should exist in the application root dir
# NETCORE & DOTNET: *.csproj should exist in the application dir
# NETCORE: <TargetFramework>netcoreapp2.0</TargetFramework>
# DOTNET: <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
runtime_details_dict = dict.fromkeys(['language', 'file_loc', 'default_sku'])
package_json_file = os.path.join(src_path, 'package.json')
package_netcore_glob = glob.glob("*.csproj")
package_netlang_glob = glob.glob("**/*.csproj", recursive=True)
runtime_java_file = glob.glob("**/*.war", recursive=True)
static_html_file = glob.glob("**/*.html", recursive=True)
if os.path.isfile(package_json_file):
runtime_details_dict['language'] = NODE_RUNTIME_NAME
runtime_details_dict['file_loc'] = package_json_file
runtime_details_dict['default_sku'] = 'S1'
elif package_netcore_glob:
package_netcore_file = os.path.join(src_path, package_netcore_glob[0])
runtime_details_dict['language'] = NETCORE_RUNTIME_NAME
elif package_netlang_glob:
package_netcore_file = os.path.join(src_path, package_netlang_glob[0])
runtime_lang = detect_dotnet_lang(package_netcore_file)
runtime_details_dict['language'] = runtime_lang
runtime_details_dict['file_loc'] = package_netcore_file
runtime_details_dict['default_sku'] = 'F1'
elif runtime_java_file:
runtime_details_dict['language'] = JAVA_RUNTIME_NAME
runtime_details_dict['file_loc'] = runtime_java_file
runtime_details_dict['default_sku'] = 'S1'
elif static_html_file:
runtime_details_dict['language'] = STATIC_RUNTIME_NAME
runtime_details_dict['file_loc'] = static_html_file[0]
runtime_details_dict['default_sku'] = 'F1'
return runtime_details_dict


def detect_dotnet_lang(csproj_path):
import xml.etree.ElementTree as ET
import re
parsed_file = ET.parse(csproj_path)
root = parsed_file.getroot()
version_lang = ''
for target_ver in root.iter('TargetFramework'):
version_lang = re.sub(r'([^a-zA-Z\s]+?)', '', target_ver.text)
if 'netcore' in version_lang.lower():
return NETCORE_RUNTIME_NAME
else:
return DOTNET_RUNTIME_NAME


def parse_dotnet_version(file_path):
from xml.dom import minidom
import re
xmldoc = minidom.parse(file_path)
framework_ver = xmldoc.getElementsByTagName('TargetFrameworkVersion')
version_detected = ['4.7']
target_ver = framework_ver[0].firstChild.data
non_decimal = re.compile(r'[^\d.]+')
# reduce the version to '5.7.4' from '5.7'
if target_ver is not None:
# remove the string from the beginning of the version value
c = non_decimal.sub('', target_ver)
version_detected = c[:3]
return version_detected


def parse_netcore_version(file_path):
import xml.etree.ElementTree as ET
import re
Expand Down Expand Up @@ -157,6 +212,15 @@ def detect_netcore_version_tocreate(detected_ver):
return NETCORE_VERSION_DEFAULT


def detect_dotnet_version_tocreate(detected_ver):
min_ver = DOTNET_VERSIONS[0]
if detected_ver in DOTNET_VERSIONS:
return detected_ver
elif detected_ver < min_ver:
return min_ver
return DOTNET_VERSION_DEFAULT


def detect_node_version_tocreate(detected_ver):
if detected_ver in NODE_VERSIONS:
return detected_ver
Expand Down
66 changes: 40 additions & 26 deletions src/webapp/azext_webapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
_get_scm_url,
get_sku_name,
list_publish_profiles,
get_site_configs)
get_site_configs,
config_diagnostics)

from azure.cli.command_modules.appservice._appservice_utils import _generic_site_operation

from .create_util import (
zip_contents_from_dir,
Expand All @@ -33,7 +36,7 @@
web_client_factory
)

from ._constants import (NODE_RUNTIME_NAME, OS_DEFAULT)
from ._constants import (NODE_RUNTIME_NAME, OS_DEFAULT, JAVA_RUNTIME_NAME, STATIC_RUNTIME_NAME)

logger = get_logger(__name__)

Expand Down Expand Up @@ -64,12 +67,14 @@ def create_deploy_webapp(cmd, name, location=None, dryrun=False):
else:
sku = lang_details.get("default_sku")
language = lang_details.get("language")
os_val = "Linux" if language.lower() == NODE_RUNTIME_NAME else OS_DEFAULT
is_java = language.lower() == JAVA_RUNTIME_NAME
is_skip_build = is_java or language.lower() == STATIC_RUNTIME_NAME
os_val = "Linux" if language.lower() == NODE_RUNTIME_NAME or is_java else OS_DEFAULT
# detect the version
data = get_runtime_version_details(lang_details.get('file_loc'), language)
version_used_create = data.get('to_create')
detected_version = data.get('detected')
runtime_version = "{}|{}".format(language, version_used_create)
runtime_version = "{}|{}".format(language, version_used_create) if version_used_create != "-" else version_used_create

if location is None:
locs = client.list_geo_regions(sku, True)
Expand All @@ -92,15 +97,14 @@ def create_deploy_webapp(cmd, name, location=None, dryrun=False):

# Resource group: check if default RG is set
default_rg = cmd.cli_ctx.config.get('defaults', 'group', fallback=None)
if default_rg and check_resource_group_supports_os(cmd, default_rg, location, is_linux):
if default_rg and check_resource_group_exists(cmd, default_rg) and check_resource_group_supports_os(cmd, default_rg, location, is_linux):
rg_name = default_rg
rg_mssg = "[Using default Resource group]"
else:
rg_mssg = ""

src_path = "{} {}".format(src_dir.replace("\\", "\\\\"), str_no_contents_warn)
rg_str = "{} {}".format(rg_name, rg_mssg)

dry_run_str = r""" {
"name" : "%s",
"serverfarm" : "%s",
Expand Down Expand Up @@ -143,43 +147,48 @@ def create_deploy_webapp(cmd, name, location=None, dryrun=False):
# create the app
if not check_app_exists(cmd, rg_name, name):
logger.warning("Creating app '%s' ....", name)
app_created = create_webapp(cmd, rg_name, name, asp, runtime_version if is_linux else None)
# update create_json to include the app_url
url = app_created.enabled_host_names[0] # picks the custom domain URL incase a domain is assigned
url = 'https://' + url
create_webapp(cmd, rg_name, name, asp, runtime_version if is_linux else None)
logger.warning("Webapp creation complete")
else:
logger.warning("App '%s' already exists", name)
# update create_json to include the app_url
url = _get_app_url(cmd, rg_name, name) # picks the custom domain URL incase a domain is assigned

if do_deployment:
# setting to build after deployment
logger.warning("Updating app settings to enable build after deployment")
update_app_settings(cmd, rg_name, name, ["SCM_DO_BUILD_DURING_DEPLOYMENT=true"])
# work around until the timeout limits issue for linux is investigated & fixed
# wakeup kudu, by making an SCM call
if not is_skip_build:
# setting to build after deployment
logger.warning("Updating app settings to enable build after deployment")
update_app_settings(cmd, rg_name, name, ["SCM_DO_BUILD_DURING_DEPLOYMENT=true"])
# work around until the timeout limits issue for linux is investigated & fixed
# wakeup kudu, by making an SCM call

import requests
# work around until the timeout limits issue for linux is investigated & fixed
user_name, password = _get_site_credential(cmd.cli_ctx, rg_name, name)
scm_url = _get_scm_url(cmd, rg_name, name)

import urllib3
authorization = urllib3.util.make_headers(basic_auth='{0}:{1}'.format(user_name, password))
requests.get(scm_url + '/api/settings', headers=authorization)

logger.warning("Creating zip with contents of dir %s ...", src_dir)
# zip contents & deploy
zip_file_path = zip_contents_from_dir(src_dir, language)
if is_java:
zip_file_path = src_path + '\\\\' + lang_details.get('file_loc')[0]
else:
logger.warning("Creating zip with contents of dir %s ...", src_dir)
# zip contents & deploy
zip_file_path = zip_contents_from_dir(src_dir, language)

logger.warning("Deploying and building contents to app."
"This operation can take some time to finish...")
logger.warning("Deploying %s contents to app."
"This operation can take some time to finish...", '' if is_skip_build else 'and building')
enable_zip_deploy(cmd, rg_name, name, zip_file_path)
# Remove the file afer deployment, handling exception if user removed the file manually
try:
os.remove(zip_file_path)
except OSError:
pass
if not is_java:
# Remove the file afer deployment, handling exception if user removed the file manually
try:
os.remove(zip_file_path)
except OSError:
pass
else:
logger.warning("No 'NODE' or 'DOTNETCORE' package detected, skipping zip and deploy process")
logger.warning("No known package (Node, ASP.NET, .NETCORE, Java or Static Html) found skipping zip and deploy process")
create_json.update({'app_url': url})
logger.warning("All done.")
return create_json
Expand Down Expand Up @@ -247,3 +256,8 @@ def create_tunnel(cmd, resource_group_name, name, port, slot=None):
break
logger.warning('Tunnel is ready! Creating on port %s', port)
tunnel_server.start_server()


def _get_app_url(cmd, rg_name, app_name):
site = _generic_site_operation(cmd.cli_ctx, rg_name, app_name, 'get')
return "https://" + site.enabled_host_names[0]
2 changes: 1 addition & 1 deletion src/webapp/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codecs import open
from setuptools import setup, find_packages

VERSION = "0.2.3"
VERSION = "0.2.4"

CLASSIFIERS = [
'Development Status :: 4 - Beta',
Expand Down