View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.security.visibility;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.UUID;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.hbase.Cell;
28  import org.apache.hadoop.hbase.Tag;
29  import org.apache.hadoop.hbase.TagRewriteCell;
30  import org.apache.hadoop.hbase.TagType;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
33  import org.apache.hadoop.hbase.replication.ReplicationEndpoint;
34  import org.apache.hadoop.hbase.replication.WALEntryFilter;
35  import org.apache.hadoop.hbase.wal.WAL.Entry;
36  
37  import com.google.common.util.concurrent.ListenableFuture;
38  
39  @InterfaceAudience.Private
40  public class VisibilityReplicationEndpoint implements ReplicationEndpoint {
41  
42    private static final Log LOG = LogFactory.getLog(VisibilityReplicationEndpoint.class);
43    private ReplicationEndpoint delegator;
44    private VisibilityLabelService visibilityLabelsService;
45  
46    public VisibilityReplicationEndpoint(ReplicationEndpoint endpoint,
47        VisibilityLabelService visibilityLabelsService) {
48      this.delegator = endpoint;
49      this.visibilityLabelsService = visibilityLabelsService;
50    }
51  
52    @Override
53    public void init(Context context) throws IOException {
54      delegator.init(context);
55    }
56  
57    @Override
58    public boolean replicate(ReplicateContext replicateContext) {
59      if (!delegator.canReplicateToSameCluster()) {
60        // Only when the replication is inter cluster replication we need to covert the visibility tags to
61        // string based tags.  But for intra cluster replication like region replicas it is not needed.
62        List<Entry> entries = replicateContext.getEntries();
63        List<Tag> visTags = new ArrayList<Tag>();
64        List<Tag> nonVisTags = new ArrayList<Tag>();
65        List<Entry> newEntries = new ArrayList<Entry>(entries.size());
66        for (Entry entry : entries) {
67          WALEdit newEdit = new WALEdit();
68          ArrayList<Cell> cells = entry.getEdit().getCells();
69          for (Cell cell : cells) {
70            if (cell.getTagsLength() > 0) {
71              visTags.clear();
72              nonVisTags.clear();
73              Byte serializationFormat = VisibilityUtils.extractAndPartitionTags(cell, visTags,
74                  nonVisTags);
75              if (!visTags.isEmpty()) {
76                try {
77                  byte[] modifiedVisExpression = visibilityLabelsService
78                      .encodeVisibilityForReplication(visTags, serializationFormat);
79                  if (modifiedVisExpression != null) {
80                    nonVisTags.add(new Tag(TagType.STRING_VIS_TAG_TYPE, modifiedVisExpression));
81                  }
82                } catch (Exception ioe) {
83                  LOG.error(
84                      "Exception while reading the visibility labels from the cell. The replication "
85                          + "would happen as per the existing format and not as string type for the cell "
86                          + cell + ".", ioe);
87                  // just return the old entries as it is without applying the string type change
88                  newEdit.add(cell);
89                  continue;
90                }
91                // Recreate the cell with the new tags and the existing tags
92                Cell newCell = new TagRewriteCell(cell, Tag.fromList(nonVisTags));
93                newEdit.add(newCell);
94              } else {
95                newEdit.add(cell);
96              }
97            } else {
98              newEdit.add(cell);
99            }
100         }
101         newEntries.add(new Entry(entry.getKey(), newEdit));
102       }
103       replicateContext.setEntries(newEntries);
104       return delegator.replicate(replicateContext);
105     } else {
106       return delegator.replicate(replicateContext);
107     }
108   }
109 
110   @Override
111   public synchronized UUID getPeerUUID() {
112     return delegator.getPeerUUID();
113   }
114 
115   @Override
116   public boolean canReplicateToSameCluster() {
117     return delegator.canReplicateToSameCluster();
118   }
119 
120   @Override
121   public WALEntryFilter getWALEntryfilter() {
122     return delegator.getWALEntryfilter();
123   }
124 
125   @Override
126   public boolean isRunning() {
127     return delegator.isRunning();
128   }
129 
130   @Override
131   public ListenableFuture<State> start() {
132     return delegator.start();
133   }
134 
135   @Override
136   public State startAndWait() {
137     return delegator.startAndWait();
138   }
139 
140   @Override
141   public State state() {
142     return delegator.state();
143   }
144 
145   @Override
146   public ListenableFuture<State> stop() {
147     return delegator.stop();
148   }
149 
150   @Override
151   public State stopAndWait() {
152     return delegator.stopAndWait();
153   }
154 
155 }