2929import java .util .Arrays ;
3030import java .util .Collections ;
3131import java .util .List ;
32+ import java .util .Locale ;
3233import java .util .Optional ;
3334import java .util .function .Predicate ;
3435import java .util .logging .Level ;
3536import java .util .logging .Logger ;
37+ import java .util .regex .Pattern ;
3638import java .util .stream .Collectors ;
3739import jenkins .model .Jenkins ;
40+ import org .apache .commons .lang .RandomStringUtils ;
3841import org .apache .commons .lang .StringUtils ;
3942import org .csanchez .jenkins .plugins .kubernetes .pipeline .PodTemplateStepExecution ;
4043
@@ -43,6 +46,9 @@ private PodUtils() {}
4346
4447 private static final Logger LOGGER = Logger .getLogger (PodUtils .class .getName ());
4548
49+ private static final Pattern NAME_PATTERN =
50+ Pattern .compile ("[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\ .[a-z0-9]([-a-z0-9]*[a-z0-9])?)*" );
51+
4652 public static final Predicate <ContainerStatus > CONTAINER_IS_TERMINATED =
4753 cs -> cs .getState ().getTerminated () != null ;
4854 public static final Predicate <ContainerStatus > CONTAINER_IS_WAITING =
@@ -57,15 +63,27 @@ public static List<ContainerStatus> getWaitingContainers(Pod pod) {
5763 return getContainers (pod , CONTAINER_IS_WAITING );
5864 }
5965
60- public static List <ContainerStatus > getContainerStatus (Pod pod ) {
66+ /**
67+ * Get all container statuses (does not include ephemeral or init containers).
68+ * @param pod pod to get container statuses for
69+ * @return list of statuses, possibly empty, never null
70+ */
71+ @ NonNull
72+ public static List <ContainerStatus > getContainerStatus (@ NonNull Pod pod ) {
6173 PodStatus podStatus = pod .getStatus ();
6274 if (podStatus == null ) {
6375 return Collections .emptyList ();
6476 }
6577 return podStatus .getContainerStatuses ();
6678 }
6779
68- public static List <ContainerStatus > getContainers (Pod pod , Predicate <ContainerStatus > predicate ) {
80+ /**
81+ * Get pod container statuses (does not include ephemeral or init containers) that match the given filter.
82+ * @param pod pod to get container statuses for
83+ * @param predicate container status predicate
84+ * @return list of statuses, possibly empty, never null
85+ */
86+ public static List <ContainerStatus > getContainers (@ NonNull Pod pod , @ NonNull Predicate <ContainerStatus > predicate ) {
6987 return getContainerStatus (pod ).stream ().filter (predicate ).collect (Collectors .toList ());
7088 }
7189
@@ -182,4 +200,39 @@ public static String logLastLines(@NonNull Pod pod, @NonNull KubernetesClient cl
182200 }
183201 return Util .fixEmpty (sb .toString ());
184202 }
203+
204+ /**
205+ * Generate a random string to be used as the suffix for dynamic resource names.
206+ * @return random string suitable for kubernetes resources
207+ */
208+ @ NonNull
209+ public static String generateRandomSuffix () {
210+ return RandomStringUtils .random (5 , "bcdfghjklmnpqrstvwxz0123456789" );
211+ }
212+
213+ /**
214+ * Create kubernetes resource name with a random suffix appended to the given base name. This method
215+ * performs some basic transforms to make the base name compliant (i.e. spaces and underscores). The
216+ * returned string will also be truncated to a max of 63 characters.
217+ * @param name base name to append to
218+ * @return resource name with random suffix and maximum length of 63 characters
219+ */
220+ @ NonNull
221+ public static String createNameWithRandomSuffix (@ NonNull String name ) {
222+ String suffix = generateRandomSuffix ();
223+ // no spaces
224+ name = name .replaceAll ("[ _]" , "-" ).toLowerCase (Locale .getDefault ());
225+ // keep it under 63 chars (62 is used to account for the '-')
226+ name = name .substring (0 , Math .min (name .length (), 62 - suffix .length ()));
227+ return String .join ("-" , name , suffix );
228+ }
229+
230+ /**
231+ * Check if the given name is a valid pod resource name. Does not validate string length.
232+ * @param name name to check
233+ * @return true if the given string contains valid pod resource name characters
234+ */
235+ public static boolean isValidName (@ NonNull String name ) {
236+ return PodUtils .NAME_PATTERN .matcher (name ).matches ();
237+ }
185238}
0 commit comments