@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 testOpenstackComputeNodeEncode() {

        OpenstackPhyInterface phyIntf1 = DefaultOpenstackPhyInterface.builder()
                                .network("mgmtnetwork")
                                .intf("eth3")
                                .build();
        OpenstackPhyInterface phyIntf2 = DefaultOpenstackPhyInterface.builder()
                                .network("oamnetwork")
                                .intf("eth4")
                                .build();

        OpenstackSshAuth sshAuth = DefaultOpenstackSshAuth.builder()
                .id("sdn")
                .password("sdn")
                .build();

        ControllerInfo controller1 =
                new ControllerInfo(IpAddress.valueOf("10.10.10.2"), 6653, "tcp");
        ControllerInfo controller2 =
                new ControllerInfo(IpAddress.valueOf("10.10.10.3"), 6663, "tcp");

        OpenstackNode node = DefaultOpenstackNode.builder()
                                .hostname("compute")
                                .type(OpenstackNode.NodeType.COMPUTE)
                                .state(NodeState.INIT)
                                .managementIp(IpAddress.valueOf("10.10.10.1"))
                                .intgBridge(DeviceId.deviceId("br-int"))
                                .vlanIntf("vlan")
                                .dataIp(IpAddress.valueOf("20.20.20.2"))
                                .phyIntfs(ImmutableList.of(phyIntf1, phyIntf2))
                                .controllers(ImmutableList.of(controller1, controller2))
                                .sshAuthInfo(sshAuth)
                                .build();

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