1 package org.kuali.common.devops.aws.sysadmin;
2
3 import java.io.IOException;
4
5 import org.kuali.common.devops.aws.sysadmin.model.BootstrapContext;
6 import org.kuali.common.devops.model.User;
7 import org.kuali.common.util.Assert;
8 import org.kuali.common.util.CollectionUtils;
9 import org.kuali.common.util.FormatUtils;
10 import org.kuali.common.util.channel.api.SecureChannel;
11 import org.kuali.common.util.channel.model.ChannelContext;
12 import org.kuali.common.util.channel.model.RemoteFile;
13 import org.kuali.common.util.channel.util.ChannelUtils;
14 import org.kuali.common.util.execute.Executable;
15
16
17
18
19
20
21
22
23
24
25
26 public final class Bootstrap implements Executable {
27
28 private static final String WARNING = "WARNING: Do not delete or edit this file unless you know exactly what you are doing";
29
30 public Bootstrap(BootstrapContext context) {
31 this(context, false);
32 }
33
34 public Bootstrap(BootstrapContext context, boolean skip) {
35 Assert.noNulls(context);
36 this.context = context;
37 this.skip = skip;
38 }
39
40 private final BootstrapContext context;
41 private final boolean skip;
42
43 @Override
44 public void execute() {
45 if (skip) {
46 return;
47 }
48 bootstrap();
49 }
50
51 protected void bootstrap() {
52 enableRootSSH();
53 SecureChannel channel = null;
54 try {
55 channel = getChannel(context.getRoot(), false);
56 if (!isBootstrapped(channel)) {
57 bootstrap(channel);
58 markAsBootstrapped(channel);
59 Assert.isTrue(isBootstrapped(channel), "Unable to verify that this instance has been bootstrapped");
60 }
61 } catch (IOException e) {
62 throw new IllegalStateException("Unexpected IO error", e);
63 } finally {
64 ChannelUtils.closeQuietly(channel);
65 }
66 }
67
68 protected boolean isBootstrapped(SecureChannel channel) {
69 RemoteFile completed = getBootStrapCompletedFile();
70 return channel.exists(completed.getAbsolutePath());
71 }
72
73 protected void bootstrap(SecureChannel channel) {
74
75 String command1 = "resize2fs " + context.getRootVolumeDeviceName();
76
77
78 String command2 = "yum --assumeyes update";
79
80
81 channel.exec(command1, command2);
82
83
84 if (context.getPackages().size() > 0) {
85 String command = "yum --assumeyes install " + CollectionUtils.getSpaceSeparatedString(context.getPackages());
86 channel.exec(command);
87 }
88 }
89
90 protected void markAsBootstrapped(SecureChannel channel) {
91 RemoteFile completed = getBootStrapCompletedFile();
92 String content = "bootstrapping completed: " + FormatUtils.getDate(System.currentTimeMillis()) + "\n" + WARNING;
93 channel.scpString(content, completed);
94 }
95
96 protected RemoteFile getBootStrapCompletedFile() {
97 return new RemoteFile.Builder(context.getBootstrapCompletedAbsolutePath()).build();
98 }
99
100
101
102
103 protected void enableRootSSH() {
104 SecureChannel channel = null;
105 try {
106 channel = getChannel(context.getSshEnabledUser(), true);
107 boolean enabled = isRootSSHEnabled(channel);
108 if (!enabled) {
109 enableRootSSH(channel);
110 markAsRootSSHEnabled(channel);
111 Assert.isTrue(isRootSSHEnabled(channel), "Unable to verify that root ssh is enabled");
112 }
113 } catch (IOException e) {
114 throw new IllegalStateException("Unexpected IO error", e);
115 } finally {
116 ChannelUtils.closeQuietly(channel);
117 }
118 }
119
120 protected void enableRootSSH(SecureChannel channel) {
121
122
123 String src = context.getSshdOverride().getConfigFileOverrideLocation();
124 String dst = context.getSshEnabledUser().getHome() + "/.bootstrap/" + null;
125
126 String command1 = "sudo cp " + context.getSshEnabledUser().getAuthorizedKeys() + " " + context.getRoot().getAuthorizedKeys();
127 String command2 = "sudo cp " + dst + " " + null;
128 String command3 = "sudo service " + null;
129
130 RemoteFile file = new RemoteFile.Builder(dst).build();
131
132 channel.exec(command1);
133 channel.scp(src, file);
134 channel.exec(command2);
135 channel.exec(command3);
136
137 }
138
139 protected void markAsRootSSHEnabled(SecureChannel channel) {
140
141 RemoteFile enabled = getRootSSHEnabledFile(context.getSshEnabledUser());
142 String content = "root ssh enabled: " + FormatUtils.getDate(System.currentTimeMillis()) + "\n" + WARNING;
143 channel.scpString(content, enabled);
144 }
145
146 protected RemoteFile getRootSSHEnabledFile(User ec2User) {
147 String absolutePath = ec2User.getHome() + "/.bootstrap/root-ssh.enabled";
148 return new RemoteFile.Builder(absolutePath).build();
149 }
150
151
152
153
154 protected boolean isRootSSHEnabled(SecureChannel channel) {
155 RemoteFile enabled = getRootSSHEnabledFile(context.getSshEnabledUser());
156 return channel.exists(enabled.getAbsolutePath());
157 }
158
159 protected SecureChannel getChannel(User user, boolean requestPseudoTerminal) throws IOException {
160
161
162 ChannelContext cc = null;
163 return context.getService().openChannel(cc);
164 }
165
166 public BootstrapContext getContext() {
167 return context;
168 }
169
170 public boolean isSkip() {
171 return skip;
172 }
173
174 }