Skip to content

Commit

Permalink
[CE-632] Support param customize for fabric ca server
Browse files Browse the repository at this point in the history
For fabric ca server deployment, can set parameters such as,
admin_name,admin_password,hosts.
Add volumes support in k8s agent.

Change-Id: Ie4959ce8e386dfdd281df2c049d77d0ee255208a
Signed-off-by: Haitao Yue <[email protected]>
  • Loading branch information
hightall committed Jul 10, 2019
1 parent 27b96d4 commit 1147686
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ repos:
rev: stable
hooks:
- id: black
entry: black -l 79 src/api-engine
entry: black -l 79 src/api-engine src/agent/kubernetes-agent
language_version: python3.7
28 changes: 26 additions & 2 deletions src/agent/kubernetes-agent/src/network/fabric/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@
# SPDX-License-Identifier: Apache-2.0
#
import logging
import os
import json

from enum import Enum, unique

LOG = logging.getLogger(__name__)
CA_CONFIG = json.loads(os.getenv("CA_CONFIG", "{}"))
# Initial admin name/password for ca server
CA_ADMIN_NAME = CA_CONFIG.get("admin_name", "admin")
CA_ADMIN_PASSWORD = CA_CONFIG.get("admin_password", "adminpw")
CA_HOSTS = CA_CONFIG.get("hosts", "").split(",")
AGENT_IP = os.getenv("AGENT_IP", "")
# Set fabric ca hosts from agent ip and user customize hosts.
CA_HOSTS.append(AGENT_IP)


@unique
Expand Down Expand Up @@ -35,11 +45,25 @@ def _generate_deployment(self):
{
"name": "FABRIC_CA_HOME",
"value": "/etc/hyperledger/fabric-ca-server",
}
},
{
"name": "FABRIC_CA_SERVER_HOME",
"value": "/etc/hyperledger/fabric-ca-server/crypto",
},
{"name": "FABRIC_CA_SERVER_TLS_ENABLED", "value": "true"},
{
"name": "FABRIC_CA_SERVER_CSR_HOSTS",
"value": ",".join(CA_HOSTS),
},
]
ports = [7054]
command = ["fabric-ca-server"]
command_args = ["start", "-b", "admin:adminpw", "-d"]
command_args = [
"start",
"-b",
"%s:%s" % (CA_ADMIN_NAME, CA_ADMIN_PASSWORD),
"-d",
]
containers.append(
{
"image": image,
Expand Down
29 changes: 28 additions & 1 deletion src/agent/kubernetes-agent/src/utils/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,43 @@ def get_or_create_namespace(self, name=None):

def create_deployment(self, namespace=None, *args, **kwargs):
containers = kwargs.get("containers", [])
volumes_json = kwargs.get("volumes", [])
deploy_name = kwargs.get("name")
labels = kwargs.get("labels", {})
labels.update({"app": deploy_name})
container_pods = []
volumes = []
for volume in volumes_json:
volume_name = volume.get("name")
host_path = volume.get("host_path", None)
parameters = {}
if host_path:
host_path = client.V1HostPathVolumeSource(path=host_path)
parameters.update({"host_path": host_path})
persistent_volume_claim = volume.get("pvc", None)
if persistent_volume_claim:
persistent_volume_claim = client.V1PersistentVolumeClaimVolumeSource(
claim_name=persistent_volume_claim
)
parameters.update(
{"persistent_volume_claim": persistent_volume_claim}
)
volumes.append(client.V1Volume(name=volume_name, **parameters))
for container in containers:
name = container.get("name")
image = container.get("image")
ports = container.get("ports", [])
environments = container.get("environments", [])
command = container.get("command", [])
command_args = container.get("command_args", [])
volume_mounts = container.get("volume_mounts", [])
volume_mounts = [
client.V1VolumeMount(
mount_path=volume_mount.get("path"),
name=volume_mount.get("name"),
)
for volume_mount in volume_mounts
]

environments = [
client.V1EnvVar(name=env.get("name"), value=env.get("value"))
Expand All @@ -74,10 +100,11 @@ def create_deployment(self, namespace=None, *args, **kwargs):
args=command_args,
ports=ports,
image_pull_policy="IfNotPresent",
volume_mounts=volume_mounts,
)
)
deployment_metadata = client.V1ObjectMeta(name=deploy_name)
pod_spec = client.V1PodSpec(containers=container_pods)
pod_spec = client.V1PodSpec(containers=container_pods, volumes=volumes)
spec_metadata = client.V1ObjectMeta(labels=labels)
template_spec = client.V1PodTemplateSpec(
metadata=spec_metadata, spec=pod_spec
Expand Down
22 changes: 22 additions & 0 deletions src/api-engine/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,22 @@ def get_compose_file_path(instance, file):
)


class FabricCA(models.Model):
admin_name = models.CharField(
help_text="Admin username for ca server",
default="admin",
max_length=32,
)
admin_password = models.CharField(
help_text="Admin password for ca server",
default="adminpw",
max_length=32,
)
hosts = JSONField(
help_text="Hosts for ca", null=True, blank=True, default=list
)


class Node(models.Model):
id = models.UUIDField(
primary_key=True,
Expand Down Expand Up @@ -340,6 +356,12 @@ class Node(models.Model):
% (FabricNodeType.names()),
max_length=64,
)
ca = models.ForeignKey(
FabricCA,
help_text="CA configuration of node",
null=True,
on_delete=models.CASCADE,
)
urls = JSONField(
help_text="URL configurations for node",
null=True,
Expand Down
19 changes: 18 additions & 1 deletion src/api-engine/api/routes/node/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
HostType,
)
from api.common.serializers import PageQuerySerializer
from api.models import Node, Port
from api.models import Node, Port, FabricCA

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -76,12 +76,28 @@ class NodeListSerializer(serializers.Serializer):
)


class FabricCASerializer(serializers.ModelSerializer):
hosts = serializers.ListField(
help_text="Hosts for ca support",
child=serializers.CharField(help_text="Host name", max_length=64),
required=False,
allow_empty=True,
)

class Meta:
model = FabricCA
fields = ("admin_name", "admin_password", "hosts")


class NodeCreateBody(serializers.ModelSerializer):
agent_type = serializers.ChoiceField(
help_text="Agent type",
choices=HostType.to_choices(True),
required=False,
)
ca = FabricCASerializer(
help_text="CA configuration for node", required=False
)

class Meta:
model = Node
Expand All @@ -91,6 +107,7 @@ class Meta:
"type",
"agent_type",
"agent",
"ca",
)
extra_kwargs = {
"network_type": {"required": True},
Expand Down
24 changes: 18 additions & 6 deletions src/api-engine/api/routes/node/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from api.common.enums import NodeStatus
from api.exceptions import CustomError, NoResource
from api.exceptions import ResourceNotFound
from api.models import Agent, Node, Port
from api.models import Agent, Node, Port, FabricCA, FabricNodeType
from api.routes.node.serializers import (
NodeOperationSerializer,
NodeQuery,
Expand Down Expand Up @@ -127,6 +127,7 @@ def create(self, request):
network_version = serializer.validated_data.get("network_version")
agent = serializer.validated_data.get("agent")
node_type = serializer.validated_data.get("type")
ca = serializer.validated_data.get("ca", {})
if agent is None:
available_agents = (
Agent.objects.annotate(network_num=Count("node__network"))
Expand All @@ -150,13 +151,27 @@ def create(self, request):
node_count = Node.objects.filter(agent=agent).count()
if node_count >= agent.node_capacity or not agent.schedulable:
raise NoResource

fabric_ca = None
if node_type == FabricNodeType.Ca.name.lower():
ca_body = {}
admin_name = ca.get("admin_name")
admin_password = ca.get("admin_password")
hosts = ca.get("hosts", [])
if admin_name:
ca_body.update({"admin_name": admin_name})
if admin_password:
ca_body.update({"admin_password": admin_password})
fabric_ca = FabricCA(**ca_body, hosts=hosts)
fabric_ca.save()
node = Node(
network_type=network_type,
agent=agent,
network_version=network_version,
user=request.user,
organization=request.user.organization,
type=node_type,
ca=fabric_ca,
)
node.save()
agent_config_file = (
Expand All @@ -172,11 +187,8 @@ def create(self, request):
agent_config_file=agent_config_file,
node_update_api=node_update_api,
)
response = NodeIDSerializer(data={"id": str(node.id)})
if response.is_valid(raise_exception=True):
return Response(
response.validated_data, status=status.HTTP_201_CREATED
)
response = NodeIDSerializer({"id": str(node.id)})
return Response(response.data, status=status.HTTP_201_CREATED)

@swagger_auto_schema(
methods=["post"],
Expand Down
14 changes: 14 additions & 0 deletions src/api-engine/api/tasks/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
from __future__ import absolute_import, unicode_literals

import json
import logging
import os

Expand Down Expand Up @@ -34,12 +35,25 @@ def create_node(self, node_id=None, agent_image=None, **kwargs):
"NODE_TYPE": node.type,
"NODE_ID": str(node.id),
"AGENT_ID": str(node.agent.id),
"AGENT_IP": str(node.agent.ip),
"AGENT_CONFIG_FILE": agent_config_file,
"NODE_UPDATE_URL": node_update_api,
# Token for call update node api
"TOKEN": ADMIN_TOKEN,
"OPERATION": AgentOperation.Start.value,
}
if node.ca:
environment.update(
{
"CA_CONFIG": json.dumps(
{
"admin_name": node.ca.admin_name,
"admin_password": node.ca.admin_password,
"hosts": ",".join(node.ca.hosts),
}
)
}
)
client = docker.from_env()
client.containers.run(
agent_image, auto_remove=True, environment=environment, detach=True
Expand Down

0 comments on commit 1147686

Please sign in to comment.