Skip to content
Open
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
6 changes: 6 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## Describe your changes

## Checklist before requesting a review
- [ ] I have performed a self-review of my code
- [ ] If it is a core feature, I have added thorough tests.

66 changes: 65 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,65 @@
# plugin-github-inven-collector
# plugin-github-inven-collector

## Introduction
**plugin-spaceone-inven-collector** is an Inventory Collector Plugin for SpaceONE, designed to collect resources from Github.
This plugin has been developed with a new plugin framework.

## Setup and Run
Since the current spaceone-inventory package is in a pre-release state, follow the steps below to configure the package.

### 1. Virtual Environment Setup
Set up a virtual environment using the venv library.
```bash
python3 -m venv venv
```
```bash
source venv/bin/activate
```

### 2. Package Installation
Install the package with the following commands in the created virtual environment.

```bash
pip3 install -r pkg/pip_requirements.txt
pip3 install --pre spaceone-inventory
```

### 3. Interpreter Configuration
If you are using PyCharm, configure the virtual environment as the interpreter.
![img.png](docs/interpreter_settings.png)
![img.png](docs/settings_source_directory.png)
![img.png](docs/run_settings.png)

After following the above steps, run the Plugin Server.
![img.png](docs/run_plugin_server.png)

## Local Environment Testing
After running the Plugin Server, **perform tests for each method** with the following commands.

### Check available API methods:

```bash
spacectl api-resources
```

#### Collector.init
```
spacectl exec init inventory.Collector -f test/init.yml
```


#### Collector.verify

```bash
spacectl exec verify inventory.Collector -f test/verify.yml
```

#### Collector.collect

```bash
spacectl exec collect inventory.Collector -f test/collect.yml
```

#### Note
Metadata will be defined as a dictionary and will be converted to YAML.
The spaceone-inventory package is in a pre-release state, so the `--pre` option must be added when using pip install.
Binary file added docs/interpreter_settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/run_plugin_server.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/run_settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/settings_source_directory.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion pkg/pip_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
spaceone-core
spaceone-api
61 changes: 61 additions & 0 deletions src/plugin/connector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import logging
import requests

from spaceone.core.connector import BaseConnector

__all__ = ["RequestConnector"]

_LOGGER = logging.getLogger(__name__)


class RequestConnector(BaseConnector):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def send_request(
self, url, headers, body=dict, method="GET", page=None, per_page=30
):
try:
if page:
for response in self._pagination(url, headers, body, per_page, page):
yield response
else:
response = requests.get(url, headers=headers).json()
yield response
except Exception as e:
_LOGGER.error(f"Request Error: {e}")
raise e

@staticmethod
def _pagination(url, headers, body, per_page, page):
responses = []
while True:
if url in "&":
url = f"{url}&per_page={per_page}&page={page}"
else:
url = f"{url}?per_page={per_page}&page={page}"
response = requests.get(url, headers=headers)
response_json = response.json()
if not response_json:
break
page += 1
responses.extend(response_json)
return responses

@staticmethod
def make_header(secret_data):
github_token = secret_data.get("github_token")
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {github_token}",
"X-GitHub-Api-Version": "2022-11-28"
}
return headers

@staticmethod
def make_header_dockerhub(secret_data):
dockerhub_token = secret_data.get("dockerhub_token")
headers = {
"Authorization": f"Bearer {dockerhub_token}",
}
return headers
27 changes: 27 additions & 0 deletions src/plugin/connector/dockerhub_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import abc
import requests
import logging

from plugin.connector import RequestConnector

_LOGGER = logging.getLogger(__name__)


class DockerhubConnector(RequestConnector):

def list_tags(self, namespace, repository, secret_data):
url = f'https://hub.docker.com/v2/namespaces/{namespace}/repositories/{repository}/tags'
headers = self.make_header_dockerhub(secret_data)

try:
response = self.send_request(url, headers=headers)
_response = list(response)
if _response and _response[0].get('results'):
results = _response[0].get('results')

return results
else:
return []
except Exception as e:
_LOGGER.error(f"Request Error: {e}")
raise e
Empty file.
40 changes: 40 additions & 0 deletions src/plugin/connector/repository_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import logging

from plugin.connector import RequestConnector

_LOGGER = logging.getLogger(__name__)


class RepositoryConnector(RequestConnector):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def list_organization_repos(self, secret_data) -> list:
headers = self.make_header(secret_data)
url = f"https://api.github.com/orgs/{secret_data.get('organization_name')}/repos"
try:
response = self.send_request(url, headers=headers, page=1)
return response
except Exception as e:
_LOGGER.error(f"Request Error: {e}")
raise e

def list_repo_tags(self, repo_name, secret_data, page=1) -> list:
headers = self.make_header(secret_data)
url = f"https://api.github.com/repos/{secret_data.get('organization_name')}/{repo_name}/tags"
try:
response = self.send_request(url, headers=headers, page=page, per_page=100)
return response
except Exception as e:
_LOGGER.error(f"Request Error: {e}")
raise e

def list_repo_topics(self, repo_name, secret_data):
headers = self.make_header(secret_data)
url = f"https://api.github.com/repos/{secret_data.get('organization_name')}/{repo_name}/topics"
try:
response = self.send_request(url, headers=headers)
return response
except Exception as e:
_LOGGER.error(f"Request Error: {e}")
raise e
82 changes: 29 additions & 53 deletions src/plugin/main.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,42 @@
import logging

from spaceone.inventory.plugin.collector.lib.server import CollectorPluginServer
from plugin.manager.repository_manager import RepositoryManager

_LOGGER = logging.getLogger('cloudforet')

app = CollectorPluginServer()


@app.route('Collector.init')
def collector_init(params: dict) -> dict:
""" init plugin by options

Args:
params (CollectorInitRequest): {
'options': 'dict', # Required
'domain_id': 'str'
}

Returns:
PluginResponse: {
'metadata': 'dict'
}
"""
pass


@app.route('Collector.verify')
def collector_verify(params: dict) -> None:
""" Verifying collector plugin

Args:
params (CollectorVerifyRequest): {
'options': 'dict', # Required
'secret_data': 'dict', # Required
'schema': 'str',
'domain_id': 'str'
}

Returns:
None
"""
pass
return {'metadata': {'options_schema': _create_options_schema()}}


@app.route('Collector.collect')
def collector_collect(params: dict) -> dict:
""" Collect external data

Args:
params (CollectorCollectRequest): {
'options': 'dict', # Required
'secret_data': 'dict', # Required
'schema': 'str',
'domain_id': 'str'
}

Returns:
Generator[ResourceResponse, None, None]
{
'state': 'SUCCESS | FAILURE',
'resource_type': 'inventory.CloudService | inventory.CloudServiceType | inventory.Region',
'resource_data': 'dict',
'match_keys': 'list',
'error_message': 'str'
'metadata': 'dict'
options = params['options']
secret_data = params['secret_data']
schema = params.get('schema')

repository_manager = RepositoryManager()
return repository_manager.collect_resources(options, secret_data, schema)


def _create_options_schema():
return {
'required': ['items'],
'order': ['items'],
'type': 'object',
'properties': {
'items': {
'title': 'Item filter',
'type': 'array',
'items': {
'enum': [
'fields'
]
}
}
}
"""
pass
}
Empty file added src/plugin/manager/__init__.py
Empty file.
Loading