From: Khaldoon Al-zoubi Date: Sun, 8 Nov 2015 22:53:28 +0000 (-0500) Subject: Integrating FAAS renderer with the faas fabric mapping services. Also, X-Git-Tag: release/beryllium~35 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=9882f0b0f43843d5b32b947ddd171a2f02a22b0f;p=groupbasedpolicy.git Integrating FAAS renderer with the faas fabric mapping services. Also, put tenants external explicit groups in resolved policies to be accessible by renderers. Change-Id: I41447bb41c71ca1e6cfb4fa001c4dd736b02a37e Signed-off-by: Khaldoon Al-zoubi --- diff --git a/features/pom.xml b/features/pom.xml index 4f789f3c9..2b1d9e7ce 100755 --- a/features/pom.xml +++ b/features/pom.xml @@ -31,6 +31,7 @@ 0.2.0-SNAPSHOT 1.2.1-SNAPSHOT 0.6.0-SNAPSHOT + 1.0.0-SNAPSHOT 0.2.0-SNAPSHOT 1.3.0-SNAPSHOT 0.3.0-SNAPSHOT @@ -137,6 +138,15 @@ ${neutron.version} xml + + + + org.opendaylight.faas + features-faas + features + ${faas.version} + xml + diff --git a/features/src/main/features/features.xml b/features/src/main/features/features.xml index 3d1ae992a..faa6dd888 100755 --- a/features/src/main/features/features.xml +++ b/features/src/main/features/features.xml @@ -19,6 +19,8 @@ mvn:org.opendaylight.openflowplugin/features-openflowplugin/{{VERSION}}/xml/features mvn:org.opendaylight.openflowplugin/features-openflowplugin-extension/{{VERSION}}/xml/features mvn:org.opendaylight.ovsdb/southbound-features/{{VERSION}}/xml/features + + mvn:org.opendaylight.faas/features-faas/{{VERSION}}/xml/features mvn:org.opendaylight.neutron/features-neutron/{{VERSION}}/xml/features @@ -84,7 +86,7 @@ --> odl-groupbasedpolicy-base - odl-openflowplugin-nxm-extensions + odl-faas-uln-mapper mvn:org.opendaylight.groupbasedpolicy/faas-renderer/{{VERSION}} mvn:org.opendaylight.groupbasedpolicy/faas-renderer/{{VERSION}}/xml/config diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java index 1d260fc5f..255e90a5e 100755 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/resolver/PolicyResolver.java @@ -224,7 +224,7 @@ public class PolicyResolver implements PolicyValidatorRegistry, AutoCloseable { Table policyMap = PolicyResolverUtils.resolvePolicy(indexedTenants); ResolvedPolicies resolvedPolicies = - new ResolvedPoliciesBuilder().setResolvedPolicy(PolicyInfoUtils.buildResolvedPolicy(policyMap)).build(); + new ResolvedPoliciesBuilder().setResolvedPolicy(PolicyInfoUtils.buildResolvedPolicy(policyMap, resolvedTenants)).build(); wTx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(ResolvedPolicies.class).build(), resolvedPolicies, true); diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java index e588d7432..4d0a4289f 100644 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/IidFactory.java @@ -116,6 +116,14 @@ public class IidFactory { .build(); } + public static InstanceIdentifier contractWildcardIid(TenantId tenantId) { + return InstanceIdentifier.builder(Tenants.class) + .child(Tenant.class, new TenantKey(tenantId)) + .child(Policy.class) + .child(Contract.class) + .build(); + } + public static InstanceIdentifier subjectIid(TenantId tenantId, ContractId contractId, SubjectName subjectName) { return InstanceIdentifier.builder(Tenants.class) @@ -281,6 +289,14 @@ public class IidFactory { .build(); } + public static InstanceIdentifier subnetWildcardIid(TenantId tenantId) { + return InstanceIdentifier.builder(Tenants.class) + .child(Tenant.class, new TenantKey(tenantId)) + .child(ForwardingContext.class) + .child(Subnet.class) + .build(); + } + public static InstanceIdentifier followedEndpointgroupIid(RendererName rendererName, TenantId tenantId, EndpointGroupId epgId) { return InstanceIdentifier.builder(Renderers.class) @@ -307,4 +323,21 @@ public class IidFactory { .child(SupportedClassifierDefinition.class) .build(); } + + public static InstanceIdentifier followedTenantIid(RendererName rendererName, TenantId tenantId) { + return InstanceIdentifier.builder(Renderers.class) + .child(Renderer.class, new RendererKey(rendererName)) + .child(Interests.class) + .child(FollowedTenants.class) + .child(FollowedTenant.class, new FollowedTenantKey(tenantId)) + .build(); + } + + public static InstanceIdentifier rendererIid(RendererName rendererName) { + return InstanceIdentifier.builder(Renderers.class).child(Renderer.class, new RendererKey(rendererName)).build(); + } + + public static InstanceIdentifier renderersIid() { + return InstanceIdentifier.builder(Renderers.class).build(); + } } diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/InheritanceUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/InheritanceUtils.java index 5bf27a6a2..f7b46864c 100644 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/InheritanceUtils.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/InheritanceUtils.java @@ -134,6 +134,7 @@ public class InheritanceUtils { .setPolicy(new PolicyBuilder().setEndpointGroup(ImmutableList.copyOf(resolvedEgs.values())) .setContract(ImmutableList.copyOf(resolvedContracts.values())) .setContractRef(unresolvedPolicy.getContractRef()) + .setExternalImplicitGroup(unresolvedPolicy.getExternalImplicitGroup()) .setSubjectFeatureInstances(unresolvedPolicy.getSubjectFeatureInstances()) .build()); } diff --git a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/PolicyInfoUtils.java b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/PolicyInfoUtils.java index 94e2c6780..100c54f30 100644 --- a/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/PolicyInfoUtils.java +++ b/groupbasedpolicy/src/main/java/org/opendaylight/groupbasedpolicy/util/PolicyInfoUtils.java @@ -12,15 +12,19 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentMap; import org.opendaylight.groupbasedpolicy.dto.ConditionSet; import org.opendaylight.groupbasedpolicy.dto.EgKey; import org.opendaylight.groupbasedpolicy.dto.EndpointConstraint; +import org.opendaylight.groupbasedpolicy.dto.IndexedTenant; import org.opendaylight.groupbasedpolicy.dto.Policy; import org.opendaylight.groupbasedpolicy.dto.RuleGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef.ConnectionTracking; @@ -50,6 +54,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.p import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRuleBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.resolved.rules.ResolvedRuleKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy.ExternalImplicitGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicyBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraints; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraintsBuilder; @@ -57,17 +62,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.p import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroupBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.ProviderEndpointConstraintsBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.Table; import com.google.common.collect.Table.Cell; public class PolicyInfoUtils { - + private static final Logger LOG = LoggerFactory.getLogger(PolicyInfoUtils.class); private PolicyInfoUtils() { throw new UnsupportedOperationException("Cannot create an instance"); } - public static List buildResolvedPolicy(Table policyMap) { + public static List buildResolvedPolicy(Table policyMap, + ConcurrentMap resolvedTenants) { List resolvedPolicies = new ArrayList<>(); for (Cell policyCell : policyMap.cellSet()) { ResolvedPolicyBuilder resolvedPolicyBuilder = new ResolvedPolicyBuilder(); @@ -77,11 +85,35 @@ public class PolicyInfoUtils { resolvedPolicyBuilder.setProviderTenantId(policyCell.getColumnKey().getTenantId()); resolvedPolicyBuilder.setPolicyRuleGroupWithEndpointConstraints( buildPolicyRuleGroupWithEndpointConstraints(policyCell.getValue())); + Tenant consTenant = resolvedTenants.get(policyCell.getRowKey().getTenantId()).getTenant(); + Tenant provTenant = resolvedTenants.get(policyCell.getColumnKey().getTenantId()).getTenant(); + if (isExternalImplicitGroup(consTenant, policyCell.getRowKey().getEgId())) { + resolvedPolicyBuilder.setExternalImplicitGroup(ExternalImplicitGroup.ConsumerEpg); + } else if (isExternalImplicitGroup(provTenant, policyCell.getColumnKey().getEgId())) { + resolvedPolicyBuilder.setExternalImplicitGroup(ExternalImplicitGroup.ProviderEpg); + } resolvedPolicies.add(resolvedPolicyBuilder.build()); } return resolvedPolicies; } + private static boolean isExternalImplicitGroup(Tenant tenant, EndpointGroupId epgId) { + if (tenant == null || epgId == null || tenant.getPolicy() == null + || tenant.getPolicy().getExternalImplicitGroup() == null) { + return false; + } + LOG.trace("Found External EPGs in Tenant {}", tenant.getId().getValue()); + for (org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup eig : tenant.getPolicy() + .getExternalImplicitGroup()) { + if (eig.getId().equals(epgId)) { + LOG.trace("EPG {} is External Implicit Group", epgId.getValue()); + return true; + } + } + LOG.trace("EPG {} is NOT External Implicit Group", epgId.getValue()); + return false; + } + private static List buildPolicyRuleGroupWithEndpointConstraints( Policy policy) { List policyRuleGroupWithEndpointConstraintsList = new ArrayList<>(); diff --git a/renderers/faas/pom.xml b/renderers/faas/pom.xml index a99a73b86..4b75906e6 100644 --- a/renderers/faas/pom.xml +++ b/renderers/faas/pom.xml @@ -19,13 +19,14 @@ 0.2.0-SNAPSHOT + 1.0.0-SNAPSHOT - org.opendaylight.openflowplugin - openflowplugin-extension-nicira - ${openflowplugin.version} + org.opendaylight.faas + uln-mapper-model + ${faas.version} @@ -57,4 +58,4 @@ - \ No newline at end of file + diff --git a/renderers/faas/src/main/config/default-config.xml b/renderers/faas/src/main/config/default-config.xml index 670e85144..4da9c6b0a 100644 --- a/renderers/faas/src/main/config/default-config.xml +++ b/renderers/faas/src/main/config/default-config.xml @@ -17,20 +17,16 @@ faas-provider-impl - - binding:binding-rpc-registry - binding-rpc-broker - - binding:binding-async-data-broker binding-data-broker - - - binding:binding-new-notification-service - binding-notification-adapter - + + + epr:ep-renderer-augmentation-registry + ep-renderer-augmentation-registry + + diff --git a/renderers/faas/src/main/java/org/opendaylight/controller/config/yang/config/faas_provider/impl/FaasProviderModule.java b/renderers/faas/src/main/java/org/opendaylight/controller/config/yang/config/faas_provider/impl/FaasProviderModule.java index 553910055..3909c975b 100644 --- a/renderers/faas/src/main/java/org/opendaylight/controller/config/yang/config/faas_provider/impl/FaasProviderModule.java +++ b/renderers/faas/src/main/java/org/opendaylight/controller/config/yang/config/faas_provider/impl/FaasProviderModule.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. - * + * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html @@ -32,8 +32,7 @@ public class FaasProviderModule extends @Override public java.lang.AutoCloseable createInstance() { - return new FaasRenderer(getDataBrokerDependency(), getRpcRegistryDependency(), - getNotificationAdapterDependency()); + return new FaasRenderer(getDataBrokerDependency(), getEpRendererAugmentationRegistryDependency()); } } diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasContractManagerListener.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasContractManagerListener.java new file mode 100644 index 000000000..f4311e38b --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasContractManagerListener.java @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi; +import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Name; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.parameter.values.grouping.ParameterValue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.parameter.values.grouping.ParameterValueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.parameter.values.grouping.parameter.value.RangeValueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.SecurityRuleGroupsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.SecurityRuleGroup; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.SecurityRuleGroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.SecurityRule; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.SecurityRuleBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.security.rule.RuleAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.security.rule.RuleActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.security.rule.RuleClassifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.security.rule.RuleClassifier.Direction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.security.rules.rev151013.security.rule.groups.attributes.security.rule.groups.container.security.rule.groups.security.rule.group.security.rule.RuleClassifierBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContractBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Policy; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.SubjectFeatureInstances; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Clause; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Subject; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.subject.Rule; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstanceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstanceKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +public class FaasContractManagerListener implements DataChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(FaasContractManagerListener.class); + private ConcurrentHashMap mappedContracts = new ConcurrentHashMap<>(); + private final ScheduledExecutorService executor; + private final DataBroker dataProvider; + private final TenantId gbpTenantId; + private final Uuid faasTenantId; + + public FaasContractManagerListener(DataBroker dataProvider, TenantId gbpTenantId, Uuid faasTenantId, + ScheduledExecutorService executor) { + this.executor = executor; + this.gbpTenantId = gbpTenantId; + this.faasTenantId = faasTenantId; + this.dataProvider = dataProvider; + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + executor.execute(new Runnable() { + + public void run() { + executeEvent(change); + } + }); + } + + private void executeEvent(final AsyncDataChangeEvent, DataObject> change) { + // Create + for (DataObject dao : change.getCreatedData().values()) { + if (dao instanceof Contract) { + Contract contract = (Contract) dao; + LOG.debug("Contract {} is Created.", contract.getId().getValue()); + UlnDatastoreApi.submitSecurityGroupsToDs(initSecurityGroupBuilder(contract).build()); + } + } + // Update + Map, DataObject> dao = change.getUpdatedData(); + for (Map.Entry, DataObject> entry : dao.entrySet()) { + if (entry.getValue() instanceof Contract) { + Contract contract = (Contract) dao; + LOG.debug("Contract {} is Updated.", contract.getId().getValue()); + UlnDatastoreApi.submitSecurityGroupsToDs(initSecurityGroupBuilder(contract).build()); + } + } + // Remove + for (InstanceIdentifier iid : change.getRemovedPaths()) { + DataObject old = change.getOriginalData().get(iid); + if (old == null) { + continue; + } + if (old instanceof Contract) { + Contract contract = (Contract) old; + LOG.debug("Contract {} is removed.", contract.getId().getValue()); + ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); + Optional op = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedContractIid(gbpTenantId, contract.getId()), rwTx); + if (op.isPresent()) { + DataStoreHelper.submitToDs(rwTx); + } + Uuid val = mappedContracts.remove(contract.getId()); + if (val != null) { + UlnDatastoreApi.removeSecurityGroupsFromDsIfExists(faasTenantId, val); + } + } + } + } + + public void loadAll(List contracts, List mpContracts) { + if (mpContracts != null) { + for (MappedContract mpContract : mpContracts) { + mappedContracts.putIfAbsent(mpContract.getGbpContractId(), mpContract.getFaasSecurityRulesId()); + } + } + if (contracts != null) { + for (Contract contract : contracts) { + LOG.debug("Loading Contract {}", contract.getId().getValue()); + UlnDatastoreApi.submitSecurityGroupsToDs(initSecurityGroupBuilder(contract).build()); + } + } + } + + private SecurityRuleGroupsBuilder initSecurityGroupBuilder(Contract contract) { + LOG.trace("Start initSecurityGroupBuilder"); + SecurityRuleGroupsBuilder builder = new SecurityRuleGroupsBuilder(); + builder.setUuid(getFaasSecurityRulesId(contract.getId())); + builder.setName(new Text(contract.getId().getValue())); + if (contract.getDescription() != null) + builder.setDescription(new Text("gbp-contract: " + contract.getDescription().getValue())); + else + builder.setDescription(new Text("gbp-contract")); + builder.setTenantId(faasTenantId); + builder.setSecurityRuleGroup(buildSecurityRuleGroup(contract)); + LOG.trace("Contract {} is mapped to Faas Security Rules {} ", contract.getId().getValue(), builder.getUuid() + .getValue()); + return builder; + } + + private Uuid getFaasSecurityRulesId(ContractId contractId) { + Uuid val = mappedContracts.get(contractId); + if (val != null) { + return val; + } + Uuid faasContractId = null; + if (FaasPolicyManager.isUUid(contractId.getValue())) { + faasContractId = new Uuid(contractId.getValue()); + } else { + faasContractId = new Uuid(UUID.randomUUID().toString()); + } + mappedContracts.putIfAbsent(contractId, faasContractId); + val = mappedContracts.get(contractId); + MappedContractBuilder builder = new MappedContractBuilder(); + builder.setFaasSecurityRulesId(val); + builder.setGbpContractId(contractId); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + MappedContract result = builder.build(); + wTx.put(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedContractIid(gbpTenantId, contractId), result); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Contract {}", result); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Contract {}", result); + } + return val; + } + + private List buildSecurityRuleGroup(Contract contract) { + LOG.trace("Start buildSecurityRuleGroup for contract {}", contract.getId().getValue()); + List securityRuleGroups = new ArrayList<>(); + if (contract.getClause() == null) { + LOG.debug("contract {} has no Clause", contract.getId().getValue()); + return null; + } + for (Clause clause : contract.getClause()) { + if (clause.getSubjectRefs() == null) { + LOG.debug("Clause {} in contract {} has no Subject Ref", clause.getName().getValue(), contract.getId() + .getValue()); + continue; + } + if (contract.getSubject() == null) { + LOG.warn("Couldn't find in Contract {} the expected subject references", contract.getId().getValue()); + continue; + } + for (SubjectName subjectRef : clause.getSubjectRefs()) { + LOG.trace("Start Parsing Subject Ref {} in Contract {}", subjectRef, contract.getId().getValue()); + for (Subject sub : contract.getSubject()) { + if (subjectRef.equals(sub.getName())) { + SecurityRuleGroupBuilder securityRuleGroupBuilder = new SecurityRuleGroupBuilder(); + securityRuleGroupBuilder.setName(new Name(subjectRef.getValue())); + List subRules = sub.getRule(); + if (subRules == null) { + LOG.warn("Subject {} in Contract {} doesn't have rules", subjectRef.getValue(), + contract.getId().getValue()); + } else { + List securityRules = getSecurityRules(contract, subjectRef, subRules); + LOG.debug("Subject {} in Contract {} has {} rules", subjectRef.getValue(), contract.getId() + .getValue(), securityRules.size()); + securityRuleGroupBuilder.setSecurityRule(securityRules); + } + LOG.debug("Added Rule {} to Subject {} in Contract {}", securityRuleGroupBuilder.getName() + .getValue(), subjectRef.getValue(), contract.getId().getValue()); + securityRuleGroups.add(securityRuleGroupBuilder.build()); + } + } + } + } + LOG.trace("Done with buildSecurityRuleGroup for contract {}", contract.getId().getValue()); + return securityRuleGroups; + } + + private List getSecurityRules(Contract contract, SubjectName subjectRef, List subRules) { + List securityRules = new ArrayList<>(); + for (Rule rule : subRules) { + List classifierRefs = rule.getClassifierRef(); + List pClassifiers = null; + if (classifierRefs == null || classifierRefs.isEmpty()) { + LOG.warn("Rule {} in Subject {} in Contract {} doesn't have classifiers", rule.getName(), subjectRef, + contract.getId()); + } else { + pClassifiers = getClassifiers(gbpTenantId, contract, classifierRefs, dataProvider); + if (pClassifiers == null || pClassifiers.isEmpty()) { + LOG.warn("Rule {} in Subject {} in Contract {} doesn't have classifiers -- Will ignore this rule", + rule.getName(), subjectRef, contract.getId()); + } + } + List actionRefs = rule.getActionRef(); + List pActions = null; + if (actionRefs == null || actionRefs.isEmpty()) { + LOG.warn("Rule {} in Subject {} in Contract {} doesn't have actions", rule.getName(), subjectRef, + contract.getId()); + } else { + pActions = getActions(contract, actionRefs); + if (pActions == null || pActions.isEmpty()) { + LOG.warn("Rule {} in Subject {} in Contract {} doesn't have actions", rule.getName(), subjectRef, + contract.getId()); + } + } + + securityRules.add(new SecurityRuleBuilder().setName(new Name(rule.getName().getValue())) + .setOrder(rule.getOrder()) + .setRuleClassifier(pClassifiers) + .setRuleAction(pActions) + .build()); + } // for rules + return securityRules; + } + + private List getActions(Contract contract, List actionRefs) { + LOG.trace("Start Parsing Actions for actionRefs count {} in Contract {}", actionRefs.size(), contract.getId() + .getValue()); + List pActions = new ArrayList<>(); + for (ActionRef actionRef : actionRefs) { + if (actionRef.getName() == null) { + LOG.warn("Couldn't find an Action in Contract {} -- ignored Action", contract.getId().getValue()); + continue; + } + RuleActionBuilder ruleActionBuilder = new RuleActionBuilder(); + ruleActionBuilder.setName(new Name(actionRef.getName().getValue())); + ruleActionBuilder.setOrder(actionRef.getOrder()); + ActionInstance actionInstance = getActionInstance(actionRef.getName()); + if (actionInstance == null) { + LOG.warn("Action instance {} is not found -- will only use the Action ref info", actionRef.getName()); + } else { + if (actionInstance.getActionDefinitionId() != null) { + ruleActionBuilder.setAdditionalInfo(new Text(actionInstance.getActionDefinitionId().getValue())); + } + List parms = null; + if (actionInstance.getParameterValue() != null) { + LOG.trace("Action Instance {} has {} parameters", actionInstance.getName().getValue(), + actionInstance.getParameterValue().size()); + parms = new ArrayList<>(); + for (org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue instance : actionInstance.getParameterValue()) { + ParameterValueBuilder pBuilder = new ParameterValueBuilder(); + pBuilder.setIntValue(instance.getIntValue()); + if (instance.getName() != null) { + pBuilder.setName(new Name(instance.getName().getValue())); + } + pBuilder.setStringValue(instance.getStringValue()); + if (instance.getRangeValue() != null) { + RangeValueBuilder rBuilder = new RangeValueBuilder().setMax( + instance.getRangeValue().getMax()).setMin(instance.getRangeValue().getMin()); + pBuilder.setRangeValue(rBuilder.build()); + } + ParameterValue parm = pBuilder.build(); + LOG.trace("Added Parm {} from Action Instance {}", parm, actionInstance.getName().getValue()); + parms.add(parm); + } + } else { + LOG.trace("Action Instance {} has no parameters", actionInstance.getName().getValue()); + } + ruleActionBuilder.setParameterValue(parms); + } + pActions.add(ruleActionBuilder.build()); + } + + return pActions; + } + + private ActionInstance getActionInstance(ActionName name) { + ReadOnlyTransaction trans = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier ciId = InstanceIdentifier.builder(Tenants.class) + .child(Tenant.class, new TenantKey(gbpTenantId)) + .child(Policy.class) + .child(SubjectFeatureInstances.class) + .child(ActionInstance.class, new ActionInstanceKey(name)) + .build(); + try { + Optional data = trans.read(LogicalDatastoreType.CONFIGURATION, ciId).get(); + if (data.isPresent()) { + return data.get(); + } + } catch (Exception e) { + LOG.error("Couldn't read Action instance from datastore. Exception: ", e); + } + return null; + } + + private List getClassifiers(TenantId tenantId, Contract contract, + List classifierRefs, DataBroker dataProvider) { + List fClassifiers = new ArrayList<>(); + for (ClassifierRef classifierRef : classifierRefs) { + if (classifierRef.getName() == null) { + LOG.warn("Found a Classifer without name in Contract {} ", contract.getId().getValue()); + continue; + } + RuleClassifierBuilder ruleClassifierBuilder = new RuleClassifierBuilder(); + ruleClassifierBuilder.setName(new Name(classifierRef.getName().getValue())); + ClassifierInstance classifierInstance = getClassifierInstance(tenantId, classifierRef.getName(), + dataProvider); + if (classifierInstance == null) { + LOG.warn("Classifer instance {} is not found -- will only use the classifier Ref info", + classifierRef.getName()); + } else { + if (classifierInstance.getClassifierDefinitionId() != null) { + ruleClassifierBuilder.setAdditionalInfo(new Text(classifierInstance.getClassifierDefinitionId() + .getValue())); + } + List parms = null; + if (classifierInstance.getParameterValue() != null) { + LOG.trace("Calssifier Instance {} has {} parameters", classifierInstance.getName().getValue(), + classifierInstance.getParameterValue().size()); + parms = new ArrayList<>(); + for (org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue instance : classifierInstance.getParameterValue()) { + ParameterValueBuilder pBuilder = new ParameterValueBuilder(); + pBuilder.setIntValue(instance.getIntValue()); + pBuilder.setName(new Name(instance.getName().getValue())); + pBuilder.setStringValue(instance.getStringValue()); + if (instance.getRangeValue() != null) { + RangeValueBuilder rBuilder = new RangeValueBuilder().setMax( + instance.getRangeValue().getMax()).setMin(instance.getRangeValue().getMin()); + pBuilder.setRangeValue(rBuilder.build()); + } + ParameterValue parm = pBuilder.build(); + LOG.trace("Added parm {} from Classifier Instance {}", parm, classifierInstance.getName() + .getValue()); + parms.add(parm); + } + } else { + LOG.trace("Classifier Instance {} has no parameters", classifierInstance.getName().getValue()); + } + ruleClassifierBuilder.setParameterValue(parms); + } + if (classifierRef.getDirection() != null) { + ruleClassifierBuilder.setDirection(Direction.forValue(classifierRef.getDirection().getIntValue())); + } else { + ruleClassifierBuilder.setDirection(Direction.Bidirectional); + } + fClassifiers.add(ruleClassifierBuilder.build()); + } + return fClassifiers; + } + + private ClassifierInstance getClassifierInstance(TenantId tenantId, ClassifierName name, DataBroker dataProvider) { + ReadOnlyTransaction trans = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier ciId = InstanceIdentifier.builder(Tenants.class) + .child(Tenant.class, new TenantKey(tenantId)) + .child(Policy.class) + .child(SubjectFeatureInstances.class) + .child(ClassifierInstance.class, new ClassifierInstanceKey(name)) + .build(); + try { + Optional data = trans.read(LogicalDatastoreType.CONFIGURATION, ciId).get(); + if (data.isPresent()) { + return data.get(); + } + } catch (Exception e) { + LOG.error("Couldn't read Action instance from datastore. Exception: ", e); + } + return null; + } +} diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointAug.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointAug.java new file mode 100644 index 000000000..fec6b90be --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointAug.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Map; + +import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentation; +import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.faas.endpoint.rev151009.FaasEndpointContext; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.faas.endpoint.rev151009.FaasEndpointContextBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.faas.endpoint.rev151009.FaasEndpointContextInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix; +import org.opendaylight.yangtools.yang.binding.Augmentation; + +public class FaasEndpointAug implements EpRendererAugmentation, AutoCloseable { + + private EpRendererAugmentationRegistry epRendererAugmentationRegistry; + + public FaasEndpointAug(EpRendererAugmentationRegistry epRendererAugmentationRegistry) { + + this.epRendererAugmentationRegistry = epRendererAugmentationRegistry; + epRendererAugmentationRegistry.register(this); + } + + @Override + public Map.Entry>, Augmentation> buildEndpointAugmentation( + RegisterEndpointInput input) { + FaasEndpointContextBuilder pb; + FaasEndpointContextInput pix = input.getAugmentation(FaasEndpointContextInput.class); + if (pix == null) { + pb = new FaasEndpointContextBuilder(); + } else { + pb = new FaasEndpointContextBuilder(pix); + } + return new SimpleImmutableEntry>, Augmentation>( + FaasEndpointContext.class, pb.build()); + + } + + @Override + public Map.Entry>, Augmentation> buildEndpointL3Augmentation( + RegisterEndpointInput input) { + return null; + } + + @Override + public Map.Entry>, Augmentation> buildL3PrefixEndpointAugmentation( + RegisterL3PrefixEndpointInput input) { + return null; + } + + @Override + public void close() throws Exception { + epRendererAugmentationRegistry.unregister(this); + } +} diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointManagerListener.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointManagerListener.java index ea5746419..f78fb5637 100644 --- a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointManagerListener.java +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasEndpointManagerListener.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. - * + * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html @@ -10,55 +10,112 @@ package org.opendaylight.groupbasedpolicy.renderer.faas; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ScheduledExecutorService; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi; +import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; import org.opendaylight.groupbasedpolicy.util.IidFactory; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.faas.endpoint.rev151009.FaasEndpointContext; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.endpoints.locations.rev151013.endpoints.locations.container.endpoints.locations.EndpointLocationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.ports.container.ports.port.PrivateIps; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.ports.container.ports.port.PrivateIpsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpointBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpointKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + public class FaasEndpointManagerListener implements DataChangeListener, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(FaasEndpointManagerListener.class); - + private final ScheduledExecutorService executor; private final ListenerRegistration registerListener; + private final FaasPolicyManager policyManager; + private final DataBroker dataProvider; - public FaasEndpointManagerListener(DataBroker dataProvider) { + public FaasEndpointManagerListener(FaasPolicyManager policyManager, DataBroker dataProvider, + ScheduledExecutorService executor) { + this.executor = executor; + this.policyManager = policyManager; + this.dataProvider = dataProvider; this.registerListener = checkNotNull(dataProvider).registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointsIidWildcard(), this, AsyncDataBroker.DataChangeScope.SUBTREE); } @Override - public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { + public void close() throws Exception { + if (registerListener != null) + registerListener.close(); + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + executor.execute(new Runnable() { + + public void run() { + executeEvent(change); + } + }); + } + + private void executeEvent(final AsyncDataChangeEvent, DataObject> change) { + // Create for (DataObject dao : change.getCreatedData().values()) { if (dao instanceof Endpoint) { - LOG.debug("Created Endpoint {}", (Endpoint) dao); + Endpoint endpoint = (Endpoint) dao; + LOG.debug("Created Endpoint {}", endpoint); + if (validate(endpoint)) { + policyManager.registerTenant(endpoint.getTenant(), endpoint.getEndpointGroup()); + processEndpoint(endpoint); + } } else if (dao instanceof EndpointL3) { LOG.debug("Created EndpointL3 {}", (EndpointL3) dao); } else if (dao instanceof EndpointL3Prefix) { - LOG.debug("Created EndpointL3Prefix {}", (EndpointL3Prefix) dao); + LOG.warn("Not Handled Event Yet by Faas Renderer. Created EndpointL3Prefix {}", (EndpointL3Prefix) dao); } } // Update Map, DataObject> dao = change.getUpdatedData(); for (Map.Entry, DataObject> entry : dao.entrySet()) { if (entry.getValue() instanceof Endpoint) { - LOG.debug("Updated Endpoint {}", (Endpoint) dao); + Endpoint endpoint = (Endpoint) dao; + LOG.debug("Updated Endpoint {}", endpoint); + if (validate(endpoint)) { + policyManager.registerTenant(endpoint.getTenant(), endpoint.getEndpointGroup()); + processEndpoint(endpoint); + } } else if (entry.getValue() instanceof EndpointL3) { LOG.debug("Updated EndpointL3 {}", (EndpointL3) dao); } else if (entry.getValue() instanceof EndpointL3Prefix) { - LOG.debug("Updated EndpointL3Prefix {}", (EndpointL3Prefix) dao); + LOG.warn("Not Handled Event Yet by Faas Renderer. Updated EndpointL3Prefix {}", (EndpointL3Prefix) dao); } } // Remove @@ -68,18 +125,162 @@ public class FaasEndpointManagerListener implements DataChangeListener, AutoClos continue; } if (old instanceof Endpoint) { - LOG.debug("Removed Endpoint {}", (Endpoint) old); + Endpoint endpoint = (Endpoint) dao; + LOG.debug("Removed Endpoint {}", endpoint); + removeFaasEndpointLocationIfExist(endpoint.getTenant(), endpoint.getL2Context(), + endpoint.getMacAddress()); } else if (old instanceof EndpointL3) { - LOG.debug("Removed EndpointL3 {}", (EndpointL3) old); + EndpointL3 endpoint = (EndpointL3) dao; + LOG.debug("Removed EndpointL3 {}", endpoint); + removeFaasEndpointLocationIfExist(endpoint.getTenant(), endpoint.getL2Context(), + endpoint.getMacAddress()); } else if (old instanceof EndpointL3Prefix) { - LOG.debug("Removed EndpointL3Prefix {}", (EndpointL3Prefix) old); + LOG.warn("Not Handled Event Yet by Faas Renderer. Removed EndpointL3Prefix {}", (EndpointL3Prefix) old); } } } - @Override - public void close() throws Exception { - if (registerListener != null) - registerListener.close(); + private void processEndpoint(Endpoint endpoint) { + Uuid tenantId = policyManager.getFaasTenantId(endpoint.getTenant()); + if (tenantId == null) { + LOG.error("Failed Endpoint Registration. Couldn't find faas tenant Id. Endpoint {}", endpoint); + return; + } + EndpointLocationBuilder epLocBuilder = new EndpointLocationBuilder(); + epLocBuilder.setDescription(new Text("gbp-endpoint")); + epLocBuilder.setName(new Text(endpoint.getL2Context().getValue())); + epLocBuilder.setTenantId(tenantId); + epLocBuilder.setFaasPortRefId(endpoint.getAugmentation(FaasEndpointContext.class).getFaasPortRefId()); + Uuid epId = getFaasEndpointId(endpoint); + if (epId == null) { + LOG.error("Failed Endpoint registration. Couldn't Create Faas Endpoint Id"); + return; + } + epLocBuilder.setUuid(epId); + Uuid faasSubnetId = getFaasSubnetId(endpoint); + List privateIpAddresses = new ArrayList(); + for (L3Address ip : endpoint.getL3Address()) { + PrivateIpsBuilder ipBuilder = new PrivateIpsBuilder(); + ipBuilder.setIpAddress(ip.getIpAddress()); + ipBuilder.setSubnetId(faasSubnetId); + privateIpAddresses.add(ipBuilder.build()); + } + if (!UlnDatastoreApi.attachEndpointToSubnet(epLocBuilder, faasSubnetId, endpoint.getMacAddress(), + privateIpAddresses, null)) { + LOG.error("Failed Endpoint Registration. Failed to Attach Endpoint to Faas Logical Network. Endpoint {}", + endpoint); + } + } + + private Uuid getFaasEndpointId(Endpoint endpoint) { + MappedEndpoint mEndpoint1 = getMappedEndpoint(endpoint); + if (mEndpoint1 != null) { + return mEndpoint1.getEndpointLocation(); + } + synchronized (this) {// must be atomic + MappedEndpoint mEndpoint2 = getMappedEndpoint(endpoint); + if (mEndpoint2 != null) { + return mEndpoint2.getEndpointLocation(); + } + MappedEndpointBuilder mBuilder = new MappedEndpointBuilder(); + mBuilder.setL2Context(endpoint.getL2Context()); + mBuilder.setMacAddress(endpoint.getMacAddress()); + mBuilder.setEndpointLocation(new Uuid(UUID.randomUUID().toString())); + MappedEndpoint mEndpoint = mBuilder.build(); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.OPERATIONAL, FaasIidFactory.mappedEndpointIid( + endpoint.getTenant(), new MappedEndpointKey(endpoint.getL2Context(), endpoint.getMacAddress())), + mEndpoint); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Endpoint {}", mEndpoint); + return mEndpoint.getEndpointLocation(); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Endpoint {}", mEndpoint); + return null; + } + } + } + + private Uuid getFaasSubnetId(Endpoint endpoint) { + if (endpoint.getEndpointGroup() == null) { + LOG.error("Failed Endpoint registration -- No Endpoint-Group Id in endpoint {}", endpoint); + return null; + } + SubnetId subnetId = null; + if (endpoint.getNetworkContainment() != null) { + LOG.trace("Subnet is defined based on endpoint containment value {}", endpoint.getNetworkContainment() + .getValue()); + subnetId = new SubnetId(endpoint.getNetworkContainment()); + } + if (subnetId == null) { + LOG.error("Failed Endpoint registration -- Couldn't find a subnet for endpoint {}", endpoint.getKey()); + return null; + } + LOG.debug("Using subnetId {} for endpoint {}", subnetId, endpoint.getKey()); + policyManager.registerSubnetWithEpg(endpoint.getEndpointGroup(), endpoint.getTenant(), subnetId); + + Optional subnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedSubnetIid(endpoint.getTenant(), subnetId), + dataProvider.newReadWriteTransaction()); + if (subnetOp.isPresent()) { + return subnetOp.get().getFaasSubnetId(); + } + LOG.error("Failed Endpoint registration -- Couldn't find Mapped Subnet Id based on GBP Subnet Id {}", subnetId); + return null; + } + + private boolean validate(Endpoint endpoint) { + if (endpoint.getL2Context() == null) { + LOG.error("Endpoint Failed Validation -- Missing L2 Context. Endpoint {}", endpoint); + return false; + } + if (endpoint.getL3Address() == null) { + LOG.error("Endpoint Failed Validation -- Missing L3 Address. Endpoint {}", endpoint); + return false; + } + if (endpoint.getMacAddress() == null) { + LOG.error("Endpoint Failed Validation -- Missing Mac Address. Endpoint {}", endpoint); + return false; + } + if (endpoint.getTenant() == null) { + LOG.error("Endpoint Failed Validation -- Missing Tenant Id. Endpoint {}", endpoint); + return false; + } + if (endpoint.getEndpointGroup() == null) { + LOG.error("Endpoint Failed Validation -- Missing Endpoint-Group. Endpoint {}", endpoint); + return false; + } + FaasEndpointContext faasEpAug = endpoint.getAugmentation(FaasEndpointContext.class); + if (faasEpAug == null || faasEpAug.getFaasPortRefId() == null) { + LOG.error("Endpoint Failed Validation -- Missing Required Faas Info. Endpoint {}", endpoint); + return false; + } + return true; + } + + private void removeFaasEndpointLocationIfExist(TenantId tenantId, L2BridgeDomainId l2BridgeDomainId, + MacAddress macAddress) { + synchronized (this) { + MappedEndpointKey mappedEndpointKey = new MappedEndpointKey(l2BridgeDomainId, macAddress); + ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); + Optional endpointOp = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedEndpointIid(tenantId, mappedEndpointKey), rwTx); + DataStoreHelper.submitToDs(rwTx); + if (endpointOp.isPresent()) { + UlnDatastoreApi.removeEndpointLocationFromDsIfExists(policyManager.getFaasTenantId(tenantId), + endpointOp.get().getEndpointLocation()); + } + } + } + + private MappedEndpoint getMappedEndpoint(Endpoint endpoint) { + MappedEndpointKey mappedEndpointKey = new MappedEndpointKey(endpoint.getL2Context(), endpoint.getMacAddress()); + Optional endpointOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedEndpointIid(endpoint.getTenant(), mappedEndpointKey), + dataProvider.newReadWriteTransaction()); + if (endpointOp.isPresent()) { + return endpointOp.get(); + } + return null; } } diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasIidFactory.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasIidFactory.java new file mode 100644 index 000000000..634e77864 --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasIidFactory.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.LogicalNetworks; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.MappedTenantsEntities; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetwork; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetworkKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntity; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntityKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenantKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContractKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpoint; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpointKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnetKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class FaasIidFactory { + + public static InstanceIdentifier logicalNetworksIid() { + return InstanceIdentifier.builder(LogicalNetworks.class).build(); + } + + public static InstanceIdentifier logicalNetworkIid(EndpointGroupId consumerEpgId, + TenantId consumerTenantId, ContractId contractId, EndpointGroupId providerEpgId, TenantId providerTenantId) { + return InstanceIdentifier.builder(LogicalNetworks.class) + .child(LogicalNetwork.class, + new LogicalNetworkKey(consumerEpgId, consumerTenantId, contractId, providerEpgId, providerTenantId)) + .build(); + } + + public static InstanceIdentifier mappedTenantsEntitiesIid() { + return InstanceIdentifier.builder(MappedTenantsEntities.class).build(); + } + + public static InstanceIdentifier mappedSubnetIid(TenantId gbpTenantId, SubnetId subnetId) { + return InstanceIdentifier.builder(MappedTenantsEntities.class) + .child(MappedEntity.class, new MappedEntityKey(gbpTenantId)) + .child(MappedSubnet.class, new MappedSubnetKey(subnetId)) + .build(); + } + + public static InstanceIdentifier mappedTenantIid(TenantId gbpTenantId) { + return InstanceIdentifier.builder(MappedTenantsEntities.class) + .child(MappedTenant.class, new MappedTenantKey(gbpTenantId)) + .build(); + } + + public static InstanceIdentifier mappedEntityIid(TenantId gbpTenantId) { + return InstanceIdentifier.builder(MappedTenantsEntities.class) + .child(MappedEntity.class, new MappedEntityKey(gbpTenantId)) + .build(); + } + + public static InstanceIdentifier mappedContractIid(TenantId gbpTenantId, ContractId contractId) { + return InstanceIdentifier.builder(MappedTenantsEntities.class) + .child(MappedEntity.class, new MappedEntityKey(gbpTenantId)) + .child(MappedContract.class, new MappedContractKey(contractId)) + .build(); + } + + public static InstanceIdentifier mappedEndpointIid(TenantId gbpTenantId, + MappedEndpointKey mappedEndpointKey) { + return InstanceIdentifier.builder(MappedTenantsEntities.class) + .child(MappedEntity.class, new MappedEntityKey(gbpTenantId)) + .child(MappedEndpoint.class, mappedEndpointKey) + .build(); + } +} diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasPolicyManager.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasPolicyManager.java new file mode 100644 index 000000000..17a57c45f --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasPolicyManager.java @@ -0,0 +1,1062 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.faas.uln.datastore.api.Pair; +import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi; +import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.groupbasedpolicy.util.IidFactory; +import org.opendaylight.groupbasedpolicy.util.TenantUtils; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.logical.routers.rev151013.logical.routers.container.logical.routers.LogicalRouterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.logical.switches.rev151013.logical.switches.container.logical.switches.LogicalSwitchBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.PortLocationAttributes.LocationType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.LogicalNetworks; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.ScopeType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.ServiceCommunicationLayer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetwork; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetworkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.logical.network.ConsumerNetworkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.logical.network.ProviderNetworkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntity; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntityBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenantBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.FollowedTenantBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroup; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPolicies; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy.ExternalImplicitGroup; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraints; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +public class FaasPolicyManager implements DataChangeListener, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(FaasPolicyManager.class); + private static final RendererName rendererName = new RendererName("faas"); + private final ListenerRegistration registerListener; + private final ScheduledExecutorService executor; + private final DataBroker dataProvider; + private final Map, List> epgSubnetsMap = new HashMap<>(); + private final ConcurrentHashMap mappedTenants = new ConcurrentHashMap<>(); + private final ConcurrentHashMap>> registeredTenants = new ConcurrentHashMap>>(); + + public FaasPolicyManager(DataBroker dataBroker, ScheduledExecutorService executor) { + this.dataProvider = dataBroker; + this.executor = executor; + this.registerListener = checkNotNull(dataProvider).registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + InstanceIdentifier.builder(ResolvedPolicies.class).child(ResolvedPolicy.class).build(), this, + AsyncDataBroker.DataChangeScope.SUBTREE); + + RendererBuilder rendBuilder = new RendererBuilder(); + rendBuilder.setName(rendererName); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.rendererIid(rendererName), rendBuilder.build()); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("{} renderer registered with the multi-renderer manager", rendererName.getValue()); + } else { + LOG.error("{} renderer Failed to register with the multi-renderer manager", rendererName.getValue()); + } + } + + @Override + public void close() throws Exception { + synchronized (registeredTenants) { + for (ArrayList> list : registeredTenants.values()) { + for (ListenerRegistration reg : list) { + reg.close(); + } + } + registeredTenants.clear(); + + LOG.debug("Closed All Tenant Registerations"); + } + if (registerListener != null) + registerListener.close(); + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + executor.execute(new Runnable() { + + public void run() { + executeEvent(change); + } + }); + } + + private void executeEvent(final AsyncDataChangeEvent, DataObject> change) { + // Create + for (DataObject dao : change.getCreatedData().values()) { + if (dao instanceof ResolvedPolicy) { + ResolvedPolicy newPolicy = (ResolvedPolicy) dao; + if (handledPolicy(newPolicy)) { + LOG.debug("Created Policy: Consumer EPG {}, Provider EPG {}", newPolicy.getConsumerEpgId(), + newPolicy.getProviderEpgId()); + updateLogicalNetwork(newPolicy); + } + } + } + // Update + Map, DataObject> d = change.getUpdatedData(); + for (Map.Entry, DataObject> entry : d.entrySet()) { + if (entry.getValue() instanceof ResolvedPolicy) { + ResolvedPolicy newPolicy = (ResolvedPolicy) entry.getValue(); + ResolvedPolicy oldPolicy = (ResolvedPolicy) change.getOriginalData().get(entry.getKey()); + if (!isEqualService(newPolicy, oldPolicy)) { + removeLogicalNetwork(oldPolicy); + } + if (handledPolicy(newPolicy)) { + LOG.debug("Updated Policy: Consumer EPG {}, Provider EPG {}", newPolicy.getConsumerEpgId(), + newPolicy.getProviderEpgId()); + updateLogicalNetwork(newPolicy); + } + } + } + + // Remove + for (InstanceIdentifier iid : change.getRemovedPaths()) { + DataObject old = change.getOriginalData().get(iid); + if (old != null && old instanceof ResolvedPolicy) { + ResolvedPolicy oldPolicy = (ResolvedPolicy) old; + LOG.debug("Removed Policy: Consumer EPG {}, Provider EPG {}", oldPolicy.getConsumerEpgId(), + oldPolicy.getProviderEpgId()); + removeLogicalNetwork(oldPolicy); + } + } + } + + public void registerTenant(TenantId gbpTenantId) { + registerTenant(gbpTenantId, null); + } + + public void registerTenant(TenantId gbpTenantId, EndpointGroupId epgId) { + if (registeredTenants.get(gbpTenantId) != null) { + registerFollowedEndpointgroup(gbpTenantId, epgId); + return; // already registered + } + synchronized (this) { + if (registeredTenants.get(gbpTenantId) != null) { + return; // already registered + } + /* + * map tenant's required elements to faas logical networks + */ + Optional mTenantOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedTenantIid(gbpTenantId), dataProvider.newReadOnlyTransaction()); + Uuid faasTenantId; + if (mTenantOptional.isPresent()) { + faasTenantId = mTenantOptional.get().getFaasTenantId(); + } else { + faasTenantId = getFaasTenantId(gbpTenantId); + } + // load tenant datastore info + Tenant tenant = null; + Optional tenantOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, + TenantUtils.tenantIid(gbpTenantId), dataProvider.newReadOnlyTransaction()); + if (tenantOptional.isPresent()) { + tenant = tenantOptional.get(); + } + List contracts = null; + List subnets = null; + if (tenant != null) { + contracts = tenant.getPolicy().getContract(); + subnets = tenant.getForwardingContext().getSubnet(); + } + Optional mEntityOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedEntityIid(gbpTenantId), + dataProvider.newReadOnlyTransaction()); + MappedEntity mappedEntity; + if (mEntityOptional.isPresent()) { + mappedEntity = mEntityOptional.get(); + } else { + // This is needed as a workaround of a datastore problem + MappedEntityBuilder builder = new MappedEntityBuilder(); + builder.setGbpTenantId(gbpTenantId); + mappedEntity = builder.build(); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedEntityIid(gbpTenantId), mappedEntity); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Initailized Mapped Entry in Datastore for tenant {}", gbpTenantId); + } else { + LOG.error("Couldn't Initailized Mapped Entry in Datastore for tenant {}", gbpTenantId); + } + } + + // contracts + FaasContractManagerListener faasContractManagerListener = new FaasContractManagerListener(dataProvider, + gbpTenantId, faasTenantId, executor); + faasContractManagerListener.loadAll(contracts, mappedEntity.getMappedContract()); + // subnets + FaasSubnetManagerListener faasSubnetManagerListener = new FaasSubnetManagerListener(dataProvider, + gbpTenantId, faasTenantId, executor); + faasSubnetManagerListener.loadAll(subnets, mappedEntity.getMappedSubnet()); + + /* + * tenant registrations + */ + ArrayList> list = new ArrayList>(); + ListenerRegistration reg; + // contracts + reg = dataProvider.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + IidFactory.contractWildcardIid(gbpTenantId), faasContractManagerListener, DataChangeScope.SUBTREE); + list.add(reg); + // subnets + reg = dataProvider.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + IidFactory.subnetWildcardIid(gbpTenantId), faasSubnetManagerListener, DataChangeScope.SUBTREE); + list.add(reg); + + // tenant + reg = dataProvider.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, + IidFactory.tenantIid(gbpTenantId), new FaasTenantManagerListener(this, gbpTenantId, faasTenantId, + executor), DataChangeScope.BASE); + list.add(reg); + + // Map previously resolved policy for this tenant + mapAllTenantResolvedPolicies(gbpTenantId, null); + + registerFollowedTenant(gbpTenantId, epgId); + + // track all registrations + registeredTenants.put(gbpTenantId, list); + + LOG.debug("Registered tenant {}", gbpTenantId); + } + } + + private void mapAllTenantResolvedPolicies(TenantId gbpTenantId, EndpointGroupId epgId) { + Optional resolvedPoliciesOptional = DataStoreHelper.readFromDs( + LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(ResolvedPolicies.class).build(), + dataProvider.newReadOnlyTransaction()); + if (!resolvedPoliciesOptional.isPresent() || resolvedPoliciesOptional.get().getResolvedPolicy() == null) { + return; + } + List resolvedPolicies = resolvedPoliciesOptional.get().getResolvedPolicy(); + for (ResolvedPolicy policy : resolvedPolicies) { + if (policy.getConsumerTenantId().equals(gbpTenantId)) { + if (epgId == null || epgId.equals(policy.getConsumerEpgId()) || epgId.equals(policy.getProviderEpgId())) { + // if any epg or a specific epg policy + updateLogicalNetwork(policy); + } + } + } + } + + private void registerFollowedTenant(TenantId gbpTenantId, EndpointGroupId epgId) { + FollowedTenantBuilder fTenantBuilder = new FollowedTenantBuilder(); + fTenantBuilder.setId(gbpTenantId); + if (epgId != null) { + List epgs = new ArrayList<>(); + epgs.add(new FollowedEndpointGroupBuilder().setId(epgId).build()); + fTenantBuilder.setFollowedEndpointGroup(epgs); + } + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.followedTenantIid(rendererName, gbpTenantId), + fTenantBuilder.build()); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.info("Tenant {} is followed by renderer {}", gbpTenantId.getValue(), rendererName.getValue()); + } else { + LOG.info("Couldn't register Tenant {} that is followed by renderer {}", gbpTenantId.getValue(), + rendererName.getValue()); + } + } + + private void registerFollowedEndpointgroup(TenantId gbpTenantId, EndpointGroupId epgId) { + if (epgId == null) { + return; + } + FollowedEndpointGroupBuilder fEpgBuilder = new FollowedEndpointGroupBuilder(); + fEpgBuilder.setId(epgId); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + wTx.put(LogicalDatastoreType.OPERATIONAL, + IidFactory.followedEndpointgroupIid(rendererName, gbpTenantId, epgId), fEpgBuilder.build()); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.trace("EPG {} in Tenant {} is followed by renderer {}", epgId.getValue(), gbpTenantId.getValue(), + rendererName.getValue()); + } else { + LOG.info("Couldn't register EPG {} in Tenant {} that is followed by renderer {}", epgId.getValue(), + gbpTenantId.getValue(), rendererName.getValue()); + } + } + + public Uuid getFaasTenantId(TenantId tenantId) { + Uuid val = mappedTenants.get(tenantId); + if (val != null) { + return val; + } + Uuid faasTenantId = null; + if (isUUid(tenantId.getValue())) { + faasTenantId = new Uuid(tenantId.getValue()); + } else { + faasTenantId = new Uuid(UUID.randomUUID().toString()); + } + mappedTenants.putIfAbsent(tenantId, faasTenantId); + val = mappedTenants.get(tenantId); + MappedTenantBuilder builder = new MappedTenantBuilder(); + builder.setFaasTenantId(val); + builder.setGbpTenantId(tenantId); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + MappedTenant result = builder.build(); + wTx.put(LogicalDatastoreType.OPERATIONAL, FaasIidFactory.mappedTenantIid(tenantId), result); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Tenant {}", result); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Tenant {}", result); + } + return val; + } + + public static boolean isUUid(String value) { + return (value != null && value.matches("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}")); + } + + public void unregisterTenant(TenantId tenantId) { + + ArrayList> list = registeredTenants.remove(tenantId); + if (list != null) { + for (ListenerRegistration reg : list) { + reg.close(); + } + LOG.debug("Unregistered tenant {}", tenantId); + } + registeredTenants.remove(tenantId); + Uuid faasTenantId = mappedTenants.get(tenantId); + if (faasTenantId != null) { + removeTenantLogicalNetwork(tenantId, faasTenantId, false); + } + } + + public boolean isTenantRegistered(TenantId tenantId) { + return registeredTenants.containsKey(tenantId); + } + + private boolean handledPolicy(ResolvedPolicy policy) { + if (!policy.getConsumerTenantId().equals(policy.getProviderTenantId())) { + // FAAS always assumes consumer and provider EPGs belong to the same tenant + LOG.warn( + "Ignore Resolved Policy between Consumer EPG {} and Provider EPG {} becuase they belong to different Tenants", + policy.getConsumerTenantId().getValue(), policy.getProviderTenantId().getValue()); + return false; + } + if (!isTenantRegistered(policy.getConsumerTenantId())) { + return false; + } + return true; + } + + private boolean isEqualService(ResolvedPolicy newPolicy, ResolvedPolicy oldPolicy) { + return oldPolicy != null && newPolicy.getConsumerEpgId().equals(oldPolicy.getConsumerEpgId()) + && newPolicy.getProviderEpgId().equals(oldPolicy.getProviderEpgId()) + && newPolicy.getConsumerTenantId().equals(oldPolicy.getConsumerTenantId()) + && newPolicy.getProviderTenantId().equals(oldPolicy.getProviderTenantId()); + } + + public void registerSubnetWithEpg(EndpointGroupId epgId, TenantId tenantId, SubnetId subnetId) { + registerSubnetWithEpg(epgId, tenantId, subnetId, true); + } + + private void registerSubnetWithEpg(EndpointGroupId epgId, TenantId tenantId, SubnetId subnetId, boolean updateLn) { + synchronized (this) { + List subnets = cloneAndGetEpgSubnets(epgId, tenantId); + for (SubnetId id : subnets) { + if (id.equals(subnetId)) { + return; + } + } + subnets.add(subnetId); + epgSubnetsMap.put(new Pair<>(epgId, tenantId), subnets); + LOG.debug("Registered Subnet {} with EPG {}", subnetId, epgId); + if (updateLn) { + mapAllTenantResolvedPolicies(tenantId, epgId); + } + } + } + + private void removeLogicalNetwork(ResolvedPolicy oldPolicy) { + if (oldPolicy == null) { + return; + } + removeLogicalNetwork(oldPolicy.getConsumerEpgId(), oldPolicy.getConsumerTenantId(), getContractId(oldPolicy), + oldPolicy.getProviderEpgId(), oldPolicy.getProviderTenantId()); + } + + private void removeLogicalNetwork(EndpointGroupId consumerEpgId, TenantId consumerTenantId, ContractId contractId, + EndpointGroupId providerEpgId, TenantId providerTenantId) { + ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); + Optional lnOp = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.logicalNetworkIid(consumerEpgId, consumerTenantId, contractId, + providerEpgId, providerTenantId), rwTx); + if (lnOp.isPresent()) { + DataStoreHelper.submitToDs(rwTx); + LogicalNetwork logicalNetwork = lnOp.get(); + Uuid consTenantId = getFaasTenantId(logicalNetwork.getConsumerTenantId()); + Uuid provTenantId = getFaasTenantId(logicalNetwork.getProviderTenantId()); + + UlnDatastoreApi.removeLogicalSwitchFromDsIfExists(consTenantId, logicalNetwork.getConsumerNetwork() + .getLogicalSwitchId()); + UlnDatastoreApi.removeLogicalSwitchFromDsIfExists(provTenantId, logicalNetwork.getProviderNetwork() + .getLogicalSwitchId()); + if (logicalNetwork.getConsumerNetwork().getLogicalRouterId() != null) { + UlnDatastoreApi.removeLogicalRouterFromDsIfExists(consTenantId, logicalNetwork.getConsumerNetwork() + .getLogicalRouterId()); + } + if (logicalNetwork.getProviderNetwork().getLogicalRouterId() != null) { + UlnDatastoreApi.removeLogicalRouterFromDsIfExists(provTenantId, logicalNetwork.getProviderNetwork() + .getLogicalRouterId()); + } + } + } + + private synchronized void updateLogicalNetwork(ResolvedPolicy policy) { + updateLogicalNetwork(policy.getConsumerEpgId(), getContractId(policy), policy.getProviderEpgId(), + policy.getConsumerTenantId(), policy.getExternalImplicitGroup()); + } + + private synchronized void updateLogicalNetwork(EndpointGroupId consumerEpgId, ContractId contractId, + EndpointGroupId providerEpgId, TenantId tenantId, ExternalImplicitGroup externalImplicitGroup) { + + LOG.trace("Start updateLogicalNetwork: Consumer EPG {} Provider Epg {} Contract {}", consumerEpgId, + providerEpgId, contractId); + + // Create Logical network + EndpointGroup consEpg = readEndpointGroup(consumerEpgId, tenantId); + if (consEpg == null) { + LOG.error("Couldn't Creat Logical Network. Missing EPG {}", consumerEpgId); + return; + } + List consSubnetIds = cloneAndGetEpgSubnets(consEpg.getId(), tenantId); + if (consSubnetIds.isEmpty()) { + LOG.info("Couldn't Creat Logical Network. Missing Subnets for Consumer EPG {}", consumerEpgId); + return; + } + EndpointGroup provEpg = readEndpointGroup(providerEpgId, tenantId); + if (provEpg == null) { + LOG.error("Couldn't Creat Logical Network. Missing EPG {}", providerEpgId); + return; + } + List provSubnetIds = cloneAndGetEpgSubnets(provEpg.getId(), tenantId); + if (provSubnetIds.isEmpty()) { + LOG.info("Couldn't Creat Logical Network. Missing Subnets for Provider EPG {}", providerEpgId); + return; + } + + ServiceCommunicationLayer comLayer = findLayerNetwork(tenantId, consSubnetIds, provSubnetIds); + if (comLayer == null) { + LOG.error( + "Couldn't determine forwarding Context. Couldn't Process Logical Network for Consumer EPG {} Provider Epg {} Contract {}", + consumerEpgId, providerEpgId, contractId); + return; + } + + if (needToCreateLogicalNetwork(comLayer, consSubnetIds, provSubnetIds, tenantId, contractId, provEpg, consEpg, + externalImplicitGroup)) { + if (comLayer == ServiceCommunicationLayer.Layer2) { + createLayer2LogicalNetwork(consEpg, contractId, provEpg, tenantId, comLayer, externalImplicitGroup); + } else if (comLayer == ServiceCommunicationLayer.Layer3) { + createLayer3LogicalNetwork(consEpg, contractId, provEpg, tenantId, comLayer, externalImplicitGroup); + } else { + LOG.error("Couldn't find the communication layer.Consumer EPG {} Provider Epg {} Contract {}", + consumerEpgId, providerEpgId, contractId); + } + } else { + LOG.debug("No need to Create the Logical Network. Consumer EPG {} Provider Epg {} Contract {}", + consumerEpgId, providerEpgId, contractId); + } + } + + private boolean isConsumerPublic(ExternalImplicitGroup externalImplicitGroup) { + return externalImplicitGroup != null && externalImplicitGroup == ExternalImplicitGroup.ConsumerEpg; + } + + private boolean isProviderPublic(ExternalImplicitGroup externalImplicitGroup) { + return externalImplicitGroup != null && externalImplicitGroup == ExternalImplicitGroup.ProviderEpg; + } + + private List cloneAndGetEpgSubnets(EndpointGroupId epgId, TenantId tenantId) { + synchronized (this) { + List list1 = epgSubnetsMap.get(new Pair<>(epgId, tenantId)); + if (list1 == null) { + return new ArrayList<>(); + } + List list2 = new ArrayList<>(); + for (SubnetId id : list1) { + list2.add(new SubnetId(id)); + } + return list2; + } + } + + private void createLayer3LogicalNetwork(EndpointGroup consEpg, ContractId contractId, EndpointGroup provEpg, + TenantId gbpTenantId, ServiceCommunicationLayer comLayer, ExternalImplicitGroup externalImplicitGroup) { + LOG.trace("Start createLayer3LogicalNetwork: Consumer EPG {} Provider Epg {} Contract {}", consEpg.getId() + .getValue(), provEpg.getId().getValue(), contractId); + LogicalNetworkBuilder lNetbuilder = buildLayer2LogicalNetwork(consEpg, provEpg, gbpTenantId, null, + externalImplicitGroup); + if (lNetbuilder == null) { + LOG.error("Failed to create Logical Switchs layer on the Logical network"); + return; + } + Uuid privateSecRulesId = getFaasSecRulesId(contractId, gbpTenantId); + if (privateSecRulesId == null) { + LOG.error( + "Couldn't Create Logical Network because unable to find FAAS Security Rules Id based on GBP Contract {}", + contractId); + return; + } + + Uuid faasTenantId = getFaasTenantId(gbpTenantId); + LogicalRouterBuilder consLR = initLogicalRouterBuilder(consEpg, faasTenantId, + isConsumerPublic(externalImplicitGroup)); + LogicalRouterBuilder provLR = initLogicalRouterBuilder(provEpg, faasTenantId, + isProviderPublic(externalImplicitGroup)); + + if (!UlnDatastoreApi.attachAndSubmitToDs(consLR, provLR, new Pair(null, privateSecRulesId), null)) { + LOG.error("Failed to join Logical Routers in a Logical Network"); + return; + } + + if (!UlnDatastoreApi.attachAndSubmitToDs(consLR.getUuid(), lNetbuilder.getConsumerNetwork() + .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType))) { + LOG.error("Failed to join Consumer Logical Router to Logical Switch in a Logical Network"); + return; + } + LOG.debug("Attached Consumer Router {} to Consumer Switch {}", consLR.getUuid().getValue(), + lNetbuilder.getConsumerNetwork().getLogicalSwitchId().getValue()); + if (!UlnDatastoreApi.attachAndSubmitToDs(provLR.getUuid(), lNetbuilder.getProviderNetwork() + .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType))) { + LOG.error("Failed to join Provider Logical Router to Logical Switch in a Logical Network"); + return; + } + LOG.debug("Attached Provider Router {} to Provider Switch {}", provLR.getUuid().getValue(), + lNetbuilder.getProviderNetwork().getLogicalSwitchId().getValue()); + ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder(lNetbuilder.getConsumerNetwork()); + cNetBuilder.setLogicalRouterId(consLR.getUuid()); + lNetbuilder.setConsumerNetwork(cNetBuilder.build()); + ProviderNetworkBuilder pNetBuilder = new ProviderNetworkBuilder(lNetbuilder.getProviderNetwork()); + pNetBuilder.setLogicalRouterId(provLR.getUuid()); + lNetbuilder.setProviderNetwork(pNetBuilder.build()); + lNetbuilder.setContractId(contractId); + lNetbuilder.setContractTenantId(gbpTenantId); + LogicalNetwork result = lNetbuilder.build(); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + InstanceIdentifier iid = FaasIidFactory.logicalNetworkIid( + consEpg.getId(), gbpTenantId, contractId, provEpg.getId(), gbpTenantId); + wTx.put(LogicalDatastoreType.OPERATIONAL, iid, result); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Logical Network {}", result); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Logical Network {}", result); + } + LOG.debug("Created Layer 3 Logical network consEpg {}, contractId {}, provEpg {}", consEpg.getId().getValue(), + contractId.getValue(), provEpg.getId().getValue()); + } + + private void createLayer2LogicalNetwork(EndpointGroup consEpg, ContractId contractId, EndpointGroup provEpg, + TenantId gbpTenantId, ServiceCommunicationLayer comLayer, ExternalImplicitGroup externalImplicitGroup) { + LOG.trace("Start createLayer2LogicalNetwork: Consumer EPG {} Provider Epg {} Contract {}", consEpg.getId() + .getValue(), provEpg.getId().getValue(), contractId); + Uuid secRulesId = getFaasSecRulesId(contractId, gbpTenantId); + if (secRulesId == null) { + LOG.error( + "Couldn't Create Logical Network because unable to find FAAS Security Rules Id based on GBP Contract {}", + contractId); + return; + } + LogicalNetworkBuilder lNetbuilder = buildLayer2LogicalNetwork(consEpg, provEpg, gbpTenantId, secRulesId, + externalImplicitGroup); + if (lNetbuilder == null) { + LOG.error("Failed to create Logical Switchs layer on the Logical network"); + return; + } + + if (isConsumerPublic(externalImplicitGroup)) { + Uuid faasTenantId = getFaasTenantId(gbpTenantId); + LogicalRouterBuilder consLR = initLogicalRouterBuilder(consEpg, faasTenantId, true); + UlnDatastoreApi.submitLogicalRouterToDs(consLR.build()); + ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder(lNetbuilder.getConsumerNetwork()); + cNetBuilder.setLogicalRouterId(consLR.getUuid()); + lNetbuilder.setConsumerNetwork(cNetBuilder.build()); + if (!UlnDatastoreApi.attachAndSubmitToDs(consLR.getUuid(), lNetbuilder.getConsumerNetwork() + .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType), + null, null)) { + LOG.error("Failed to join Consumer Public Logical Router to Logical Switch in a Logical Network"); + } + LOG.debug("Attached Consumer Public Router {} to Consumer Switch {}", consLR.getUuid().getValue(), + lNetbuilder.getConsumerNetwork().getLogicalSwitchId().getValue()); + } + if (isProviderPublic(externalImplicitGroup)) { + Uuid faasTenantId = getFaasTenantId(gbpTenantId); + LogicalRouterBuilder provLR = initLogicalRouterBuilder(provEpg, faasTenantId, true); + provLR.setPublic(true); + UlnDatastoreApi.submitLogicalRouterToDs(provLR.build()); + ProviderNetworkBuilder cNetBuilder = new ProviderNetworkBuilder(lNetbuilder.getProviderNetwork()); + cNetBuilder.setLogicalRouterId(provLR.getUuid()); + lNetbuilder.setProviderNetwork(cNetBuilder.build()); + if (!UlnDatastoreApi.attachAndSubmitToDs(provLR.getUuid(), lNetbuilder.getProviderNetwork() + .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType), + null, null)) { + LOG.error("Failed to join Provider Public Logical Router to Logical Switch in a Logical Network"); + } + LOG.debug("Attached Provider Public Router {} to Provider Switch {}", provLR.getUuid().getValue(), + lNetbuilder.getProviderNetwork().getLogicalSwitchId().getValue()); + } + + lNetbuilder.setContractId(contractId); + lNetbuilder.setContractTenantId(gbpTenantId); + LogicalNetwork result = lNetbuilder.build(); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + InstanceIdentifier iid = FaasIidFactory.logicalNetworkIid( + consEpg.getId(), gbpTenantId, contractId, provEpg.getId(), gbpTenantId); + wTx.put(LogicalDatastoreType.OPERATIONAL, iid, result); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Logical Network {}", result); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Logical Network {}", result); + } + LOG.debug("Created Layer 2 Logical network consEpg {}, contractId {}, provEpg {}", consEpg.getId().getValue(), + contractId.getValue(), provEpg.getId().getValue()); + } + + private LogicalNetworkBuilder buildLayer2LogicalNetwork(EndpointGroup consEpg, EndpointGroup provEpg, + TenantId gbpTenantId, Uuid layer2SecRulesId, ExternalImplicitGroup externalImplicitGroup) { + LOG.trace("Start buildLayer2LogicalNetwork: Consumer EPG {} Provider Epg {}", consEpg.getId().getValue(), + provEpg.getId().getValue()); + List consSubnetIds = cloneAndGetEpgSubnets(consEpg.getId(), gbpTenantId); + List consFaasSubnetIds = new ArrayList<>(); + for (SubnetId subnetId : consSubnetIds) { + Uuid id = getFaasSubnetId(subnetId, gbpTenantId); + if (id != null) { + LOG.trace("Added to Consumer Network Faas Subnet {}", id.getValue()); + consFaasSubnetIds.add(id); + } + } + if (consFaasSubnetIds.isEmpty()) { + LOG.error("Couldn't find Faas subnets based on EPG {} -- Unable to create Layer2 Logical Network", + consEpg.getId().getValue()); + return null; + } + List provSubnetIds = cloneAndGetEpgSubnets(provEpg.getId(), gbpTenantId); + List provFaasSubnetIds = new ArrayList<>(); + for (SubnetId subnetId : provSubnetIds) { + Uuid id = getFaasSubnetId(subnetId, gbpTenantId); + if (id != null) { + LOG.trace("Added to Provider Network Faas Subnet {}", id.getValue()); + provFaasSubnetIds.add(id); + } + } + if (provFaasSubnetIds.isEmpty()) { + LOG.error("Couldn't find Faas subnets based on EPG {} -- Unable to create Layer2 Logical Network", + provEpg.getId().getValue()); + return null; + } + Uuid faasTenantId = getFaasTenantId(gbpTenantId); + LogicalSwitchBuilder consLS = initLogicalSwitchBuilder(consEpg, faasTenantId); + LogicalSwitchBuilder provLS = initLogicalSwitchBuilder(provEpg, faasTenantId); + if (layer2SecRulesId != null) { + if (!UlnDatastoreApi.attachAndSubmitToDs(consLS, provLS, new Pair(null, layer2SecRulesId))) { + LOG.error("Failed to join Logical Switches in a Logical Network"); + return null; + } + } else { + UlnDatastoreApi.submitLogicalSwitchToDs(consLS.build()); + UlnDatastoreApi.submitLogicalSwitchToDs(provLS.build()); + } + for (Uuid subnetId : consFaasSubnetIds) { + if (!UlnDatastoreApi.attachAndSubmitToDs(consLS.getUuid(), subnetId, consLS.getTenantId(), new Pair<>( + LocationType.SwitchType, LocationType.SubnetType))) { + LOG.error("Failed to join Consumer Logical Switch with Subnet {} in a Logical Network", subnetId); + return null; + } + LOG.debug("Attached Consumer Switch {} to Subnet {}", consLS.getUuid().getValue(), subnetId.getValue()); + } + for (Uuid subnetId : provFaasSubnetIds) { + if (!UlnDatastoreApi.attachAndSubmitToDs(provLS.getUuid(), subnetId, provLS.getTenantId(), new Pair<>( + LocationType.SwitchType, LocationType.SubnetType))) { + LOG.error("Failed to join Provider Logical Switch with Subnet {} in a Logical Network", subnetId); + return null; + } + LOG.debug("Attached Provider Switch {} to Subnet {}", provLS.getUuid().getValue(), subnetId.getValue()); + } + LogicalNetworkBuilder lNetbuilder = new LogicalNetworkBuilder(); + lNetbuilder.setConsumerEpgId(consEpg.getId()); + lNetbuilder.setConsumerTenantId(gbpTenantId); + lNetbuilder.setContractTenantId(gbpTenantId); + lNetbuilder.setProviderEpgId(provEpg.getId()); + lNetbuilder.setProviderTenantId(gbpTenantId); + ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder(); + cNetBuilder.setLogicalSwitchId(consLS.getUuid()); + cNetBuilder.setGbpSubnetId(consSubnetIds); + if (isConsumerPublic(externalImplicitGroup)) { + cNetBuilder.setNetworkScopeType(ScopeType.Public); + } else { + cNetBuilder.setNetworkScopeType(ScopeType.Private); + } + lNetbuilder.setConsumerNetwork(cNetBuilder.build()); + ProviderNetworkBuilder pNetBuilder = new ProviderNetworkBuilder(); + pNetBuilder.setLogicalSwitchId(provLS.getUuid()); + pNetBuilder.setGbpSubnetId(provSubnetIds); + if (isProviderPublic(externalImplicitGroup)) { + pNetBuilder.setNetworkScopeType(ScopeType.Public); + } else { + pNetBuilder.setNetworkScopeType(ScopeType.Private); + } + lNetbuilder.setProviderNetwork(pNetBuilder.build()); + + return lNetbuilder; + + } + + private Uuid getFaasSubnetId(SubnetId subnetId, TenantId gbpTenantId) { + if (subnetId != null) { + Optional mSubnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedSubnetIid(gbpTenantId, subnetId), + dataProvider.newReadOnlyTransaction()); + if (mSubnetOp.isPresent()) { + return mSubnetOp.get().getFaasSubnetId(); + } + } + return null; + } + + private Uuid getFaasSecRulesId(ContractId contractId, TenantId gbpTenantId) { + if (contractId != null) { + Optional mContractOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedContractIid(gbpTenantId, contractId), + dataProvider.newReadOnlyTransaction()); + if (mContractOp.isPresent()) { + return mContractOp.get().getFaasSecurityRulesId(); + } + } + return null; + } + + private LogicalRouterBuilder initLogicalRouterBuilder(EndpointGroup epg, Uuid tenantId, boolean isPublic) { + LogicalRouterBuilder builder = new LogicalRouterBuilder(); + builder.setAdminStateUp(true); + builder.setName(new Text(epg.getId().getValue())); + if (epg.getDescription() != null) + builder.setDescription(new Text("gbp-epg: " + epg.getDescription().getValue())); + else + builder.setDescription(new Text("gbp-epg")); + builder.setPublic(isPublic); + builder.setTenantId(tenantId); + builder.setUuid(new Uuid(UUID.randomUUID().toString())); + return builder; + } + + private LogicalSwitchBuilder initLogicalSwitchBuilder(EndpointGroup epg, Uuid tenantId) { + LogicalSwitchBuilder builder = new LogicalSwitchBuilder(); + builder.setAdminStateUp(true); + builder.setName(new Text(epg.getId().getValue())); + if (epg.getDescription() != null) + builder.setDescription(new Text("gbp-epg: " + epg.getDescription().getValue())); + else + builder.setDescription(new Text("gbp-epg")); + builder.setTenantId(tenantId); + builder.setUuid(new Uuid(UUID.randomUUID().toString())); + return builder; + } + + private boolean needToCreateLogicalNetwork(ServiceCommunicationLayer comLayer, List consSubnetIds, + List provSubnetIds, TenantId tenantId, ContractId contractId, EndpointGroup providerEpg, + EndpointGroup consumerEpg, ExternalImplicitGroup externalImplicitGroup) { + Optional lnOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.logicalNetworkIid(consumerEpg.getId(), tenantId, contractId, + providerEpg.getId(), tenantId), dataProvider.newReadOnlyTransaction()); + if (!lnOp.isPresent()) { + return true; + } + LogicalNetwork logicalNet = lnOp.get(); + if (!comLayer.equals(logicalNet.getCommunicationLayer())) { + return true; + } + + boolean isConsPublic = logicalNet.getConsumerNetwork().getNetworkScopeType() != null + && logicalNet.getConsumerNetwork().getNetworkScopeType() == ScopeType.Public; + if (isConsumerPublic(externalImplicitGroup) != isConsPublic) { + return true; + } + boolean isProvPublic = logicalNet.getProviderNetwork().getNetworkScopeType() != null + && logicalNet.getProviderNetwork().getNetworkScopeType() == ScopeType.Public; + if (isProviderPublic(externalImplicitGroup) != isProvPublic) { + return true; + } + Set lnConsSubnets = new HashSet<>(logicalNet.getConsumerNetwork().getGbpSubnetId()); + if (lnConsSubnets.size() != consSubnetIds.size() || !lnConsSubnets.containsAll(consSubnetIds)) { + return true; + } + Set lnProvSubnets = new HashSet<>(logicalNet.getProviderNetwork().getGbpSubnetId()); + if (lnProvSubnets.size() != provSubnetIds.size() || !lnProvSubnets.containsAll(provSubnetIds)) { + return true; + } + return false; + } + + private ServiceCommunicationLayer findLayerNetwork(TenantId tenantId, List consSubnetIds, + List provSubnetIds) { + Subnet consSubnet = null; + Subnet provSubnet = null; + ContextId contextId = null; + for (SubnetId subnetId : consSubnetIds) { + consSubnet = readSubnet(subnetId, tenantId); + if (consSubnet == null) { + LOG.error("Couldn't find subnet {} in datastore", subnetId); + return null; + } + if (consSubnet.getParent() == null) { + LOG.error("Flood domain is set to NULL in subnet " + consSubnet.getId()); + return null; + } + if (contextId == null) { + contextId = consSubnet.getParent(); + } else if (!contextId.equals(consSubnet.getParent())) { + LOG.error("Flood domain is not the same for all Network domains in the Consumer EPG "); + return null; + } + } + + contextId = null; + for (SubnetId subnetId : provSubnetIds) { + provSubnet = readSubnet(subnetId, tenantId); + if (provSubnet == null) { + LOG.error("Couldn't find subnet {} in datastore", subnetId); + return null; + } + if (provSubnet.getParent() == null) { + LOG.error("Flood domain is set to NULL in subnet " + provSubnet.getId()); + return null; + } + if (contextId == null) { + contextId = provSubnet.getParent(); + } else if (!contextId.equals(provSubnet.getParent())) { + LOG.error("Flood domain is not the same for all Network domains in the Provider EPG "); + return null; + } + } + + if (consSubnet == null || provSubnet == null) { + LOG.error("Couldn't find Consumer and/or Provider subnets"); + return null; + } + + L2FloodDomainId consL2FldId = new L2FloodDomainId(consSubnet.getParent().getValue()); + L2FloodDomain consFloodDomain = readL2FloodDomain(consL2FldId, tenantId); + if (consFloodDomain == null) { + LOG.error("Couldn't find flood domain instance in datastore with id " + consL2FldId); + return null; + } + L2FloodDomainId provL2FldId = new L2FloodDomainId(provSubnet.getParent().getValue()); + L2FloodDomain provFloodDomain = readL2FloodDomain(provL2FldId, tenantId); + if (provFloodDomain == null) { + LOG.error("Couldn't find flood domain instance in datastore with id " + provL2FldId); + return null; + } + + if (consFloodDomain.equals(provFloodDomain)) { + return ServiceCommunicationLayer.Layer2; + } + + if (consFloodDomain.getParent() == null) { + LOG.error("Bridge domain is set to NULL in flood domain " + consFloodDomain.getId()); + return null; + } + if (provFloodDomain.getParent() == null) { + LOG.error("Bridge domain is set to NULL in flood domain " + provFloodDomain.getId()); + return null; + } + + L2BridgeDomain consBridgeDomain = readL2BridgeDomainInstance(tenantId, consFloodDomain.getParent()); + if (consBridgeDomain == null) { + LOG.error("Couldn't find bridge domain instance in datastore with id " + consFloodDomain.getParent()); + return null; + } + L2BridgeDomain provBridgeDomain = readL2BridgeDomainInstance(tenantId, provFloodDomain.getParent()); + if (provBridgeDomain == null) { + LOG.error("Couldn't find bridge domain instance in datastore with id " + provFloodDomain.getParent()); + return null; + } + if (consBridgeDomain.equals(provBridgeDomain)) { + return ServiceCommunicationLayer.Layer2; + } + + L3Context consL3ContextDomain = readL3ContextInstance(tenantId, consBridgeDomain.getParent()); + if (consL3ContextDomain == null) { + LOG.error("Couldn't find L3 context instance in datastore with id " + consBridgeDomain.getParent()); + return null; + } + L3Context provL3ContextDomain = readL3ContextInstance(tenantId, provBridgeDomain.getParent()); + if (provL3ContextDomain == null) { + LOG.error("Couldn't find L3 context instance in datastore with id " + provBridgeDomain.getParent()); + return null; + } + if (consL3ContextDomain.equals(provL3ContextDomain)) { + return ServiceCommunicationLayer.Layer3; + } + return null; + } + + private L3Context readL3ContextInstance(TenantId tenantId, L3ContextId l3cId) { + ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier iid = IidFactory.l3ContextIid(tenantId, l3cId); + Optional l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx); + if (!l2Op.isPresent()) { + LOG.error("Couldn't find L3 Context Domain {} which belongs to Tenant {}", l3cId, tenantId); + rTx.close(); + return null; + } + return l2Op.get(); + } + + private L2BridgeDomain readL2BridgeDomainInstance(TenantId tenantId, L2BridgeDomainId l2bId) { + ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier iid = IidFactory.l2BridgeDomainIid(tenantId, l2bId); + Optional l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx); + if (!l2Op.isPresent()) { + LOG.error("Couldn't find L2 Brdge Domain {} which belongs to Tenant {}", l2bId, tenantId); + rTx.close(); + return null; + } + return l2Op.get(); + } + + private L2FloodDomain readL2FloodDomain(L2FloodDomainId l2fId, TenantId tenantId) { + ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier iid = IidFactory.l2FloodDomainIid(tenantId, l2fId); + Optional l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx); + if (!l2Op.isPresent()) { + LOG.error("Couldn't find L2 Flood Domain {} which belongs to Tenant {}", l2fId, tenantId); + rTx.close(); + return null; + } + return l2Op.get(); + } + + public Subnet readSubnet(SubnetId subnetId, TenantId tenantId) { + ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier iid = IidFactory.subnetIid(tenantId, subnetId); + Optional subnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx); + if (!subnetOp.isPresent()) { + LOG.warn("Couldn't find Subnet {} which belongs to Tenant {}", subnetId, tenantId); + rTx.close(); + return null; + } + return subnetOp.get(); + } + + public EndpointGroup readEndpointGroup(EndpointGroupId epgId, TenantId tenantId) { + ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction(); + InstanceIdentifier iid = IidFactory.endpointGroupIid(tenantId, epgId); + Optional epgOp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx); + if (!epgOp.isPresent()) { + LOG.warn("Couldn't find EPG {} which belongs to Tenant {}", epgId, tenantId); + rTx.close(); + return null; + } + return epgOp.get(); + } + + private ContractId getContractId(ResolvedPolicy policy) { + for (PolicyRuleGroupWithEndpointConstraints prgwec : policy.getPolicyRuleGroupWithEndpointConstraints()) { + for (PolicyRuleGroup prg : prgwec.getPolicyRuleGroup()) { + return prg.getContractId(); + } + } + return null; + } + + public void removeTenantLogicalNetwork(TenantId gbpTenantId, Uuid faasTenantId) { + removeTenantLogicalNetwork(gbpTenantId, faasTenantId, true); + } + + private void removeTenantLogicalNetwork(TenantId gbpTenantId, Uuid faasTenantId, boolean unregister) { + UlnDatastoreApi.removeTenantFromDsIfExists(faasTenantId); + synchronized (this) { + mappedTenants.remove(gbpTenantId); + Optional op3 = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.logicalNetworksIid(), dataProvider.newReadOnlyTransaction()); + if (op3.isPresent()) { + LogicalNetworks logicalNetworks = op3.get(); + for (LogicalNetwork ln : logicalNetworks.getLogicalNetwork()) { + if (ln.getConsumerTenantId().equals(gbpTenantId) || ln.getProviderTenantId().equals(gbpTenantId)) { + removeLogicalNetwork(ln.getConsumerEpgId(), ln.getConsumerTenantId(), ln.getContractId(), + ln.getProviderEpgId(), ln.getProviderTenantId()); + } + } + } + boolean toSubmit = false; + ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); + Optional op1 = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedEntityIid(gbpTenantId), rwTx); + if (op1.isPresent()) { + toSubmit = true; + } + Optional op2 = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedTenantIid(gbpTenantId), rwTx); + if (op2.isPresent()) { + toSubmit = true; + } + if (toSubmit) { + DataStoreHelper.submitToDs(rwTx); + } + + if (unregister) { + unregisterTenant(gbpTenantId); + } + } + } +} diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasRenderer.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasRenderer.java index 3e1807e0c..694ab7c48 100644 --- a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasRenderer.java +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasRenderer.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. - * + * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html @@ -12,8 +12,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.NotificationService; -import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,21 +24,17 @@ public class FaasRenderer implements AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(FaasRenderer.class); - private final DataBroker dataBroker; private final ScheduledExecutorService executor; - private final FaasEndpointManagerListener endpointListner; + private final FaasPolicyManager policyManager; + private final FaasEndpointAug faasEndpointAug; - public FaasRenderer(final DataBroker dataProvider, RpcProviderRegistry rpcRegistry, - NotificationService notificationService) { - super(); - this.dataBroker = dataProvider; - + public FaasRenderer(final DataBroker dataProvider, EpRendererAugmentationRegistry epRendererAugmentationRegistry) { int numCPU = Runtime.getRuntime().availableProcessors(); executor = Executors.newScheduledThreadPool(numCPU * 2); - - endpointListner = new FaasEndpointManagerListener(dataProvider); - + policyManager = new FaasPolicyManager(dataProvider, executor); + endpointListner = new FaasEndpointManagerListener(policyManager, dataProvider, executor); + faasEndpointAug = new FaasEndpointAug(epRendererAugmentationRegistry); LOG.info("FAAS Renderer has Started"); } @@ -47,6 +42,7 @@ public class FaasRenderer implements AutoCloseable { public void close() throws Exception { executor.shutdownNow(); endpointListner.close(); + policyManager.close(); + faasEndpointAug.close(); } - } diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasSubnetManagerListener.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasSubnetManagerListener.java new file mode 100644 index 000000000..75f14e3c5 --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasSubnetManagerListener.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi; +import org.opendaylight.groupbasedpolicy.util.DataStoreHelper; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.subnets.rev151013.subnets.container.subnets.SubnetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.subnets.rev151013.subnets.container.subnets.subnet.ExternalGateways; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.subnets.rev151013.subnets.container.subnets.subnet.ExternalGatewaysBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.subnet.Gateways; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.subnet.gateways.Prefixes; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +public class FaasSubnetManagerListener implements DataChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(FaasSubnetManagerListener.class); + private ConcurrentHashMap mappedSubnets = new ConcurrentHashMap<>(); + private final ScheduledExecutorService executor; + private final DataBroker dataProvider; + private final TenantId gbpTenantId; + private final Uuid faasTenantId; + + public FaasSubnetManagerListener(DataBroker dataProvider, TenantId gbpTenantId, Uuid faasTenantId, + ScheduledExecutorService executor) { + this.executor = executor; + this.faasTenantId = faasTenantId; + this.gbpTenantId = gbpTenantId; + this.dataProvider = dataProvider; + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + executor.execute(new Runnable() { + + public void run() { + executeEvent(change); + } + }); + } + + private void executeEvent(final AsyncDataChangeEvent, DataObject> change) { + // Create + for (DataObject dao : change.getCreatedData().values()) { + if (dao instanceof Subnet) { + Subnet subnet = (Subnet) dao; + LOG.debug("Subnet {} is Created.", subnet.getId().getValue()); + UlnDatastoreApi.submitSubnetToDs(initSubnetBuilder(subnet).build()); + } + } + // Update + Map, DataObject> dao = change.getUpdatedData(); + for (Map.Entry, DataObject> entry : dao.entrySet()) { + if (entry.getValue() instanceof Subnet) { + Subnet subnet = (Subnet) dao; + LOG.debug("Subnet {} is Updated.", subnet.getId().getValue()); + UlnDatastoreApi.submitSubnetToDs(initSubnetBuilder(subnet).build()); + } + } + // Remove + for (InstanceIdentifier iid : change.getRemovedPaths()) { + DataObject old = change.getOriginalData().get(iid); + if (old == null) { + continue; + } + if (old instanceof Subnet) { + Subnet subnet = (Subnet) old; + ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); + Optional op = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedSubnetIid(gbpTenantId, subnet.getId()), rwTx); + if (op.isPresent()) { + DataStoreHelper.submitToDs(rwTx); + } + Uuid faasSubnetId = mappedSubnets.remove(subnet.getId()); + if (faasSubnetId != null) { + UlnDatastoreApi.removeSubnetFromDsIfExists(faasTenantId, faasSubnetId); + } + } + } + } + + public void loadAll(List subnets, List mpSubnets) { + if (mpSubnets != null) { + for (MappedSubnet mpSubnet : mpSubnets) { + mappedSubnets.putIfAbsent(mpSubnet.getGbpSubnetId(), mpSubnet.getFaasSubnetId()); + } + } + if (subnets != null) { + for (Subnet subnet : subnets) { + LOG.debug("Loading Subnet {}", subnet.getId().getValue()); + UlnDatastoreApi.submitSubnetToDs(initSubnetBuilder(subnet).build()); + } + } + } + + private SubnetBuilder initSubnetBuilder(Subnet gbpSubnet) { + SubnetBuilder builder = new SubnetBuilder(); + if (gbpSubnet.getGateways() != null) { + List gateways = new ArrayList<>(); + for (Gateways gw : gbpSubnet.getGateways()) { + ExternalGatewaysBuilder eb = new ExternalGatewaysBuilder(); + eb.setExternalGateway(gw.getGateway()); + if (gw.getPrefixes() != null) { + List ipPrefixes = new ArrayList<>(); + for (Prefixes px : gw.getPrefixes()) { + ipPrefixes.add(px.getPrefix()); + } + eb.setPrefixes(ipPrefixes); + } + gateways.add(eb.build()); + } + builder.setExternalGateways(gateways); + } + + builder.setIpPrefix(gbpSubnet.getIpPrefix()); + builder.setUuid(getFaasSubnetId(gbpSubnet.getId())); + builder.setName(new Text(gbpSubnet.getId().getValue())); + if (gbpSubnet.getDescription() != null) + builder.setDescription(new Text("gbp-subnet: " + gbpSubnet.getDescription().getValue())); + else + builder.setDescription(new Text("gbp-subnet")); + builder.setTenantId(faasTenantId); + builder.setVirtualRouterIp(gbpSubnet.getVirtualRouterIp()); + // TODO DNS servers + builder.setDnsNameservers(null); + // TODO DHCP server + builder.setEnableDhcp(false); + return builder; + } + + private Uuid getFaasSubnetId(SubnetId subnetId) { + Uuid val = mappedSubnets.get(subnetId); + if (val != null) { + return val; + } + Uuid faasSubnetId = null; + if (FaasPolicyManager.isUUid(subnetId.getValue())) { + faasSubnetId = new Uuid(subnetId.getValue()); + } else { + faasSubnetId = new Uuid(UUID.randomUUID().toString()); + } + mappedSubnets.putIfAbsent(subnetId, faasSubnetId); + val = mappedSubnets.get(subnetId); + MappedSubnetBuilder builder = new MappedSubnetBuilder(); + builder.setFaasSubnetId(val); + builder.setGbpSubnetId(subnetId); + WriteTransaction wTx = dataProvider.newWriteOnlyTransaction(); + MappedSubnet result = builder.build(); + wTx.put(LogicalDatastoreType.OPERATIONAL, + FaasIidFactory.mappedSubnetIid(gbpTenantId, subnetId), result); + if (DataStoreHelper.submitToDs(wTx)) { + LOG.debug("Cached in Datastore Mapped Subnet {}", result); + } else { + LOG.error("Couldn't Cache in Datastore Mapped Subnet {}", result); + } + return val; + } + +} diff --git a/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasTenantManagerListener.java b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasTenantManagerListener.java new file mode 100644 index 000000000..c7a9179c4 --- /dev/null +++ b/renderers/faas/src/main/java/org/opendaylight/groupbasedpolicy/renderer/faas/FaasTenantManagerListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Huawei Technologies and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.groupbasedpolicy.renderer.faas; + +import java.util.concurrent.ScheduledExecutorService; + +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FaasTenantManagerListener implements DataChangeListener { + + private static final Logger LOG = LoggerFactory.getLogger(FaasTenantManagerListener.class); + private final ScheduledExecutorService executor; + private final TenantId gbpTenantId; + private final Uuid faasTenantId; + private final FaasPolicyManager policyManager; + + public FaasTenantManagerListener(FaasPolicyManager policyManager, TenantId gbpTenantId, Uuid faasTenantId, + ScheduledExecutorService executor) { + this.executor = executor; + this.faasTenantId = faasTenantId; + this.gbpTenantId = gbpTenantId; + this.policyManager = policyManager; + } + + @Override + public void onDataChanged(final AsyncDataChangeEvent, DataObject> change) { + executor.execute(new Runnable() { + + public void run() { + executeEvent(change); + } + }); + } + + private void executeEvent(final AsyncDataChangeEvent, DataObject> change) { + // Remove + for (InstanceIdentifier iid : change.getRemovedPaths()) { + DataObject old = change.getOriginalData().get(iid); + if (old == null) { + continue; + } + if (old instanceof Tenant) { + Tenant tenant = (Tenant) old; + if (tenant.getId().equals(gbpTenantId)) { + LOG.info("Removed gbp Tenant {} -- faas Tenant {}", gbpTenantId.getValue(), + faasTenantId.getValue()); + this.policyManager.removeTenantLogicalNetwork(gbpTenantId, faasTenantId); + } + } + } + } +} diff --git a/renderers/faas/src/main/yang/faas-endpoint.yang b/renderers/faas/src/main/yang/faas-endpoint.yang index 1ac4a231d..04b78fa18 100644 --- a/renderers/faas/src/main/yang/faas-endpoint.yang +++ b/renderers/faas/src/main/yang/faas-endpoint.yang @@ -12,44 +12,26 @@ module faas-endpoint { prefix "faas-endpoint"; import yang-ext { prefix ext; revision-date "2013-07-09"; } - import opendaylight-inventory { prefix inv; revision-date "2013-08-19"; } - import gbp-common { prefix gbp-common; } - import endpoint { prefix endpoint; } + import endpoint { prefix endpoint; revision-date 2014-04-21; } + import faas-common { prefix faas-common; revision-date 2015-10-13; } revision 2015-10-09 { description "Initial revision"; } - grouping switch-attach-location { - description - "The switch attachment for this endpoint"; - - leaf node-id { - description "The switch for this attached point"; - type inv:node-id; - } - - leaf node-connector-id { - description "The node connector that this point is attached to"; - type inv:node-connector-id; + grouping faas-port-ref { + leaf faas-port-ref-id { + description "faas port cross reference"; + type faas-common:uuid; } } - - grouping endpoint-ext-fields { - leaf subnet-id { - description "The subnet Id"; - type gbp-common:unique-id; - } - uses switch-attach-location; - } - augment "/endpoint:endpoints/endpoint:endpoint" { ext:augment-identifier "faas-endpoint-context"; - uses endpoint-ext-fields; + uses faas-port-ref; } augment "/endpoint:register-endpoint/endpoint:input" { ext:augment-identifier "faas-endpoint-context-input"; - uses endpoint-ext-fields; + uses faas-port-ref; } } diff --git a/renderers/faas/src/main/yang/faas-provider-impl.yang b/renderers/faas/src/main/yang/faas-provider-impl.yang index df5b2d08c..d41bf78c4 100644 --- a/renderers/faas/src/main/yang/faas-provider-impl.yang +++ b/renderers/faas/src/main/yang/faas-provider-impl.yang @@ -14,6 +14,7 @@ module faas-provider-impl { import config { prefix config; revision-date 2013-04-05; } import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28; } import opendaylight-sal-binding-broker-impl { prefix sal-broker; revision-date 2013-10-28; } + import groupbasedpolicy-cfg { prefix gbpcfg; revision-date 2015-11-06; } description "This module contains the base YANG definitions for faas-provider @@ -35,7 +36,7 @@ module faas-provider-impl { case faas-provider-impl { when "/config:modules/config:module/config:type = 'faas-provider-impl'"; - //wires in the data-broker service + //wires in the data-broker service container data-broker { uses config:service-ref { refine type { @@ -44,21 +45,12 @@ module faas-provider-impl { } } } - // RPC Registry - container rpc-registry { + // EpRendererAugmentationRegistry service + container ep-renderer-augmentation-registry { uses config:service-ref { refine type { mandatory true; - config:required-identity mdsal:binding-rpc-registry; - } - } - } - // Notification service - container notification-adapter { - uses config:service-ref { - refine type { - mandatory true; - config:required-identity sal-broker:binding-new-notification-service; + config:required-identity gbpcfg:ep-renderer-augmentation-registry; } } } diff --git a/renderers/faas/src/main/yang/faas.yang b/renderers/faas/src/main/yang/faas.yang index e8fcd48d2..0e786f600 100644 --- a/renderers/faas/src/main/yang/faas.yang +++ b/renderers/faas/src/main/yang/faas.yang @@ -12,9 +12,10 @@ module faas { namespace "urn:opendaylight:groupbasedpolicy:faas"; prefix "faas"; - import gbp-common { prefix gbp-common; } - import endpoint { prefix endpoint; } - import resolved-policy { prefix resolved-policy; } + import gbp-common { prefix gbp-common; revision-date 2014-04-21; } + import faas-common { prefix faas-common; revision-date 2015-10-13; } + import endpoint { prefix endpoint; revision-date 2014-04-21; } + import resolved-policy { prefix resolved-policy; revision-date 2015-08-28; } description "This module defines the group-based policy faas renderer model."; @@ -24,6 +25,29 @@ module faas { "Initial revision."; } + typedef scope-type { + type enumeration { + enum private { + description "private scope within a tenant domain"; + } + enum public { + description "public scope that is exposed outside the tenant domain such as the Internet"; + } + } + } + typedef service-communication-layer { + type enumeration { + enum layer-undefined { + description "Undefined layer"; + } + enum layer-2 { + description "layer 2"; + } + enum layer-3 { + description "layer 3"; + } + } + } grouping has-contract-key { leaf contract-tenant-id { description "Related tenant id"; @@ -36,45 +60,99 @@ module faas { } } - container mapped-service-profiles { - description "The list of mapped services"; + grouping has-logical-entity { + leaf logical-router-id { + type faas-common:uuid; + } + leaf logical-switch-id { + type faas-common:uuid; + } + leaf-list gbp-subnet-id { + type gbp-common:subnet-id; + } + } + + container logical-networks { + description "The mapped logical networks based on GBP resolved services"; config false; - list mapped-service-profile { - description "a service is an EPG-Contract-EPG"; + list logical-network { + description "Mapped logical network for an EPG-Contract-EPG service"; - key "consumer-epg-id contract-id provider-epg-id"; + key "consumer-epg-id contract-id provider-epg-id consumer-tenant-id provider-tenant-id"; uses resolved-policy:has-consumer-epg-key; uses has-contract-key; uses resolved-policy:has-provider-epg-key; - leaf faas-security-rules-groups { - description "Faas rules generated from GBP contract"; - type gbp-common:uuid; + leaf communication-layer { + description "logical network communication layer"; + type service-communication-layer; } - leaf-list faas-routers { - description "Faas logical routers"; - type gbp-common:uuid; + container consumer-network { + uses has-logical-entity; + leaf network-scope-type { + description "if public, it means the router has a public access port"; + default private; + type scope-type; + } } - leaf-list faas-switches { - description "Faas logical switches"; - type gbp-common:uuid; + container provider-network { + uses has-logical-entity; + leaf network-scope-type { + description "if public, it means the router has a public access port"; + default private; + type scope-type; + } } - leaf-list faas-ports { - description "Faas logical ports"; - type gbp-common:uuid; + } + } + + grouping tenant-pair-id { + leaf gbp-tenant-id { + type gbp-common:tenant-id; + } + leaf faas-tenant-id { + type faas-common:uuid; + } + } + container mapped-tenants-entities { + + config false; + + list mapped-tenant { + key "gbp-tenant-id"; + uses tenant-pair-id; + } + list mapped-entity { + key "gbp-tenant-id"; + leaf gbp-tenant-id { + type gbp-common:tenant-id; } - leaf-list faas-subnets { - description "Faas subnets"; - type gbp-common:uuid; + list mapped-contract { + key "gbp-contract-id"; + leaf gbp-contract-id { + type gbp-common:contract-id; + } + leaf faas-security-rules-id { + type faas-common:uuid; + } } - } - list mapped-endpoints { - uses endpoint:l2-key; - leaf-list faas-ports { - description "Faas logical ports"; - type gbp-common:uuid; + list mapped-subnet { + key "gbp-subnet-id"; + leaf gbp-subnet-id { + type gbp-common:subnet-id; + } + leaf faas-subnet-id { + type faas-common:uuid; + } + } + list mapped-endpoint { + key "l2-context mac-address"; + uses endpoint:l2-key; + leaf endpoint-location { + type faas-common:uuid; + } } } }