@Override
    public ObjectNode encode(OpenstackNode node, CodecContext context) {
        checkNotNull(node, "Openstack node cannot be null");

        ObjectNode result = context.mapper().createObjectNode()
                .put(HOST_NAME, node.hostname())
                .put(TYPE, node.type().name())
                .put(STATE, node.state().name())
                .put(MANAGEMENT_IP, node.managementIp().toString());

        OpenstackNode.NodeType type = node.type();

        // serialize uplink port only for gateway node
        if (type == OpenstackNode.NodeType.GATEWAY) {
            result.put(UPLINK_PORT, node.uplinkPort());
        }

        // serialize keystone config for controller node
        if (type == OpenstackNode.NodeType.CONTROLLER) {

            ObjectNode keystoneConfigJson = context.codec(KeystoneConfig.class)
                    .encode(node.keystoneConfig(), context);

            result.set(KEYSTONE_CONFIG, keystoneConfigJson);

            // serialize neutron config for controller node
            if (node.neutronConfig() != null) {
                ObjectNode neutronConfigJson = context.codec(NeutronConfig.class)
                        .encode(node.neutronConfig(), context);

                result.set(NEUTRON_CONFIG, neutronConfigJson);
            }
        }

        // serialize integration bridge config
        if (node.intgBridge() != null) {
            result.put(INTEGRATION_BRIDGE, node.intgBridge().toString());
        }

        // serialize VLAN interface, it is valid only if any VLAN interface presents
        if (node.vlanIntf() != null) {
            result.put(VLAN_INTF_NAME, node.vlanIntf());
        }

        // serialize data IP only if it presents
        if (node.dataIp() != null) {
            result.put(DATA_IP, node.dataIp().toString());
        }

        // serialize physical interfaces, it is valid only if any of physical interface presents
        if (node.phyIntfs() != null && !node.phyIntfs().isEmpty()) {
            ArrayNode phyIntfs = context.mapper().createArrayNode();
            node.phyIntfs().forEach(phyIntf -> {
                ObjectNode phyIntfJson =
                        context.codec(OpenstackPhyInterface.class).encode(phyIntf, context);
                phyIntfs.add(phyIntfJson);
            });
            result.set(PHYSICAL_INTERFACES, phyIntfs);
        }

        // serialize controllers, it is valid only if any of controller presents
        if (node.controllers() != null && !node.controllers().isEmpty()) {
            ArrayNode controllers = context.mapper().createArrayNode();
            node.controllers().forEach(controller -> {
                ObjectNode controllerJson =
                        context.codec(ControllerInfo.class).encode(controller, context);
                controllers.add(controllerJson);
            });
            result.set(CONTROLLERS, controllers);
        }

        // serialize SSH authentication info, it is valid only if auth info presents
        if (node.sshAuthInfo() != null) {
            ObjectNode sshAuthJson = context.codec(OpenstackSshAuth.class)
                    .encode(node.sshAuthInfo(), context);
            result.set(SSH_AUTH, sshAuthJson);
        }

        // serialize DPDK config, it is valid only if dpdk config presents
        if (node.dpdkConfig() != null) {
            ObjectNode dpdkConfigJson = context.codec(DpdkConfig.class)
                    .encode(node.dpdkConfig(), context);
            result.set(DPDK_CONFIG, dpdkConfigJson);
        }

        return result;
    }
@Test
    public void testOpenstackControllerNodeEncode() {
        OpenstackAuth auth = DefaultOpenstackAuth.builder()
                .version("v2.0")
                .protocol(OpenstackAuth.Protocol.HTTP)
                .project("admin")
                .username("admin")
                .password("nova")
                .perspective(OpenstackAuth.Perspective.PUBLIC)
                .build();

        String endpoint = "172.16.130.10:35357/v2.0";

        KeystoneConfig keystoneConfig = DefaultKeystoneConfig.builder()
                                            .endpoint(endpoint)
                                            .authentication(auth)
                                            .build();

        NeutronConfig neutronConfig = DefaultNeutronConfig.builder()
                                            .useMetadataProxy(true)
                                            .metadataProxySecret("onos")
                                            .novaMetadataIp("172.16.130.10")
                                            .novaMetadataPort(8775)
                                            .build();

        OpenstackNode node = DefaultOpenstackNode.builder()
                .hostname("controller")
                .type(OpenstackNode.NodeType.CONTROLLER)
                .state(NodeState.INIT)
                .managementIp(IpAddress.valueOf("172.16.130.10"))
                .keystoneConfig(keystoneConfig)
                .neutronConfig(neutronConfig)
                .build();

        ObjectNode nodeJson = openstackNodeCodec.encode(node, context);
        assertThat(nodeJson, matchesOpenstackNode(node));
    }