/* * Copyright (c) 2017 Baidu, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.elasticsearch.cluster.metadata; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.AbstractDiffable; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import com.google.common.collect.ImmutableMap; public class TenantMetadata extends AbstractDiffable<TenantMetadata> { public static TenantMetadata PROTO = builder().build(); public static final String TENANT_SETTING_PREFIX = "tenants"; private final ImmutableMap<Long, TenantProperty> tenantProperties; private final ImmutableMap<String, Long> nodeToTenant; private final ImmutableMap<String, Long> tenantNameToId; private long maxTenantId = 0; private TenantMetadata(ImmutableMap<Long, TenantProperty> tenantProperties, long maxTenantId) { this.tenantProperties = tenantProperties; Map<String, Long> nameToId = new HashMap<>(); for (Long id : this.tenantProperties.keySet()) { nameToId.put(this.tenantProperties.get(id).tenantName(), id); } this.tenantNameToId = ImmutableMap.copyOf(nameToId); Map<String, Long> tmpNodeToTenant = new HashMap<>(); for (Long id : this.tenantProperties.keySet()) { for (AllocatedNodeInfo node : this.tenantProperties.get(id).nodes().values()) { if (tmpNodeToTenant.containsKey(node)) { throw new IllegalStateException(""); } else { tmpNodeToTenant.put(node.getAllocatedNodeId(), id); } } } this.nodeToTenant = ImmutableMap.copyOf(tmpNodeToTenant); this.maxTenantId = maxTenantId; } public TenantProperty getTenantProperty(long tenantId) { if (tenantProperties.containsKey(tenantId)) { return tenantProperties.get(tenantId); } return null; } public TenantProperty getTenantPropertyForLoginUser(String loginUsername) { long tenantId = UserProperty.getTenantIdFromLoginUserName(loginUsername, this); return tenantProperties.get(tenantId); } public TenantProperty getNodeTenant(DiscoveryNode node) { AllocatedNodeInfo nodeGroupTag = AllocatedNodeInfo.getNodeGroupFromNode(node); Long tenantId = nodeToTenant.get(nodeGroupTag.getAllocatedNodeId()); if (tenantId == null) { return null; } return tenantProperties.get(tenantId); } public boolean isNodeAllocatedToTenant(DiscoveryNode node, Long tenantId) { AllocatedNodeInfo nodeInfo = AllocatedNodeInfo.getNodeGroupFromNode(node); Long nodeTenantId = nodeToTenant.get(nodeInfo.getAllocatedNodeId()); if (nodeTenantId == null || !nodeTenantId.equals(tenantId)) { return false; } TenantProperty tenantProperty = tenantProperties.get(nodeTenantId); AllocatedNodeInfo nodeInfoInTenant = tenantProperty.nodes().get(nodeInfo.getAllocatedNodeId()); if (nodeInfoInTenant != null && nodeInfoInTenant.getAllocatedNodeStatus().equals(AllocatedNodeStatus.DECOMMISSIONING)) { return false; } return true; } public TenantProperty getNodeTenant(AllocatedNodeInfo nodeGroupTag) { Long tenantId = nodeToTenant.get(nodeGroupTag.getAllocatedNodeId()); return tenantProperties.get(tenantId); } public boolean tenantExist(long tenantId) { if (tenantId == TenantProperty.ROOT_TENANT_ID) { return true; } return tenantProperties.containsKey(tenantId); } public boolean tenantExist(String tenantName) { return tenantNameToId.containsKey(tenantName); } public long tenantId(String tenantName) { if (!tenantNameToId.containsKey(tenantName)) { throw new ElasticsearchException("could not find tenant: " + tenantName); } return tenantNameToId.get(tenantName); } public long maxTenantId() { return maxTenantId; } public ImmutableMap<Long, TenantProperty> tenantProperties() { return tenantProperties; } public TenantProperty tenant(long tenantId) { if (!tenantProperties.containsKey(tenantId)) { throw new ElasticsearchException("could not find tenant with id: " + tenantId); } return tenantProperties.get(tenantId); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeInt(tenantProperties.size()); for (Long tenantId : tenantProperties.keySet()) { TenantProperty tenantProperty = tenantProperties.get(tenantId); tenantProperty.writeTo(out); } out.writeLong(maxTenantId); } @Override public TenantMetadata readFrom(StreamInput in) throws IOException { int tenantNum = in.readInt(); Builder builder = new Builder(); for (int tenantIndex = 0; tenantIndex < tenantNum; ++tenantIndex) { TenantProperty tenantProperty = TenantProperty.PROTO.readFrom(in); builder.addOrChangeTenantProperty(tenantProperty); } builder.maxTenantId(in.readLong()); return builder.build(); } public static Builder builder() { return new Builder(); } public static class Builder { private Map<Long, TenantProperty> tenantProperties; private long maxTenantId = 1; public Builder() { tenantProperties = new HashMap<Long, TenantProperty>(); } public Builder(TenantMetadata tenantMetadata) { maxTenantId = tenantMetadata.maxTenantId; tenantProperties = new HashMap<Long, TenantProperty>(); for (Long tenantId : tenantMetadata.tenantProperties.keySet()) { tenantProperties.put(tenantId, tenantMetadata.tenantProperties.get(tenantId)); } } public Builder addOrChangeTenantProperty(TenantProperty tenantProperty) { if (tenantProperty.tenantId() != TenantProperty.INVALID_TENANT_ID) { tenantProperties.put(tenantProperty.tenantId(), tenantProperty); } return this; } public Builder addOrChangeTenantProperty(TenantProperty.Builder tenantPropertyBuilder) { tenantProperties.put(tenantPropertyBuilder.tenantId(), tenantPropertyBuilder.build()); return this; } public TenantProperty getTenantProperty(long tenantId) { return tenantProperties.get(tenantId); } public boolean containsTenant(Long tenantId) { return tenantProperties.containsKey(tenantId); } public boolean deleteTenant(Long tenantId) { if (tenantProperties.containsKey(tenantId)) { tenantProperties.remove(tenantId); } return true; } public void maxTenantId(long id) { this.maxTenantId = id; } public long maxTenantId() { return this.maxTenantId; } public TenantMetadata build() { ImmutableMap<Long, TenantProperty> newProperties = ImmutableMap.copyOf(tenantProperties); return new TenantMetadata(newProperties, maxTenantId); } public static void toXContent(TenantMetadata tenantMetadata, XContentBuilder builder, ToXContent.Params params) throws IOException { builder.startObject("tenants"); builder.field("max_tenant_id", tenantMetadata.maxTenantId); builder.startObject("tenant_list"); for (Long tenantId : tenantMetadata.tenantProperties.keySet()) { TenantProperty.Builder.toXContent(tenantMetadata.tenantProperties.get(tenantId), builder, params); } builder.endObject(); builder.endObject(); } public static TenantMetadata fromXContent(XContentParser parser) throws IOException { Builder builder = new Builder(); XContentParser.Token token = parser.currentToken(); String currentFieldName = parser.currentName(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if ("tenant_list".equalsIgnoreCase(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { TenantProperty tenantProperty = TenantProperty.Builder.fromXContent(parser); builder.addOrChangeTenantProperty(tenantProperty); } } } } else if (token == XContentParser.Token.VALUE_NUMBER) { if ("max_tenant_id".equalsIgnoreCase(currentFieldName)) { builder.maxTenantId(parser.longValue()); } } } return builder.build(); } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (maxTenantId ^ (maxTenantId >>> 32)); result = prime * result + ((tenantProperties == null) ? 0 : tenantProperties.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TenantMetadata other = (TenantMetadata) obj; if (maxTenantId != other.maxTenantId) return false; if (tenantProperties == null) { if (other.tenantProperties != null) return false; } else if (!tenantProperties.equals(other.tenantProperties)) return false; return true; } }