com.aoindustries.aoserv.master.NetHostHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aoserv-master Show documentation
Show all versions of aoserv-master Show documentation
Master server for the AOServ Platform.
/*
* aoserv-master - Master server for the AOServ Platform.
* Copyright (C) 2001-2013, 2015, 2016, 2017, 2018, 2019, 2020 AO Industries, Inc.
* [email protected]
* 7262 Bull Pen Cir
* Mobile, AL 36695
*
* This file is part of aoserv-master.
*
* aoserv-master is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aoserv-master is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with aoserv-master. If not, see .
*/
package com.aoindustries.aoserv.master;
import com.aoindustries.aoserv.client.account.Account;
import com.aoindustries.aoserv.client.distribution.OperatingSystemVersion;
import com.aoindustries.aoserv.client.master.User;
import com.aoindustries.aoserv.client.master.UserHost;
import com.aoindustries.aoserv.client.schema.Table;
import com.aoindustries.collections.IntList;
import com.aoindustries.collections.LongArrayList;
import com.aoindustries.collections.LongList;
import com.aoindustries.collections.SortedIntArrayList;
import com.aoindustries.dbc.DatabaseAccess;
import com.aoindustries.dbc.DatabaseConnection;
import com.aoindustries.net.DomainName;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The ServerHandler
handles all the accesses to the Host tables.
*
* @author AO Industries, Inc.
*/
final public class NetHostHandler {
private static final Logger logger = Logger.getLogger(NetHostHandler.class.getName());
private NetHostHandler() {
}
private static Map> userHosts;
/*
public static int addBackupServer(
DatabaseConnection conn,
RequestSource source,
InvalidateList invalidateList,
String hostname,
String farm,
int owner,
String description,
int os_version,
String username,
String password,
String contact_phone,
String contact_email
) throws IOException, SQLException {
// Security and validity checks
String account=UsernameHandler.getAccountForUsername(conn, source.getUsername());
if(
!conn.executeBooleanQuery(Connection.TRANSACTION_READ_COMMITTED, true, true, "select can_add_backup_server from account.\"Account\" where accounting=?", account)
) throw new SQLException("Not allowed to add_backup_server: "+source.getUsername());
MasterServer.checkAccessHostname(conn, source, "addBackupServer", hostname);
String farm_owner=conn.executeStringQuery(
Connection.TRANSACTION_READ_COMMITTED,
true,
true,
"select\n"
+ " pk.accounting\n"
+ "from\n"
+ " infrastructure."ServerFarm" sf,\n"
+ " billing.\"Package\" pk\n"
+ "where\n"
+ " sf.name=?\n"
+ " and sf.owner=pk.id",
farm
);
if(!AccountHandler.isAccountOrParent(conn, account, farm_owner)) throw new SQLException("Not able to access farm: "+farm);
PackageHandler.checkAccessPackage(conn, source, "addBackupServer", owner);
String check = Username.checkUsername(username, Locale.getDefault());
if(check!=null) throw new SQLException(check);
PasswordChecker.Result[] results = Administrator.checkPassword(Locale.getDefault(), username, password);
if(PasswordChecker.hasResults(Locale.getDefault(), results)) throw new SQLException("Password strength check failed: "+PasswordChecker.getResultsString(results).replace('\n', '|'));
int host = conn.executeIntUpdate(
"INSERT INTO\n"
+ " net."Host"\n"
+ "VALUES (\n"
+ " default,\n"
+ " ?,\n"
+ " ?,\n"
+ " ?,\n"
+ " 'orion',\n"
+ " ?,\n"
+ " null,\n"
+ " ?,\n"
+ " null\n"
+ ") RETURNING id",
hostname,
farm,
PackageHandler.getAccountForPackage(conn, owner),
description,
os_version
);
invalidateList.addTable(conn, Table.TableID.SERVERS, account, InvalidateList.allServers, false);
// Build a stack of parents, adding each business_server
Stack bus=new Stack();
String packageAccount=PackageHandler.getAccountForPackage(conn, owner);
String currentAccount=packageAccount;
while(true) {
bus.push(currentAccount);
if(currentAccount.equals(AccountHandler.getRootAccount())) break;
currentAccount=AccountHandler.getParentAccount(conn, currentAccount);
}
while(!bus.isEmpty()) {
AccountHandler.addBusinessServer(conn, invalidateList, bus.pop(), host, true);
}
UsernameHandler.addUsername(conn, source, invalidateList, PackageHandler.getNameForPackage(conn, owner), username, false);
AccountHandler.addAdministrator(
conn,
source,
invalidateList,
username,
hostname+" backup",
null,
-1,
true,
contact_phone,
null,
null,
null,
contact_email,
null,
null,
null,
null,
null,
null
);
conn.executeUpdate("insert into master.\"User\" values(?,true,false,false,false,false,false,false)", username);
invalidateList.addTable(conn, Table.TableID.MASTER_USERS, packageAccount, InvalidateList.allServers, false);
conn.executeUpdate("insert into master.\"UserHost\"(username, server) values(?,?)", username, host);
invalidateList.addTable(conn, Table.TableID.MASTER_SERVERS, packageAccount, InvalidateList.allServers, false);
AccountHandler.setAdministratorPassword(conn, source, invalidateList, username, password);
return host;
}*/
/*public static void checkAccessServer(DatabaseConnection conn, RequestSource source, String action, String server) throws IOException, SQLException {
if(!canAccessServer(conn, source, server)) {
String message=
"currentAdministrator="
+source.getCurrentAdministrator()
+" is not allowed to access server: action='"
+action
+", hostname="
+server
;
UserHost.reportSecurityMessage(source, message);
throw new SQLException(message);
}
}*/
public static void checkAccessHost(DatabaseConnection conn, RequestSource source, String action, int host) throws IOException, SQLException {
if(!canAccessHost(conn, source, host)) {
String message=
"currentAdministrator="
+source.getCurrentAdministrator()
+" is not allowed to access server: action='"
+action
+", server.id="
+host
;
throw new SQLException(message);
}
}
/*
public static boolean canAccessServer(DatabaseConnection conn, RequestSource source, String server) throws IOException, SQLException {
return getAllowedServers(conn, source).contains(server);
}*/
public static boolean canAccessHost(DatabaseConnection conn, RequestSource source, int host) throws IOException, SQLException {
return getAllowedHosts(conn, source).contains(host);
}
/**
* Gets the servers that are allowed for the provided username.
*/
static List getAllowedHosts(DatabaseConnection conn, RequestSource source) throws IOException, SQLException {
synchronized(NetHostHandler.class) {
com.aoindustries.aoserv.client.account.User.Name currentAdministrator = source.getCurrentAdministrator();
if(userHosts==null) userHosts=new HashMap<>();
List SV=userHosts.get(currentAdministrator);
if(SV==null) {
SV=new SortedIntArrayList();
User mu = MasterServer.getUser(conn, currentAdministrator);
if(mu!=null) {
UserHost[] masterServers = MasterServer.getUserHosts(conn, currentAdministrator);
if(masterServers.length!=0) {
for(UserHost masterServer : masterServers) {
SV.add(masterServer.getServerPKey());
}
} else {
SV.addAll(conn.executeIntListQuery("select id from net.\"Host\""));
}
} else {
SV.addAll(
conn.executeIntListQuery(
"select\n"
+ " bs.server\n"
+ "from\n"
+ " account.\"User\" un,\n"
+ " billing.\"Package\" pk,\n"
+ " account.\"AccountHost\" bs\n"
+ "where\n"
+ " un.username=?\n"
+ " and un.package=pk.name\n"
+ " and pk.accounting=bs.accounting",
currentAdministrator
)
);
}
userHosts.put(currentAdministrator, SV);
}
return SV;
}
}
public static List getAccountsForHost(DatabaseConnection conn, int host) throws IOException, SQLException {
return conn.executeObjectCollectionQuery(new ArrayList<>(),
ObjectFactories.accountNameFactory,
"select accounting from account.\"AccountHost\" where server=?",
host
);
}
// TODO: Move to LinuxServerHandler
final private static Map failoverServers=new HashMap<>();
public static int getFailoverServer(DatabaseConnection conn, int linuxServer) throws IOException, SQLException {
synchronized(failoverServers) {
if(failoverServers.containsKey(linuxServer)) return failoverServers.get(linuxServer);
int failoverServer=conn.executeIntQuery(
"select\n"
+ " coalesce(\n"
+ " (\n"
+ " select\n"
+ " failover_server\n"
+ " from\n"
+ " linux.\"Server\"\n"
+ " where\n"
+ " server=?\n"
+ " ), -1\n"
+ " )",
linuxServer
);
failoverServers.put(linuxServer, failoverServer);
return failoverServer;
}
}
final private static Map farmForHosts = new HashMap<>();
public static String getFarmForHost(DatabaseConnection conn, int host) throws IOException, SQLException {
Integer I=host;
synchronized(farmForHosts) {
String farm=farmForHosts.get(I);
if(farm==null) {
farm=conn.executeStringQuery("select farm from net.\"Host\" where id=?", host);
farmForHosts.put(I, farm);
}
return farm;
}
}
// TODO: Move to LinuxServerHandler
final private static Map hostnamesForLinuxServers = new HashMap<>();
public static DomainName getHostnameForLinuxServer(DatabaseAccess database, int linuxServer) throws IOException, SQLException {
Integer mapKey = linuxServer;
synchronized(hostnamesForLinuxServers) {
DomainName hostname = hostnamesForLinuxServers.get(mapKey);
if(hostname == null) {
hostname = database.executeObjectQuery(
ObjectFactories.domainNameFactory,
"select hostname from linux.\"Server\" where server=?",
linuxServer
);
hostnamesForLinuxServers.put(mapKey, hostname.intern());
}
return hostname;
}
}
/**
* Gets the operating system version for a server or -1
if not available.
*/
public static int getOperatingSystemVersionForHost(DatabaseConnection conn, int host) throws IOException, SQLException {
return conn.executeIntQuery("select coalesce((select operating_system_version from net.\"Host\" where id=?), -1)", host);
}
// TODO: Move to LinuxServerHandler
final private static Map hostsForLinuxServerHostnames = new HashMap<>();
public static int getHostForLinuxServerHostname(DatabaseConnection conn, DomainName hostname) throws IOException, SQLException {
synchronized(hostsForLinuxServerHostnames) {
Integer I = hostsForLinuxServerHostnames.get(hostname);
int host;
if(I == null) {
host = conn.executeIntQuery("select server from linux.\"Server\" where hostname=?", hostname);
hostsForLinuxServerHostnames.put(hostname, host);
} else {
host = I;
}
return host;
}
}
public static int getHostForPackageAndName(DatabaseAccess database, int packageId, String name) throws IOException, SQLException {
return database.executeIntQuery("select id from net.\"Host\" where package=? and name=?", packageId, name);
}
public static IntList getHosts(DatabaseConnection conn) throws IOException, SQLException {
return conn.executeIntListQuery("select id from net.\"Host\"");
}
// TODO: Move to VirtualServerHandler
/**
* Gets all of the Xen physical servers.
*/
public static IntList getEnabledXenPhysicalServers(DatabaseAccess database) throws IOException, SQLException {
return database.executeIntListQuery(
"select se.id from net.\"Host\" se inner join infrastructure.\"PhysicalServer\" ps on se.id=ps.server where se.operating_system_version in (?,?,?) and se.monitoring_enabled",
OperatingSystemVersion.CENTOS_5_DOM0_I686,
OperatingSystemVersion.CENTOS_5_DOM0_X86_64,
OperatingSystemVersion.CENTOS_7_DOM0_X86_64
);
}
// TODO: Move to LinuxServerHandler
final private static Map linuxServers = new HashMap<>();
public static boolean isLinuxServer(DatabaseConnection conn, int host) throws IOException, SQLException {
Integer I = host;
synchronized(linuxServers) {
if(linuxServers.containsKey(I)) return linuxServers.get(I);
boolean isLinuxServer = conn.executeBooleanQuery(
"select (select server from linux.\"Server\" where server=?) is not null",
host
);
linuxServers.put(I, isLinuxServer);
return isLinuxServer;
}
}
public static void invalidateTable(Table.TableID tableID) {
if(tableID==Table.TableID.AO_SERVERS) {
synchronized(linuxServers) {
linuxServers.clear();
}
} else if(tableID==Table.TableID.BUSINESS_SERVERS) {
synchronized(NetHostHandler.class) {
userHosts=null;
}
} else if(tableID==Table.TableID.MASTER_SERVERS) {
synchronized(NetHostHandler.class) {
userHosts=null;
}
} else if(tableID==Table.TableID.SERVERS) {
synchronized(failoverServers) {
failoverServers.clear();
}
synchronized(farmForHosts) {
farmForHosts.clear();
}
synchronized(hostnamesForLinuxServers) {
hostnamesForLinuxServers.clear();
}
synchronized(hostsForLinuxServerHostnames) {
hostsForLinuxServerHostnames.clear();
}
} else if(tableID==Table.TableID.SERVER_FARMS) {
}
}
private static final Object invalidateSyncLock = new Object();
/**
* HashMap(server)->HashMap(Long(id))->RequestSource
*/
private static final Map> invalidateSyncEntries = new HashMap<>();
/**
* HashMap(Host)->Long(lastID)
*/
private static final Map lastIDs = new HashMap<>();
public static Long addInvalidateSyncEntry(int host, RequestSource source) {
Integer S=host;
synchronized(invalidateSyncLock) {
long id;
Long L=lastIDs.get(S);
if(L==null) id=0;
else id=L;
Long idLong=id;
lastIDs.put(S, idLong);
Map ids=invalidateSyncEntries.get(S);
if(ids==null) invalidateSyncEntries.put(S, ids=new HashMap<>());
ids.put(idLong, source);
return idLong;
}
}
public static void removeInvalidateSyncEntry(int host, Long id) {
Integer S=host;
synchronized(invalidateSyncLock) {
Map ids=invalidateSyncEntries.get(S);
if(ids!=null) ids.remove(id);
invalidateSyncLock.notify();
}
}
public static void waitForInvalidates(int host) {
Integer S=host;
synchronized(invalidateSyncLock) {
Long L=lastIDs.get(S);
if(L!=null) {
long lastID=L;
Map ids=invalidateSyncEntries.get(S);
if(ids!=null) {
// Wait until the most recent ID and all previous IDs have been completed, but do
// not wait for more than 60 seconds total to prevent locked-up daemons from
// locking up everything.
long startTime=System.currentTimeMillis();
while(true) {
long maxWait=startTime+60000-System.currentTimeMillis();
if(maxWait>0 && maxWait<=60000) {
LongList closedIDs=null;
Iterator I=ids.keySet().iterator();
boolean foundOlder=false;
while(I.hasNext()) {
Long idLong=I.next();
RequestSource source=ids.get(idLong);
if(source.isClosed()) {
if(closedIDs==null) closedIDs=new LongArrayList();
closedIDs.add(idLong);
} else {
long id=idLong;
if(id<=lastID) {
foundOlder=true;
break;
}
}
}
if(closedIDs!=null) {
int size=closedIDs.size();
for(int c=0;c
© 2015 - 2025 Weber Informatics LLC | Privacy Policy