This commit is contained in:
Derek Bekoe 2017-09-11 10:12:16 -07:00 коммит произвёл GitHub
Родитель 8e1fb86915
Коммит 2534d773a8
6 изменённых файлов: 309 добавлений и 9 удалений

Просмотреть файл

@ -0,0 +1,65 @@
RPM Packaging
================
Building the RPM package
------------------------
On a build machine (e.g. new CentOS 7 VM) run the following.
Install dependencies required to build:
```
# Required for rpm build tools.
sudo yum install -y gcc rpm-build rpm-devel rpmlint make python bash coreutils diffutils patch rpmdevtools
# Required to build the CLI.
sudo yum install -y gcc python libffi-devel python-devel openssl-devel
```
Set up directory structure for build:
```
mkdir -p ~/rpmbuild/
cd ~/rpmbuild/
mkdir -p BUILD RPMS SOURCES SPECS SRPMS
> SPECS/azure-cli.spec; vi SPECS/azure-cli.spec
```
Set the CLI version and SHA256 for the archive:
```
export CLI_VERSION=2.0.16
export CLI_DOWNLOAD_SHA256=22c048d2911c13738c6b901a741ea655f277e0d9eb756c4fb9aee6bb6c2b0109
```
RPM Build:
```
rpmbuild -v -bb --clean SPECS/azure-cli.spec
```
Verification
------------
```
sudo rpm -i RPMS/*/azure-cli-2.0.16-1.noarch.rpm
az --version
```
Check the file permissions of the package:
```
rpmlint RPMS/*/azure-cli-2.0.16-1.x86_64.rpm
```
Check the file permissions of the package:
```
rpm -qlvp RPMS/*/azure-cli-2.0.16-1.x86_64.rpm
```
To remove:
```
sudo rpm -e azure-cli
```
Links
-----
https://fedoraproject.org/wiki/How_to_create_an_RPM_package
https://fedoraproject.org/wiki/Packaging:RPMMacros?rd=Packaging/RPMMacros

Просмотреть файл

@ -0,0 +1,81 @@
# RPM spec file for Azure CLI 2.0
# Definition of macros used - https://fedoraproject.org/wiki/Packaging:RPMMacros?rd=Packaging/RPMMacros
# .el7.centos -> .el7
%if 0%{?rhel} == 7
%define dist .el7
%endif
%define name azure-cli
%define release 1%{?dist}
%define version %{getenv:CLI_VERSION}
%define source_sha256 %{getenv:CLI_DOWNLOAD_SHA256}
%define source_url https://azurecliprod.blob.core.windows.net/releases/azure-cli_packaged_%{version}.tar.gz
%define venv_url https://pypi.python.org/packages/source/v/virtualenv/virtualenv-15.0.0.tar.gz
%define venv_sha256 70d63fb7e949d07aeb37f6ecc94e8b60671edb15b890aa86dba5dfaf2225dc19
%define cli_lib_dir %{_libdir}/az
Summary: Azure CLI 2.0
License: MIT
Name: %{name}
Version: %{version}
Release: %{release}
Source0: %{source_url}
Url: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
BuildArch: x86_64
Requires: python
BuildRequires: gcc
BuildRequires: python
BuildRequires: libffi-devel
BuildRequires: python-devel
BuildRequires: openssl-devel
%description
A great cloud needs great tools; we're excited to introduce Azure CLI 2.0,
our next generation multi-platform command line experience for Azure.
%prep
# Create some tmp files
tmp_venv_archive=$(mktemp)
tmp_source_archive=$(mktemp)
# Download, Extract Source
wget %{source_url} -qO $tmp_source_archive
echo "%{source_sha256} $tmp_source_archive" | sha256sum -c -
tar -xvzf $tmp_source_archive -C %{_builddir}
# Download, Extract Virtualenv
wget %{venv_url} -qO $tmp_venv_archive
echo "%{venv_sha256} $tmp_venv_archive" | sha256sum -c -
tar -xvzf $tmp_venv_archive -C %{_builddir}
%install
# Create the venv
python %{_builddir}/virtualenv-15.0.0/virtualenv.py --python python %{buildroot}%{cli_lib_dir}
# Build the wheels from the source
source_dir=%{_builddir}/azure-cli_packaged_%{version}
dist_dir=$(mktemp -d)
for d in $source_dir/src/azure-cli $source_dir/src/azure-cli-core $source_dir/src/azure-cli-nspkg $source_dir/src/azure-cli-command_modules-nspkg $source_dir/src/command_modules/azure-cli-*/; \
do cd $d; %{buildroot}%{cli_lib_dir}/bin/python setup.py bdist_wheel -d $dist_dir; cd -; done;
# Install the CLI
%{buildroot}%{cli_lib_dir}/bin/pip install azure-cli --find-links $dist_dir
%{buildroot}%{cli_lib_dir}/bin/pip install --force-reinstall --upgrade azure-nspkg azure-mgmt-nspkg
# Fix up %{buildroot} appearing in some files...
for d in %{buildroot}%{cli_lib_dir}/bin/*; do perl -p -i -e "s#%{buildroot}##g" $d; done;
# Create executable
mkdir -p %{buildroot}%{_bindir}
printf '#!/usr/bin/env bash\n%{cli_lib_dir}/bin/python -Esm azure.cli "$@"' > %{buildroot}%{_bindir}/az
# Set up tab completion
mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d/
cat $source_dir/az.completion > %{buildroot}%{_sysconfdir}/bash_completion.d/azure-cli
%files
%attr(-,root,root) %{cli_lib_dir}
%config(noreplace) %{_sysconfdir}/bash_completion.d/azure-cli
%attr(0755,root,root) %{_bindir}/az

Просмотреть файл

@ -3,6 +3,11 @@
Release History Release History
=============== ===============
0.1.4 (2017-09-07)
++++++++++++++++++
* Add release script for RPM releases.
0.1.3 (2017-08-18) 0.1.3 (2017-08-18)
++++++++++++++++++ ++++++++++++++++++

Просмотреть файл

@ -29,6 +29,7 @@ These can be set in the initial `docker run` command above or by using `export E
python release.py python release.py
python release-docker.py python release-docker.py
python release-debian.py python release-debian.py
python release-rpm.py
``` ```
Environment Variables Environment Variables
@ -51,7 +52,9 @@ The `GITHUB_USER` should have the following GitHub OAuth scopes:
`DOCKER_USERNAME` - The Docker username that has push permissions to the above Docker repo. `DOCKER_USERNAME` - The Docker username that has push permissions to the above Docker repo.
`DOCKER_PASSWORD` - The Docker password for the user. `DOCKER_PASSWORD` - The Docker password for the user.
`MS_REPO_URL` - The repository URL to publish .deb/.rpm packages.
`MS_REPO_USERNAME` - The repository username to publish .deb/.rpm packages.
`MS_REPO_PASSWORD` - The user password to publish the .deb/.rpm package.
`DEBIAN_REPO_ID` - The repository ID to publish the .deb package. `DEBIAN_REPO_ID` - The repository ID to publish the .deb package.
`DEBIAN_REPO_URL` - The repository URL to publish the .deb package. `YUM_REPO_ID` - The repository ID to publish the .rpm package.
`DEBIAN_REPO_USERNAME` - The repository username to publish the .deb package.
`DEBIAN_REPO_PASSWORD` - The user password to publish the .deb package.

Просмотреть файл

@ -26,9 +26,9 @@ add_script_env('CLI_VERSION')
add_script_env('CLI_DOWNLOAD_SHA256') add_script_env('CLI_DOWNLOAD_SHA256')
add_script_env('AZURE_STORAGE_CONNECTION_STRING') add_script_env('AZURE_STORAGE_CONNECTION_STRING')
add_script_env('DEBIAN_REPO_ID') add_script_env('DEBIAN_REPO_ID')
add_script_env('DEBIAN_REPO_URL') add_script_env('MS_REPO_URL')
add_script_env('DEBIAN_REPO_USERNAME') add_script_env('MS_REPO_USERNAME')
add_script_env('DEBIAN_REPO_PASSWORD') add_script_env('MS_REPO_PASSWORD')
assert (all(script_env[n] != None for n in script_env)), "Not all required environment variables have been set. {}".format(script_env) assert (all(script_env[n] != None for n in script_env)), "Not all required environment variables have been set. {}".format(script_env)
@ -133,9 +133,9 @@ def main():
upload_script = REPO_UPLOAD_SCRIPT_TMPL.format(cli_version=script_env.get('CLI_VERSION'), upload_script = REPO_UPLOAD_SCRIPT_TMPL.format(cli_version=script_env.get('CLI_VERSION'),
repo_id=script_env.get('DEBIAN_REPO_ID'), repo_id=script_env.get('DEBIAN_REPO_ID'),
source_url=deb_url, source_url=deb_url,
repo_package_url=script_env.get('DEBIAN_REPO_URL'), repo_package_url=script_env.get('MS_REPO_URL'),
repo_user=script_env.get('DEBIAN_REPO_USERNAME'), repo_user=script_env.get('MS_REPO_USERNAME'),
repo_pass=script_env.get('DEBIAN_REPO_PASSWORD')) repo_pass=script_env.get('MS_REPO_PASSWORD'))
my_vm(['echo', '-e', '"{}"'.format(upload_script), '>>', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout) my_vm(['echo', '-e', '"{}"'.format(upload_script), '>>', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout)
my_vm(['python', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout) my_vm(['python', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout)
print_status('Done. :)') print_status('Done. :)')

Просмотреть файл

@ -0,0 +1,146 @@
#!/usr/bin/env python
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# This script is interactive as you need to log in to 'az'.
from __future__ import print_function
import os
import sys
import time
from datetime import datetime
from six import StringIO
from sh import az, ssh
script_env = {}
def add_script_env(name):
script_env[name] = os.environ.get(name)
add_script_env('REPO_NAME')
add_script_env('CLI_VERSION')
add_script_env('CLI_DOWNLOAD_SHA256')
add_script_env('AZURE_STORAGE_CONNECTION_STRING')
add_script_env('YUM_REPO_ID')
add_script_env('MS_REPO_URL')
add_script_env('MS_REPO_USERNAME')
add_script_env('MS_REPO_PASSWORD')
assert (all(script_env[n] != None for n in script_env)), "Not all required environment variables have been set. {}".format(script_env)
REPO_UPLOAD_SCRIPT_TMPL = """
import os, requests
payload = {{'name': 'azure-cli', 'version': '{cli_version}', 'repositoryId': '{repo_id}', 'sourceUrl': '{source_url}'}}
r = requests.post('{repo_package_url}', verify=False, auth=('{repo_user}', '{repo_pass}'), json=payload)
print('Status Code')
print(r.status_code)
print('Query with a GET to the following:')
print(r.headers['Location'])
"""
def print_env_vars():
for n in script_env:
print('{} = {}'.format(n, script_env[n]))
def print_status(msg=''):
print('-- '+msg)
def print_heading(heading):
print('{0}\n{1}\n{0}'.format('=' * len(heading), heading))
def give_chance_to_cancel(msg_prefix=''):
cancel_time_secs = 10
msg_tmpl = '{}: Starting in {} seconds.'
for i in range(cancel_time_secs, 0, -1):
print_status(msg_tmpl.format(msg_prefix, i))
time.sleep(1)
def main():
print_env_vars()
time_str = datetime.utcnow().strftime('%Y%m%d%H%M%S')
az(["login"], _out=sys.stdout, _err=sys.stdout)
resource_group = 'azurecli-release-rpm-' + time_str
vm_name = 'vm-rpm-' + time_str
print_status('Creating resource group.')
az(['group', 'create', '-l', 'westus', '-n', resource_group], _out=sys.stdout, _err=sys.stdout)
print_status('Creating VM.')
az(['vm', 'create', '-g', resource_group, '-n', vm_name, '--generate-ssh-keys', '--authentication-type', 'ssh',
'--image', 'OpenLogic:CentOS:7.3:latest', '--admin-username', 'myuser'],
_out=sys.stdout, _err=sys.stdout)
io = StringIO()
print_status('Getting VM IP address.')
az(['vm', 'list-ip-addresses', '--resource-group', resource_group, '--name', vm_name,
'--query', '[0].virtualMachine.network.publicIpAddresses[0].ipAddress'], _out=io)
ip_address = io.getvalue().strip().replace('"', '')
print_status('VM IP address is {}'.format(ip_address))
io.close()
vm_connect_str = "myuser@{}".format(ip_address)
my_vm = ssh.bake(['-oStrictHostKeyChecking=no', vm_connect_str])
print_status('Installing git.')
build_prereqs = "sudo yum update -y && sudo yum install -y git gcc rpm-build rpm-devel rpmlint make python bash coreutils " \
"diffutils patch rpmdevtools python libffi-devel python-devel openssl-devel"
my_vm(build_prereqs.split(),
_out=sys.stdout, _err=sys.stdout)
my_vm("mkdir -p ~/rpmbuild/BUILD ~/rpmbuild/RPMS ~/rpmbuild/SOURCES ~/rpmbuild/SPECS ~/rpmbuild/SRPMS".split(), _out=io)
io = StringIO()
my_vm(['mktemp', '-d'], _out=io)
repo_dir = io.getvalue().strip()
io.close()
print_status('Cloning repo.')
my_vm(['git', 'clone', 'https://github.com/{}'.format(script_env.get('REPO_NAME')), repo_dir], _out=sys.stdout, _err=sys.stdout)
path_to_spec_file = os.path.join(repo_dir, 'packaged_releases', 'rpm', 'azure-cli.spec')
print_status('Running build script.')
my_vm(['export', 'CLI_VERSION={}'.format(script_env.get('CLI_VERSION')), '&&',
'export', 'CLI_DOWNLOAD_SHA256={}'.format(script_env.get('CLI_DOWNLOAD_SHA256')), '&&',
'rpmbuild', '-v', '-bb', '--clean', path_to_spec_file],
_out=sys.stdout, _err=sys.stdout)
print_status('Build complete.')
io = StringIO()
my_vm(['ls', '~/rpmbuild/RPMS/*/*'], _out=io)
rpm_file_path = io.getvalue().strip()
io.close()
artifact_name = rpm_file_path.split('/')[-1]
print_status('Installing the .rpm on the build machine')
my_vm(['sudo', 'rpm', '-i', rpm_file_path], _out=sys.stdout, _err=sys.stdout)
# Upload to Azure Storage
print_status('Uploading .rpm to Azure storage.')
my_vm(['az', 'storage', 'container', 'create', '--name', 'rpms', '--public-access', 'blob',
'--connection-string', '"{}"'.format(script_env.get('AZURE_STORAGE_CONNECTION_STRING'))],
_out=sys.stdout, _err=sys.stdout)
my_vm(['az', 'storage', 'blob', 'upload', '-f', rpm_file_path,
'-n', artifact_name, '-c', 'rpms', '--connection-string', '"{}"'.format(script_env.get('AZURE_STORAGE_CONNECTION_STRING'))],
_out=sys.stdout, _err=sys.stdout)
io = StringIO()
my_vm(['az', 'storage', 'blob', 'url', '-n', artifact_name, '-c', 'rpms', '--output', 'tsv',
'--connection-string', '"{}"'.format(script_env.get('AZURE_STORAGE_CONNECTION_STRING'))], _out=io)
rpm_url = io.getvalue().strip()
io.close()
print_status('RPM file uploaded to the following URL.')
print_status(rpm_url)
# Publish to service
my_vm(['wget', '-q', 'https://bootstrap.pypa.io/get-pip.py'], _out=sys.stdout, _err=sys.stdout)
my_vm(['sudo', 'python', 'get-pip.py'], _out=sys.stdout, _err=sys.stdout)
my_vm(['sudo', 'pip', 'install', '--upgrade', 'requests'], _out=sys.stdout, _err=sys.stdout)
upload_script = REPO_UPLOAD_SCRIPT_TMPL.format(cli_version=script_env.get('CLI_VERSION'),
repo_id=script_env.get('YUM_REPO_ID'),
source_url=rpm_url,
repo_package_url=script_env.get('MS_REPO_URL'),
repo_user=script_env.get('MS_REPO_USERNAME'),
repo_pass=script_env.get('MS_REPO_PASSWORD'))
# Keeping this code commented for when we can automate the signing of RPM packages.
# my_vm(['echo', '-e', '"{}"'.format(upload_script), '>>', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout)
# my_vm(['python', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout)
print_status('PRINTING OUT REPO UPLOAD SCRIPT AS THE UNSIGNED RPM NEEDS TO BE FIRST SIGNED BEFORE UPLOADING...')
my_vm(['cat', 'repo_upload.py'], _out=sys.stdout, _err=sys.stdout)
print_status('Done. :)')
give_chance_to_cancel('Delete resource group (in background)')
az(['group', 'delete', '--name', resource_group, '--yes', '--no-wait'], _out=sys.stdout, _err=sys.stdout)
print_status('Finished. :)')
if __name__ == '__main__':
main()