BUG-6858: adapt to ise api, wire harvestAll to template-provider
[groupbasedpolicy.git] / sxp-integration / sxp-ise-adapter / src / main / java / org / opendaylight / groupbasedpolicy / sxp_ise_adapter / impl / GbpIseConfigListenerImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.sxp_ise_adapter.impl;
10
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.ThreadFactoryBuilder;
16 import java.text.SimpleDateFormat;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.LinkedBlockingQueue;
22 import java.util.concurrent.ThreadPoolExecutor;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.GbpSxpIseAdapter;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseHarvestStatus;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseHarvestStatusBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseSourceConfig;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Purpose: listen for harvest configuration and trigger harvesting
43  */
44 public class GbpIseConfigListenerImpl implements GbpIseConfigListener {
45
46     private static final Logger LOG = LoggerFactory.getLogger(GbpIseConfigListenerImpl.class);
47
48     private static final String DATE_AND_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
49
50     private final DataBroker dataBroker;
51     private final GbpIseSgtHarvester gbpIseSgtHarvester;
52     @Nonnull private final EPPolicyTemplateProviderFacade templateProviderFacade;
53     private final ThreadPoolExecutor pool;
54
55     public GbpIseConfigListenerImpl(@Nonnull final DataBroker dataBroker, @Nonnull final GbpIseSgtHarvester gbpIseSgtHarvester,
56                                     @Nonnull final EPPolicyTemplateProviderFacade templateProviderFacade) {
57         this.dataBroker = dataBroker;
58         this.gbpIseSgtHarvester = gbpIseSgtHarvester;
59         this.templateProviderFacade = templateProviderFacade;
60         pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10),
61                 new ThreadFactoryBuilder().setNameFormat("ise-sgt-harverster-%d").build()) {
62             @Override
63             protected void afterExecute(final Runnable r, final Throwable t) {
64                 super.afterExecute(r, t);
65                 if (t != null) {
66                     LOG.warn("ise harvest task failed", t);
67                 }
68             }
69         };
70     }
71
72     @Override
73     public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<IseSourceConfig>> collection) {
74         for (DataTreeModification<IseSourceConfig> modification : collection) {
75             final IseSourceConfig iseSourceConfig = modification.getRootNode().getDataAfter();
76             final IseContext iseContext = new IseContext(iseSourceConfig);
77             templateProviderFacade.assignIseContext(iseContext);
78             if (iseSourceConfig != null) {
79                 pool.submit(() -> {
80                     final ListenableFuture<Collection<SgtInfo>> harvestResult = gbpIseSgtHarvester.harvestAll(iseContext);
81                     Futures.addCallback(harvestResult, new FutureCallback<Collection<SgtInfo>>() {
82                         @Override
83                         public void onSuccess(@Nullable final Collection<SgtInfo> result) {
84                             LOG.debug("ise harvest finished, outcome: {}", result);
85                             storeOutcome(true, Optional.ofNullable(result).map(Collection::size).orElse(0), null);
86                         }
87
88                         @Override
89                         public void onFailure(final Throwable t) {
90                             LOG.debug("ise harvest failed", t);
91                             storeOutcome(false, 0, t.getMessage());
92                         }
93                     });
94
95                     try {
96                         harvestResult.get(30, TimeUnit.SECONDS);
97                     } catch (InterruptedException | ExecutionException | TimeoutException e) {
98                         LOG.debug("failed to finish ise-sgt-harvest task properly on time", e);
99                     }
100                 });
101             }
102         }
103     }
104
105     private CheckedFuture<Void, TransactionCommitFailedException> storeOutcome(final boolean succeeded, final int counter, final String reason) {
106         final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
107         final InstanceIdentifier<IseHarvestStatus> harvestStatusPath = InstanceIdentifier.create(GbpSxpIseAdapter.class)
108                 .child(IseHarvestStatus.class);
109         final IseHarvestStatus harvestStatus = new IseHarvestStatusBuilder()
110                 .setReason(reason)
111                 .setSuccess(succeeded)
112                 .setTemplatesWritten(counter)
113                 .setTimestamp(createDateTime(new Date()))
114                 .build();
115         wTx.put(LogicalDatastoreType.OPERATIONAL, harvestStatusPath, harvestStatus, true);
116         return wTx.submit();
117     }
118
119     private static DateAndTime createDateTime(Date when) {
120         final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_AND_TIME_FORMAT);
121         return new DateAndTime(simpleDateFormat.format(when));
122     }
123
124     @Override
125     public void close() throws Exception {
126         if (!pool.isTerminated()) {
127             pool.shutdown();
128             final boolean terminated = pool.awaitTermination(10, TimeUnit.SECONDS);
129             if (! terminated) {
130                 pool.shutdownNow();
131             }
132         }
133     }
134 }