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

Adding support for SNMP server object #35

Merged
merged 3 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# PyPowerStore Change Log

## Version 3.4.0.0 - released on 29/11/24
- Added the Support for SNMP server object.

## Version 3.3.0.0 - released on 31/05/24
- Added the Support for ACL in SMB Share object.

Expand Down
48 changes: 48 additions & 0 deletions ProgrammersGuideExamples/snmp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Dell Technologies

""" SNMP server Operations"""
from PyPowerStore import powerstore_conn

CONN = powerstore_conn.PowerStoreConn(username="admin",
password="Pinkballoon082$",
server_ip="10.230.24.67",
verify=False,
timeout=180.0)
print(CONN)

MODIFY_PARAMS = {
"ip_address": "127.0.0.10",
"port": 162,
"trap_community": "community",
"alert_severity": "Info"
}

CREATE_PARAMS = {
"ip_address": "127.0.0.8",
"port": 162,
"version": "V2c",
"alert_severity": "Info",
"trap_community": "public"
}

# create SNMP server
SNMP_SERVER = CONN.snmp_server.create_snmp_server(CREATE_PARAMS)
print(SNMP_SERVER)

# Get SNMP server list
SNMP_SERVERS = CONN.snmp_server.get_snmp_server_list(all_pages=True)
print(SNMP_SERVERS)

# get SNMP server details by ID
SNMP_SERVER = CONN.snmp_server.get_snmp_server_details(SNMP_SERVER['id'])
print(SNMP_SERVER)

# modify SNMP server
MODIFY_SNMP_SERVER = CONN.snmp_server.modify_snmp_server(SNMP_SERVERS[0]['id'],
MODIFY_PARAMS)
print(MODIFY_SNMP_SERVER)

# delete SNMP server
DELETE_SNMP_SERVER = CONN.snmp_server.delete_snmp_server(SNMP_SERVERS[0]['id'])
print(DELETE_SNMP_SERVER)
132 changes: 132 additions & 0 deletions PyPowerStore/objects/snmp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2024, Dell Technologies

"""Collection of SNMP related functions for PowerStore"""

from PyPowerStore.client import Client
from PyPowerStore.utils import constants, helpers

# TODO: kept LOG as global for now will improve it to avoid overriding
LOG = helpers.get_logger(__name__)

SELECT_ALL_SNMP = {"select": "id, ip_address, port, version, trap_community,"
"alert_severity, user_name, auth_protocol, privacy_protocol"}

# SNMP server endpoints
GET_SNMP_LIST_URL = 'https://{0}/api/rest/snmp_server'
GET_SNMP_DETAILS_URL = 'https://{0}/api/rest/snmp_server/{1}'
GET_SNMP_DETAILS_BY_NAS_SERVER_URL = GET_SNMP_LIST_URL
MODIFY_SNMP_URL = GET_SNMP_DETAILS_URL
CREATE_SNMP_URL = GET_SNMP_LIST_URL
DELETE_SNMP_URL = GET_SNMP_DETAILS_URL

class SNMPServer:
"""Provisioning related functionality for PowerStore."""
def __init__(self, provisioning, enable_log=False):
""" Initializes ProtectionFunctions Class.

:param provisioning: Provisioning class object
:type provisioning: Provisioning
:param enable_log: (optional) Whether to enable log or not
:type enable_log: bool
"""
global LOG
self.provisioning = provisioning
self.server_ip = provisioning.server_ip
self.snmp_server_client = provisioning.client
LOG = helpers.get_logger(__name__, enable_log=enable_log)

# SNMP server methods begin
def get_snmp_server_list(self, filter_dict=None, all_pages=False):
"""Get a list of SNMP servers.

:param filter_dict: (optional) Filter detail
:type filter_dict: dict
:param all_pages: (optional) Indicates whether to return all element
or not
:type all_pages: bool
:returns: SNMP servers
:rtype: list of dict
"""
LOG.info("Getting SNMP servers with filter: '%s' and all_pages: %s"
% (filter_dict, all_pages))
querystring = helpers.prepare_querystring(SELECT_ALL_SNMP, filter_dict)
LOG.info("Querystring: '%s'" % querystring)
return self.snmp_server_client.request(constants.GET,
GET_SNMP_LIST_URL.format
(self.server_ip), payload=None,
querystring=querystring,
all_pages=all_pages)

def get_snmp_server_details(self, snmp_server_id):
"""Details of a SNMP server.

:param snmp_server_id: The SNMP server ID
:type snmp_server_id: str
:return:SNMP server details
:rtype: dict
"""
querystring = SELECT_ALL_SNMP

LOG.info("Getting SNMP server details by ID: '%s'" % snmp_server_id)
return self.snmp_server_client.request(
constants.GET,
GET_SNMP_DETAILS_URL.format(self.server_ip,
snmp_server_id),
payload=None,
querystring=querystring)

def create_snmp_server(self, payload):
"""Create an SNMP server.

:param payload: The payload to create the SNMP server
:type payload: dict
:return: SNMP server ID on success else raise exception
:rtype: dict
"""
LOG.info("Creating SNMP server")
return self.snmp_server_client.request(
constants.POST,
CREATE_SNMP_URL.format(self.server_ip),
payload=payload)

def modify_snmp_server(self, snmp_server_id, modify_parameters):
"""Modify SNMP server attributes.

:param snmp_server_id: The ID of the SNMP server
:type snmp_server_id: str
:param modify_parameters: Attributes to be modified
:type modify_parameters: dict
:return: None if success else raise exception
:rtype: None
"""
LOG.info("Modifying SNMP server: '%s'" % snmp_server_id)
if modify_parameters:
payload = dict()
for key, value in modify_parameters.items():
if value is not None:
payload[key] = value

if payload:
return self.snmp_server_client.request(
constants.PATCH,
MODIFY_SNMP_URL.format(
self.server_ip, snmp_server_id),
payload=payload)

raise ValueError("Nothing to modify")

def delete_snmp_server(self, snmp_server_id):
"""Delete an SNMP server.

:param snmp_server_id: The ID of the SNMP server to delete
:type snmp_server_id: str
:return: None on success else raise exception
:rtype: None
"""
LOG.info("Deleting SNMP server: '%s'" % snmp_server_id)
return self.snmp_server_client.request(
constants.DELETE,
DELETE_SNMP_URL.format(self.server_ip, snmp_server_id))

# SNMP server methods end
3 changes: 3 additions & 0 deletions PyPowerStore/powerstore_conn.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from PyPowerStore.objects.nfs_server import NFSServer
from PyPowerStore.objects.file_dns import FileDNS
from PyPowerStore.objects.file_nis import FileNIS
from PyPowerStore.objects.snmp_server import SNMPServer

class PowerStoreConn():
"""Class for establishing connection with PowerStore"""
Expand Down Expand Up @@ -55,3 +56,5 @@ def __init__(self, username, password, server_ip, verify=False,
enable_log=enable_log)
self.file_nis = FileNIS(self.provisioning,
enable_log=enable_log)
self.snmp_server = SNMPServer(self.provisioning,
enable_log=enable_log)
3 changes: 3 additions & 0 deletions PyPowerStore/tests/unit_tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from PyPowerStore.tests.unit_tests.data.nfs_server_data import NFSServerData
from PyPowerStore.tests.unit_tests.data.file_dns_data import FileDNSData
from PyPowerStore.tests.unit_tests.data.file_nis_data import FileNISData
from PyPowerStore.tests.unit_tests.data.snmp_server_data import SNMPServerData
from unittest import mock

class TestBase(TestCase):
Expand Down Expand Up @@ -57,6 +58,7 @@ def setUp(self):
self.nfs_server_data = NFSServerData()
self.file_dns_data = FileDNSData()
self.file_nis_data = FileNISData()
self.snmp_server_data = SNMPServerData()
self.conf = PowerStoreConfig()
self.mock_client = mock.patch('PyPowerStore.provisioning.Client',
new=MockClient)
Expand All @@ -74,3 +76,4 @@ def setUp(self):
self.file_nis = self.conn.file_nis
self.smb_server = self.conn.smb_server
self.nfs_server = self.conn.nfs_server
self.snmp_server = self.conn.snmp_server
75 changes: 75 additions & 0 deletions PyPowerStore/tests/unit_tests/data/snmp_server_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
class SNMPServerData():

snmp_server_id = "snmp_server_id_1"

snmp_server_list = [
{
"id": "2bf5709d-0466-437a-a28f-9d31f2fdfcc5",
"ip_address": "127.0.0.1",
"port": 162,
"version": "V2c",
"trap_community": "commnity",
"alert_severity": "Info",
"user_name": None,
"auth_protocol": None,
"privacy_protocol": None
},
{
"id": "54261519-c5c2-446a-ad76-5f4ca63581df",
"ip_address": "100.96.32.85",
"port": 162,
"version": "V2c",
"trap_community": "public",
"alert_severity": "Info",
"user_name": None,
"auth_protocol": None,
"privacy_protocol": None
},
{
"id": "789f4c09-9e15-4b44-a9f3-baf716172140",
"ip_address": "10.250.230.45",
"port": 162,
"version": "V3",
"trap_community": None,
"alert_severity": "Info",
"user_name": "test",
"auth_protocol": "None",
"privacy_protocol": "None"
}]

snmp_server_detail = {
"id": "789f4c09-9e15-4b44-a9f3-baf716172140",
"ip_address": "10.250.230.45",
"port": 162,
"version": "V3",
"trap_community": None,
"alert_severity": "Info",
"user_name": "test",
"auth_protocol": "None",
"privacy_protocol": "None"
}

snmp_server_valid_param_list = [
"ip_address", "port", "version", "alert_severity", "trap_community"]

snmp_server_id_not_exist = "5f4a3017-0bad-899e-e1eb-c6f547282e66"
snmp_server_error = {
400: {'messages': [{'arguments': ['Object instance has properties '
'which are not allowed by the '
'schema.'],
'code': '0xE04040030001',
'message_l10n': 'Validation failed: Object '
'instance has properties which '
'are not allowed by the schema.',
'severity': 'Error'}]},
422: {"messages": [{
"code": "0xE0F0101D0024",
"severity": "Error",
"message_l10n": "Server Record Not Found, id: c5fdeb93-42ed-4ec9-988e-daec2974f2fk",
"arguments": [
"c5fdeb93-42ed-4ec9-988e-daec2974f2fk"
]
}
]
}
}
53 changes: 53 additions & 0 deletions PyPowerStore/tests/unit_tests/entity/snmp_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from PyPowerStore.tests.unit_tests.entity.base_abstract import Entity
from PyPowerStore.tests.unit_tests.data.snmp_server_data import SNMPServerData
from PyPowerStore.utils import constants
from PyPowerStore.objects import snmp_server

class SNMPServerResponse(Entity):

def __init__(self, method, url, **kwargs):
self.method = method
self.url = url
self.kwargs = kwargs
self.snmp_server_data = SNMPServerData()
self.status_code = 200

def get_api_name(self):
if self.method == 'GET':
if self.url.endswith('/snmp_server'):
return self.get_snmp_server_list
else:
return self.get_snmp_server_details
elif self.method == 'PATCH':
return self.modify_snmp_server
elif self.method == 'POST':
return self.create_snmp_server
elif self.method == 'DELETE':
return self.delete_snmp_server

def execute_api(self, api_name):
status_code, response = api_name()
return status_code, response

def get_snmp_server_list(self):
return self.status_code, self.snmp_server_data.snmp_server_list

def get_snmp_server_details(self):
if self.url.endswith('/snmp_server/{0}'.format(
self.snmp_server_data.snmp_server_id_not_exist)):
return 422, self.snmp_server_data.snmp_server_error[422]
return 200, self.snmp_server_data.snmp_server_detail

def modify_snmp_server(self):
data = self.kwargs.get('data', {})
param = list(data.keys())
if set(param) - set(self.snmp_server_data.snmp_server_valid_param_list):
# invalid param given
return 400, self.snmp_server_data.snmp_server_error[400]
return 204, None

def create_snmp_server(self):
return 201, self.snmp_server_data.snmp_server_id

def delete_snmp_server(self):
return 204, None
4 changes: 3 additions & 1 deletion PyPowerStore/tests/unit_tests/myrequests.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from PyPowerStore.tests.unit_tests.entity.nfs_server import NFSServerResponse
from PyPowerStore.tests.unit_tests.entity.file_dns import FileDNSResponse
from PyPowerStore.tests.unit_tests.entity.file_nis import FileNISResponse
from PyPowerStore.tests.unit_tests.entity.snmp_server import SNMPServerResponse
import json

# map the entity class name with the url resource name
Expand Down Expand Up @@ -103,7 +104,8 @@
'smb_server': SMBServerResponse,
'nfs_server': NFSServerResponse,
'file_dns': FileDNSResponse,
'file_nis': FileNISResponse
'file_nis': FileNISResponse,
'snmp_server': SNMPServerResponse
}


Expand Down
Loading
Loading