package io.cattle.platform.process.agent;
import static io.cattle.platform.core.model.tables.AccountTable.*;
import static io.cattle.platform.core.model.tables.AgentTable.*;
import io.cattle.platform.archaius.util.ArchaiusUtil;
import io.cattle.platform.core.constants.AccountConstants;
import io.cattle.platform.core.constants.AgentConstants;
import io.cattle.platform.core.constants.CredentialConstants;
import io.cattle.platform.core.dao.AccountDao;
import io.cattle.platform.core.dao.InstanceDao;
import io.cattle.platform.core.model.Account;
import io.cattle.platform.core.model.Agent;
import io.cattle.platform.engine.handler.HandlerResult;
import io.cattle.platform.engine.process.ProcessInstance;
import io.cattle.platform.engine.process.ProcessState;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.util.DataAccessor;
import io.cattle.platform.process.base.AbstractDefaultProcessHandler;
import io.cattle.platform.util.type.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import com.netflix.config.DynamicBooleanProperty;
@Named
public class AgentCreate extends AbstractDefaultProcessHandler {
private static final DynamicBooleanProperty CREATE_ACCOUNT = ArchaiusUtil.getBoolean("process.agent.create.create.account");
@Inject
JsonMapper jsonMapper;
@Inject
AccountDao accountDao;
@Inject
InstanceDao instanceDao;
@Override
public HandlerResult handle(ProcessState state, ProcessInstance process) {
Agent agent = (Agent) state.getResource();
Long accountId = agent.getAccountId();
if (accountId != null || !CREATE_ACCOUNT.get()) {
return new HandlerResult(AGENT.ACCOUNT_ID, accountId);
}
DataAccessor.fromMap(state.getData()).withScope(AccountConstants.class).withKey(AccountConstants.OPTION_CREATE_APIKEY).set(true);
DataAccessor.fromMap(state.getData()).withScope(AccountConstants.class).withKey(AccountConstants.OPTION_CREATE_APIKEY_KIND).set(
CredentialConstants.KIND_AGENT_API_KEY);
List<? extends String> roles =
DataAccessor.fromDataFieldOf(agent).withKey(AgentConstants.DATA_REQUESTED_ROLES).withDefault(Collections.EMPTY_LIST)
.asList(jsonMapper, String.class);
sortRoles(roles);
String primaryRole = getPrimaryRole(roles); // note null is an acceptable value
Account account = createPrimaryAccount(agent, primaryRole);
create(account, state.getData());
Map<String, Object> data = new HashMap<>();
data.put(AgentConstants.FIELD_ACCOUNT_ID, account.getId());
List<? extends String> secondaryRoles = getSecondaryRoles(roles);
List<Long> authedRoleAccounts = createSecondaryAccounts(agent, secondaryRoles, state);
if (!authedRoleAccounts.isEmpty()) {
data.put(AgentConstants.FIELD_AUTHORIZED_ROLE_ACCOUNTS, authedRoleAccounts);
}
return new HandlerResult(data);
}
protected Account createPrimaryAccount(Agent agent, String role) {
if (agent.getAccountId() != null) {
return getObjectManager().loadResource(Account.class, agent.getAccountId());
}
String uuid = getAccountUuid(agent);
Account account = accountDao.findByUuid(uuid);
if (account == null) {
Object data = createAccountDataWithActAsValue(role);
account = getObjectManager().create(Account.class,
ACCOUNT.UUID, uuid,
ACCOUNT.DATA, data,
ACCOUNT.KIND, "agent");
}
return account;
}
protected List<Long> createSecondaryAccounts(Agent agent, List<? extends String> roles, ProcessState state) {
if (roles.isEmpty()) {
return new ArrayList<Long>();
}
List<Long> authedRoleAccountIds = DataAccessor.fieldLongList(agent, AgentConstants.FIELD_AUTHORIZED_ROLE_ACCOUNTS);
if (authedRoleAccountIds != null && !authedRoleAccountIds.isEmpty()) {
return authedRoleAccountIds;
}
authedRoleAccountIds = new ArrayList<Long>();
for (String role : roles) {
String uuid = getAccountUuid(agent, role);
Account account = accountDao.findByUuid(uuid);
Map<String, Object> data = createAccountDataWithActAsValue(role);
data.put(AccountConstants.DATA_AGENT_OWNER_ID, agent.getId());
if (account == null) {
account = getObjectManager().create(Account.class,
ACCOUNT.UUID, uuid,
ACCOUNT.DATA, data,
ACCOUNT.KIND, "agent");
}
create(account, state.getData());
authedRoleAccountIds.add(account.getId());
}
return authedRoleAccountIds;
}
Map<String, Object> createAccountDataWithActAsValue(String r) {
if ("environment".equals(r)) {
return CollectionUtils.asMap(AccountConstants.DATA_ACT_AS_RESOURCE_ACCOUNT, true);
} else if ("environmentAdmin".equals(r)) {
return CollectionUtils.asMap(AccountConstants.DATA_ACT_AS_RESOURCE_ADMIN_ACCOUNT, true);
}
return new HashMap<>();
}
private void sortRoles(List<? extends String> roles) {
Collections.sort(roles, new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
if (lhs.equals(rhs)) {
return 0;
}
if ("agent".equals(lhs)) {
return -1;
} else if ("agent".equals(rhs)) {
return 1;
}
if ("environmentAdmin".equals(lhs)) {
return -1;
} else if ("environmentAdmin".equals(rhs)) {
return 1;
}
return 0;
}
});
}
private String getPrimaryRole(List<? extends String> roles) {
if (roles.isEmpty()) {
return null;
}
return roles.get(0);
}
private List<? extends String> getSecondaryRoles(List<? extends String> roles) {
if (roles.isEmpty()) {
return roles;
} else if (roles.size() == 1){
return new ArrayList<String>();
}
return roles.subList(1, roles.size());
}
protected String getAccountUuid(Agent agent, String role) {
return "agentAccount" + agent.getId() + "-" + role;
}
protected String getAccountUuid(Agent agent) {
return "agentAccount" + agent.getId();
}
public AccountDao getAccountDao() {
return accountDao;
}
}