Skip to content

Commit 1fef395

Browse files
authored
feat: add Session class and rapida init command to authenticate (#96)
* feat: add Session class and rapida init command to authenticate * fix * updated readme and session.py
1 parent 029fd73 commit 1fef395

File tree

6 files changed

+175
-15
lines changed

6 files changed

+175
-15
lines changed

.devcontainer/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ RUN apt-get update && \
66
apt-get install -y python3-pip pipenv gcc cmake libgeos-dev && \
77
apt-get clean && \
88
rm -rf /var/lib/apt/lists/*
9+
10+
# install azure-cli
11+
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ RUN apt-get update && \
77
apt-get clean && \
88
rm -rf /var/lib/apt/lists/*
99

10+
# install azure-cli
11+
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash
12+
1013
WORKDIR /app
1114

1215
COPY . .

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,47 @@
11
# geo-cb-surge
22
A repo to hold python tools that facilitate the assessment of natural hazards over various domains like population, landuse, infrastructure, etc
33

4-
## Usage
4+
## Installation
55

66
Install the project with dependencies to virtual environment as below.
77

88
```shell
99
pipenv run pip install -e .
1010
```
1111

12+
To uninstall the project from Python environment, execute the following command.
13+
14+
```shell
15+
pipenv run pip uninstall geo-cb-surge
16+
```
17+
18+
## Usage
19+
1220
Then, run the below command to show help menu.
1321

1422
```shell
1523
pipenv run rapida --help
1624
```
1725

18-
To uninstall the project from Python environment, execute the following command.
26+
## Setup
27+
28+
To access blob storage in Azure, each user must have a role of `Storage Blob Data Contributor`.
29+
30+
- inside Docker container
31+
32+
Since it has an issue of opening browser by azure.identity package inside docker container, use `az login` to authenticate prior to use API.
1933

2034
```shell
21-
pipenv run pip uninstall geo-cb-surge
35+
az login # authenticate with az login
36+
pipenv run rapida init
37+
```
38+
39+
- without Docker
40+
41+
`init` command will open browser to authenticate to Azure
42+
43+
```shell
44+
pipenv run rapida init
2245
```
2346

2447
## Admin

cbsurge/cli.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,20 @@
11
import click as click
2-
2+
from cbsurge.session import init
33
from cbsurge.admin import admin
4-
54
from cbsurge.exposure.builtenv import builtenv
6-
import click
7-
8-
@click.group
9-
def cli(ctx):
10-
"""Main CLI for the application."""
11-
pass
12-
cli.add_command(admin)
13-
cli.add_command(builtenv)
14-
155
from cbsurge.exposure.population import population
166
from cbsurge.stats import stats
17-
7+
import click
188

199
@click.group
2010

2111
def cli():
2212
"""Main CLI for the application."""
2313
pass
14+
2415
cli.add_command(admin)
16+
cli.add_command(builtenv)
17+
cli.add_command(init)
2518
cli.add_command(population)
2619
cli.add_command(stats)
2720

cbsurge/session.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import logging
2+
import click
3+
from azure.identity import DefaultAzureCredential, AzureAuthorityHosts
4+
from azure.core.exceptions import ClientAuthenticationError
5+
from azure.storage.blob import BlobServiceClient
6+
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class Session(object):
12+
def __init__(self, scopes = "https://storage.azure.com/.default"):
13+
"""
14+
constructor
15+
16+
Parameters:
17+
scopes: scopes for get_token method. Default to "https://storage.azure.com/.default"
18+
"""
19+
self.scopes = scopes
20+
21+
def __enter__(self):
22+
return self
23+
24+
def __exit__(self, exc_type, exc_value, traceback):
25+
self.scopes = None
26+
27+
28+
def get_credential(self):
29+
"""
30+
get token credential for azure.
31+
32+
Usage example:
33+
34+
from azure.storage.blob import BlobServiceClient
35+
from cbsurge.session import Session
36+
37+
session = Session()
38+
credential = session.get_credential()
39+
40+
blob_service_client = BlobServiceClient(
41+
account_url="https://<my_account_name>.blob.core.windows.net",
42+
credential=token_credential
43+
)
44+
45+
Returns:
46+
Azure TokenCredential is returned if authenticated.
47+
"""
48+
credential = DefaultAzureCredential()
49+
return credential
50+
51+
def get_token(self):
52+
"""
53+
get access token for blob storage account. This token is required for using Azure REST API.
54+
55+
Returns:
56+
Azure token is returned if authenticated.
57+
Raises:
58+
ClientAuthenticationError is raised if authentication failed.
59+
60+
ClientAuthenticationError:
61+
https://learn.microsoft.com/en-us/python/api/azure-core/azure.core.exceptions.clientauthenticationerror?view=azure-python
62+
"""
63+
try:
64+
credential = self.get_credential()
65+
token = credential.get_token(self.scopes)
66+
return token
67+
except ClientAuthenticationError as err:
68+
logger.error("authentication failed. Please use 'rapida init' command to setup credentials.")
69+
raise err
70+
71+
def authenticate(self):
72+
"""
73+
Authenticate to Azure through interactive browser if DefaultAzureCredential is not provideds.
74+
Authentication uses DefaultAzureCredential.
75+
76+
Please refer to https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python
77+
about DefaultAzureCredential api specificaiton.
78+
79+
Returns:
80+
Azure credential and token are returned if authenticated. If authentication failed, return None.
81+
"""
82+
try:
83+
credential = DefaultAzureCredential(
84+
exclude_interactive_browser_credential=False,
85+
)
86+
token = credential.get_token(self.scopes)
87+
return [credential, token]
88+
except ClientAuthenticationError as err:
89+
logger.error("authentication failed.")
90+
logger.error(err)
91+
return None
92+
93+
def get_blob_service_client(self, account_name: str) -> BlobServiceClient:
94+
"""
95+
get BlobServiceClient for account url
96+
97+
Usage example:
98+
with Session() as session:
99+
blob_service_client = session.get_blob_service_client(
100+
account_name="undpgeohub"
101+
)
102+
103+
Parameters:
104+
account_name (str): name of storage account. https://{account_name}.blob.core.windows.net
105+
Returns:
106+
BlobServiceClient
107+
"""
108+
credential = self.get_credential()
109+
blob_service_client = BlobServiceClient(
110+
account_url=f"https://{account_name}.blob.core.windows.net",
111+
credential=credential
112+
)
113+
return blob_service_client
114+
115+
116+
@click.command()
117+
@click.option('--debug',
118+
is_flag=True,
119+
default=False,
120+
help="Set log level to debug"
121+
)
122+
def init(debug=False):
123+
"""
124+
This command setup rapida command environment by authenticating to Azure.
125+
"""
126+
logging.basicConfig(level=logging.DEBUG if debug else logging.INFO, force=True)
127+
128+
if click.confirm('Would you like to setup rapida tool?', abort=True):
129+
# login to Azure
130+
session = Session()
131+
credential, token = session.authenticate()
132+
logger.debug(token)
133+
if token is None:
134+
logger.info("Authentication failed.Please `az login` to authenticate first.")
135+
return
136+
click.echo('Setting up was successfully done!')
137+

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ dependencies = [
3232
"azure-core",
3333
"rasterio",
3434
"geopandas",
35+
"azure-identity",
3536
"pytest"
3637
]
3738

0 commit comments

Comments
 (0)