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

Add get channel config endpoint #479

Merged
merged 4 commits into from
Aug 11, 2022
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
94 changes: 94 additions & 0 deletions bootup/docker-compose-files/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# This compose file will deploy the services, and bootup a postgres server.

#
# SPDX-License-Identifier: Apache-2.0
#

# cello-dashboard: dashboard service for cello
# cello-api-engine: api engine service of cello to provide RESTful APIs, listen on 8080
# cello-postgres: postgres db

version: '3.2'
services:
cello-dashboard:
image: hyperledger/cello-dashboard
container_name: cello-dashboard
ports:
- "${DASHBOARD_SERVICE_PORT}:8081"
networks:
- cello-net

# pg database
cello-postgres:
image: postgres:11.1
container_name: cello-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=api_engine
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=123456
ports:
- "5432:5432"
volumes:
- /opt/cello/pgdata:/var/lib/postgresql/data
networks:
- cello-net

cello-redis:
image: redis:4.0.13
hostname: cello-redis
container_name: cello-redis
volumes:
- /opt/cello/redis:/data

# api engine service of cello
cello-api-engine:
image: hyperledger/cello-api-engine
container_name: cello-api-engine
restart: unless-stopped
stdin_open: true
dns_search: .
environment:
- GODEBUG=netdns=go
- DB_NAME=api_engine
- DB_USER=postgres
- DB_PASSWORD=123456
- DB_HOST=cello-postgres
- CELERY_BROKER_URL=redis://redis
- DB_PORT=5432
- DEBUG=True
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
ports:
- "8080:8080"
volumes:
- /opt/cello:/opt/cello
networks:
- cello-net

# cello docker agent may deploy to an individual server. This cofig only serves development purpose.
cello-docker-agent:
image: hyperledger/cello-agent-docker
container_name: cello-docker-agent
hostname: cello.docker.agent
restart: always
ports:
- "2375:2375"
- "5001:5001"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_URL=unix://var/run/docker.sock
- STORAGE_PATH=/opt/hyperledger
networks:
- cello-net

networks:
cello-net:
name: cello-net

volumes:
cello-api-engine:
cello-postgres:
cello-dashboard:
cello-docker-agent:
42 changes: 24 additions & 18 deletions src/api-engine/api/lib/configtxlator/configtxlator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# SPDX-License-Identifier: Apache-2.0
#
from subprocess import call
from subprocess import call, run
from api.config import FABRIC_TOOL


Expand All @@ -10,9 +10,8 @@ class ConfigTxLator:
Class represents configtxlator CLI.
"""

def __init__(self, filepath="", configtxlator=FABRIC_TOOL, version="2.2.0"):
def __init__(self, configtxlator=FABRIC_TOOL, version="2.2.0"):
self.configtxlator = configtxlator + "/configtxlator"
self.filepath = filepath
self.version = version

def proto_encode(self, input, type, output):
Expand All @@ -25,16 +24,17 @@ def proto_encode(self, input, type, output):
output: A file to write the output to.
"""
try:
call([self.configtxlator,
"--input", "{}/{}".format(self.filepath, input),
"--type", type,
"--output", "{}/{}".format(self.filepath, output),
])
res = call([self.configtxlator,
"proto_encode",
"--input={}".format(input),
"--type={}".format(type),
"--output={}".format(output),
])
except Exception as e:
err_msg = "configtxlator proto decode fail! "
raise Exception(err_msg + str(e))

def proto_decode(self, input, type, output):
def proto_decode(self, input, type):
"""
Converts a proto message to JSON.

Expand All @@ -44,11 +44,16 @@ def proto_decode(self, input, type, output):
output: A file to write the output to.
"""
try:
call([self.configtxlator,
"--input", "{}/{}".format(self.filepath, input),
"--type", type,
"--output", "{}/{}".format(self.filepath, output),
])
res = run([self.configtxlator,
"proto_decode",
"--type={}".format(type),
"--input={}".format(input),
],
capture_output= True)
if res.returncode == 0 :
return res.stdout
else:
return res.stderr
except Exception as e:
err_msg = "configtxlator proto decode fail! "
raise Exception(err_msg + str(e))
Expand All @@ -66,10 +71,11 @@ def compute_update(self, original, updated, channel_id, output):
"""
try:
call([self.configtxlator,
"--original", original,
"--updated", updated,
"--channel_id", channel_id,
"--output", "{}/{}".format(self.filepath, output)
"compute_update",
"--original={}".format(original),
"--updated={}".format(updated),
"--channel_id={}".format(channel_id),
"--output={}".format(output),
])
except Exception as e:
err_msg = "configtxlator compute update fail! "
Expand Down
14 changes: 9 additions & 5 deletions src/api-engine/api/lib/peer/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,25 @@ def update(self, channel, channel_tx, orderer_url):
res = res >> 8
return res

def fetch(self, option, channel, orderer_url, time_out="90s"):
def fetch(self, option, channel):
"""
Fetch a specified block, writing it to a file e.g. <channelID>.block.
params:
option: block option newest|oldest|config|(block number).
channel: channel id.
orderer_url: Ordering service endpoint.
"""
try:
res = os.system("{} channel fetch {} -c {} -o {} --timeout {}".format(
self.peer, option, channel, orderer_url, time_out))
res = subprocess.call(args=[
self.peer,
"channel",
"fetch",
"{}".format(option),
"-c",
channel
])
except Exception as e:
err_msg = "fetch a specified block failed {}!".format(e)
raise Exception(err_msg)
res = res >> 8
return res

def signconfigtx(self, channel_tx):
Expand Down
3 changes: 3 additions & 0 deletions src/api-engine/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
FabricVersions,
)
from api.utils.common import make_uuid, random_name, hash_file
from api.config import CELLO_HOME

SUPER_USER_TOKEN = getattr(settings, "ADMIN_TOKEN", "")
MAX_CAPACITY = getattr(settings, "MAX_AGENT_CAPACITY", 100)
Expand Down Expand Up @@ -750,6 +751,8 @@ class Channel(models.Model):
help_text="Orderer list in the channel",
)

def get_channel_config_path(self):
return "/var/www/server/" + self.name +"_config.block"
# class ChainCode(models.Model):
# id = models.UUIDField(
# primary_key=True,
Expand Down
38 changes: 36 additions & 2 deletions src/api-engine/api/routes/channel/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0
#
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

Expand All @@ -12,10 +13,11 @@

from api.config import CELLO_HOME
from api.common.serializers import PageQuerySerializer
from api.utils.common import with_common_response
from api.utils.common import with_common_response, to_dict
from api.auth import TokenAuth
from api.lib.configtxgen import ConfigTX, ConfigTxGen
from api.lib.peer.channel import Channel as PeerChannel
from api.lib.configtxlator.configtxlator import ConfigTxLator
from api.exceptions import (
ResourceNotFound,
)
Expand All @@ -31,6 +33,10 @@
ChannelUpdateSerializer
)
from api.common import ok, err
from api.common.enums import (
NodeStatus,
FabricNodeType,
)


class ChannelViewSet(viewsets.ViewSet):
Expand Down Expand Up @@ -188,7 +194,35 @@ def update(self, request, pk=None):
return Response(status=status.HTTP_202_ACCEPTED)
except ObjectDoesNotExist:
raise ResourceNotFound

@swagger_auto_schema(
responses=with_common_response({status.HTTP_200_OK: "Accepted"}),
)
@action(
methods=["get"],
detail=True,
url_path="config"
)
def get_channel_org_config(self, request, pk=None):
try:
org = request.user.organization
channel = Channel.objects.get(id=pk)
path = channel.get_channel_config_path()
node = Node.objects.filter(
organization=org,
type=FabricNodeType.Peer.name.lower(),
status=NodeStatus.Running.name.lower()
).first()
dir_node = "{}/{}/crypto-config/peerOrganizations".format(
CELLO_HOME, org.name)
env = {
"FABRIC_CFG_PATH": "{}/{}/peers/{}/".format(dir_node, org.name, node.name + "." + org.name),
}
peer_channel_cli = PeerChannel("v2.2.0", **env)
peer_channel_cli.fetch(option="config", channel=channel.name)
config = ConfigTxLator().proto_decode(input=path,type="common.Block")
except ObjectDoesNotExist:
raise ResourceNotFound
return Response(data=to_dict(config, org.name.split(".")[0].capitalize()),status=status.HTTP_200_OK)

def init_env_vars(node, org):
"""
Expand Down
19 changes: 19 additions & 0 deletions src/api-engine/api/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from api.common.serializers import BadResponseSerializer
import uuid
from zipfile import ZipFile
from json import loads


def make_uuid():
Expand Down Expand Up @@ -129,3 +130,21 @@ def zip_file(dirpath, outFullName):
zfile = ZipFile(outFullName, "w")
zfile.write(dirpath, dirpath.rsplit("/", 1)[1])
zfile.close()

def to_dict(data, org_name):
"""
Parse org config from channel config block.

:param data: channel config block in json format.
:param org_name: the organization prefix name
:return organization config
"""
config = loads(data)
if config.get("data") != None:
payloads = config["data"]["data"]
for p in payloads:
groups = p["payload"]["data"]["config"]["channel_group"]["groups"]["Application"]["groups"]
res = groups.get(org_name, None)
if res != None:
return res
return {"error": "can't find channel config"}