git.fiddlerwoaroof.com
Browse code

feat: fetch resources, add statuses

Ed Langley authored on 29/10/2020 21:59:19
Showing 8 changed files
... ...
@@ -8,3 +8,4 @@ daydreamer
8 8
 daydreamer--all-systems.a
9 9
 daydreamer-runtime
10 10
 remember--versions_half_up_to_pi
11
+*.sw?
... ...
@@ -1,32 +1,43 @@
1 1
 (defpackage :daydreamer.aws-result
2
-  (:use :cl :fw.lu :alexandria :st)
3
-  (:export
4
-   #:stack
5
-   #:outputs
6
-   #:reader
7
-   #:creation-time
8
-   #:notification-arns
9
-   #:stack-id
10
-   #:stack-name
11
-   #:description
12
-   #:stack-status
13
-   #:disable-rollback
14
-   #:tags
15
-   #:deletion-time
16
-   #:rollback-configuration
17
-   #:drift-information
18
-   #:enable-termination-protection
19
-   #:parameters
20
-   #:start-date-time
21
-   #:end-date-time
22
-   #:creation-date-time
23
-   #:extract-timeline
24
-   #:extract-list
25
-   #:extract-stack
26
-   #:timeline
27
-   #:tagged-kv-formatter))
2
+  (:use :cl :fw.lu :alexandria)
3
+  (:export #:stack
4
+           #:outputs
5
+           #:reader
6
+           #:creation-time
7
+           #:notification-arns
8
+           #:stack-id
9
+           #:stack-name
10
+           #:description
11
+           #:stack-status
12
+           #:disable-rollback
13
+           #:tags
14
+           #:deletion-time
15
+           #:rollback-configuration
16
+           #:drift-information
17
+           #:enable-termination-protection
18
+           #:parameters
19
+           #:start-date-time
20
+           #:end-date-time
21
+           #:creation-date-time
22
+           #:extract-timeline
23
+           #:extract-list
24
+           #:extract-stack
25
+           #:timeline
26
+           #:tagged-kv-formatter
27
+           #:extract-stack-resource
28
+           #:stack-resource
29
+           #:physical-resource-id
30
+           #:resource-status
31
+           #:logical-resource-id
32
+           #:timestamp
33
+           #:resource-type
34
+           #:resource-status-reason))
28 35
 (in-package :daydreamer.aws-result)
29 36
 
37
+(defgeneric stack-name (stack)
38
+  (:method ((stack string))
39
+    stack))
40
+
30 41
 (defun find-all-indices (pred str &optional accum (start (or (car accum) 0)))
31 42
   (check-type pred function)
32 43
   (check-type str string)
... ...
@@ -158,16 +169,18 @@
158 169
 (defparameter *stack-statuses*
159 170
   '("CREATE_COMPLETE" "CREATE_IN_PROGRESS" "CREATE_FAILED"
160 171
     "DELETE_COMPLETE" "DELETE_FAILED" "DELETE_IN_PROGRESS"
161
-    "REVIEW_IN_PROGRESS"
162
-    "ROLLBACK_COMPLETE" "ROLLBACK_FAILED" "ROLLBACK_IN_PROGRESS"
163
-    "UPDATE_COMPLETE" "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS" "UPDATE_IN_PROGRESS"
164
-    "UPDATE_ROLLBACK_COMPLETE" "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS" "UPDATE_ROLLBACK_FAILED" "UPDATE_ROLLBACK_IN_PROGRESS"))
172
+    "REVIEW_IN_PROGRESS" "ROLLBACK_COMPLETE" "ROLLBACK_FAILED"
173
+    "ROLLBACK_IN_PROGRESS" "UPDATE_COMPLETE"
174
+    "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS" "UPDATE_IN_PROGRESS"
175
+    "UPDATE_ROLLBACK_COMPLETE"
176
+    "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS"
177
+    "UPDATE_ROLLBACK_FAILED" "UPDATE_ROLLBACK_IN_PROGRESS"))
165 178
 
166 179
 #+nil
167
-(aws-sdk/services/cloudformation:list-stacks 
180
+(aws-sdk/services/cloudformation:list-stacks
168 181
  :stack-status-filter '("UPDATE_COMPLETE" "UPDATE_IN_PROGRESS"
169 182
                         "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS" "UPDATE_ROLLBACK_COMPLETE"
170
-                        "UPDATE_ROLLBACK_IN_PROGRESS" "UPDATE_ROLLBACK_FAILED" 
183
+                        "UPDATE_ROLLBACK_IN_PROGRESS" "UPDATE_ROLLBACK_FAILED"
171 184
                         "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS" "CREATE_FAILED"
172 185
                         "CREATE_COMPLETE" "CREATE_IN_PROGRESS"))
173 186
 
... ...
@@ -183,11 +196,47 @@
183 196
           s-edt (initialize-date s-edt)
184 197
           s-cdt (initialize-date s-cdt))))
185 198
 
186
-
199
+(defclass stack-resource ()
200
+  ((%physical-resource-id :initarg :physical-resource-id :reader physical-resource-id)
201
+   (%resource-status :initarg :resource-status :reader resource-status)
202
+   (%resource-status-reason :initarg :resource-status-reason :reader resource-status-reason :initform nil)
203
+   (%stack-id :initarg :stack-id :reader stack-id)
204
+   (%stack-name :initarg :stack-name :reader stack-name)
205
+   (%drift-information :initarg :drift-information :reader drift-information)
206
+   (%logical-resource-id :initarg :logical-resource-id :reader logical-resource-id)
207
+   (%timestamp :initarg :timestamp :reader timestamp)
208
+   (%resource-type :initarg :resource-type :reader resource-type)))
209
+
210
+(defmethod print-object ((o stack-resource) s)
211
+  (print-unreadable-object (o s :type t :identity t)
212
+    (format s "~a (~a): ~a"
213
+            (logical-resource-id o)
214
+            (resource-type o)
215
+            (resource-status o))))
216
+
217
+(defun extract-stack-resource (it)
218
+  (apply 'make-instance 'daydreamer.aws-result::stack-resource
219
+         (daydreamer.aws-result::alist-to-initargs
220
+          it (fw.lu:alist-string-hash-table
221
+              `((:physical-resource-id . car)
222
+                (:resource-status . car)
223
+                (:resource-status-reason . car)
224
+                (:stack-id . car)
225
+                (:stack-name . car)
226
+                (:drift-information . car)
227
+                (:logical-resource-id . car)
228
+                (:timestamp . car)
229
+                (:resource-type . car))))))
230
+
231
+(defclass stack-template ()
232
+  ((template-body :initarg :template-body :reader template-body)
233
+   (stages-available :initarg :stages-available :reader stages-available)))
234
+
235
+
236
+#+(or)
187 237
 (deftest decamelize ()
188 238
   (should be equal "a" (decamelize "A"))
189 239
   (should be equal "a" (decamelize "a"))
190 240
   (should be equal "outputs" (decamelize "Outputs"))
191 241
   (should be equal "outputs-outputs" (decamelize "OutputsOutputs"))
192 242
   (should be equal "a-b-c" (decamelize "ABC")))
193
-
... ...
@@ -21,23 +21,25 @@
21 21
 ;;     nil)
22 22
 
23 23
 (stepwise
24
-  ((defun load-compile (pn)
25
-     (load (compile-file pn))))
26
-
27
-  ((ql:quickload :cffi-grovel))
28
-  ((princ
29
-    (mapcar 'load-compile
30
-            (remove #\.
31
-                    (directory (merge-pathnames "*.asd"
32
-                                                *load-pathname*)) 
33
-                    :key 'pathname-name 
34
-                    :test 'alexandria:starts-with)))
35
-   (terpri))
36
-
37
-  ((ql:quickload :daydreamer))
38
-
39
-  ((asdf:operate :static-program-op :daydreamer))
40
-  #+nil
41
-  ((asdf/driver:symbol-call :daydreamer.cli :dump))
42
-  
43
-  ((sb-ext:quit)))
24
+ ((defun load-compile (pn)
25
+    (load (compile-file pn))))
26
+
27
+ ((ql:quickload :cffi-grovel))
28
+ ((princ
29
+   (mapcar 'load-compile
30
+           (remove #\.
31
+                   (directory (merge-pathnames "*.asd"
32
+                                               *load-pathname*))
33
+                   :key 'pathname-name
34
+                   :test 'alexandria:starts-with)))
35
+  (terpri))
36
+
37
+ ((ql:quickload :daydreamer))
38
+
39
+ #+linux
40
+ ((asdf:operate :static-program-op :daydreamer))
41
+
42
+ #-linux
43
+ ((uiop:symbol-call :daydreamer.cli :dump))
44
+
45
+ ((sb-ext:quit)))
... ...
@@ -13,30 +13,45 @@
13 13
 
14 14
 (in-package :daydreamer.cli)
15 15
 
16
-
17 16
 (defparameter *daydreamer-synopsis*
18 17
   (defsynopsis (:postfix "ARGS...")
19 18
     (group (:header "actions")
20
-           (flag :short-name "s" :long-name "stacks" :description "show stack information")
21
-           (flag :short-name "p" :long-name "parameters" :description "show stack parameters")
22
-           (flag :short-name "o" :long-name "outputs" :description "show stack outputs")
23
-           (flag :short-name "w" :long-name "watch" :description "watch a cloudformation stack until it's done processing")
24
-           (flag :short-name "i" :long-name "info" :description "get parameters, status and output of a stack")
25
-           #+null
26
-           (flag :short-name "s" :long-name "start")
27
-           (stropt :long-name "aws-region" :default-value "us-west-2")
28
-           (flag :short-name "u" :long-name "update"))
19
+      (flag :short-name "s" :long-name "stacks" :description "show stack information")
20
+      (flag :short-name "p" :long-name "parameters" :description "show stack parameters")
21
+      (flag :short-name "o" :long-name "outputs" :description "show stack outputs")
22
+      (flag :short-name "r" :long-name "resources" :description "show stack resources")
23
+      (flag :short-name "w" :long-name "watch" :description "watch a cloudformation stack until it's done processing")
24
+      (flag :short-name "i" :long-name "info" :description "get parameters, status and output of a stack")
25
+      #+null
26
+      (flag :short-name "s" :long-name "start")
27
+      (stropt :long-name "aws-region"
28
+              :description "explicitly pick AWS Region"
29
+              :env-var "AWS_DEFAULT_REGION")
30
+      (stropt :long-name "aws-profile"
31
+              :description "aws profile to use for authentication"
32
+              :env-var "AWS_PROFILE")
33
+      (stropt :long-name "aws-access-key-id"
34
+              :description "aws access-key-id to use for authentication"
35
+              :env-var "AWS_ACCESS_KEY_ID")
36
+      (stropt :long-name "aws-secret-access-key"
37
+              :description "aws secret-access-key to use for authentication"
38
+              :env-var "AWS_SECRET_ACCESS_KEY")
39
+      (stropt :long-name "aws-session-token"
40
+              :description "aws session-token to use for authentication"
41
+              :env-var "AWS_SESSION_TOKEN")
42
+      #+null
43
+      (flag :short-name "u" :long-name "update"))
29 44
     (group (:header "misc")
30
-           (flag :long-name "rebuild")
31
-           (flag :long-name "self-test")
32
-           (flag :long-name "help"))))
45
+      (flag :long-name "rebuild")
46
+      (flag :long-name "self-test")
47
+      (flag :long-name "help"))))
33 48
 
34 49
 (defun stacks-main ()
35 50
   (mapcar (lambda (s)
36 51
             (format t "~3&STACK ~a ~a~2%"
37 52
                     (daydreamer.aws-result:stack-name s)
38 53
                     (daydreamer.aws-result:stack-status s))
39
-            (stack-info s))
54
+            (stack-info s t t t))
40 55
           (mapcar 'daydreamer.aws-result:extract-stack
41 56
                   (daydreamer.aws-result:extract-list
42 57
                    (cdar
... ...
@@ -48,8 +63,8 @@
48 63
 (defun stack-outputs-main (name)
49 64
   (stack-outputs (stack-for-name name)))
50 65
 
51
-(defun stack-info-main (name)
52
-  (stack-info (stack-for-name name)))
66
+(defun stack-info-main (name status parameters outputs resources)
67
+  (stack-info (stack-for-name name) status parameters outputs resources))
53 68
 
54 69
 (defun run-tests ()
55 70
   (st:test :package (find-package :daydreamer.aws-result))
... ...
@@ -74,20 +89,58 @@
74 89
   (let* ((context (net.didierverna.clon:make-context :synopsis *daydreamer-synopsis*))
75 90
          (files (clon:remainder :context context))
76 91
          (region (clon:getopt :long-name "aws-region"))
77
-         (aws-sdk:*session* (aws-sdk:make-session :credentials (aws-sdk:default-aws-credentials)
78
-                                                  :region region)))
92
+         (profile (clon:getopt :long-name "aws-profile"))
93
+         (access-key-id (clon:getopt :long-name "aws-access-key-id"))
94
+         (secret-access-key (clon:getopt :long-name "aws-secret-access-key"))
95
+         (session-token (clon:getopt :long-name "aws-session-token")))
96
+
97
+    (cond (access-key-id
98
+           (setf aws:*session*
99
+                 (aws:make-session
100
+                  :credentials (if session-token
101
+                                   (aws:make-credentials
102
+                                    :access-key-id access-key-id
103
+                                    :secret-access-key secret-access-key
104
+                                    :session-token session-token
105
+                                    )
106
+                                   (aws:make-credentials
107
+                                    :access-key-id access-key-id
108
+                                    :secret-access-key secret-access-key
109
+                                    :session-token nil
110
+                                    ))
111
+                  :region region)))
112
+          ((and region profile)
113
+           (aws:init-session
114
+            :region region
115
+            :profile profile))
116
+          (region
117
+           (aws:init-session
118
+            :region region))
119
+          (profile
120
+           (aws:init-session
121
+            :profile profile))
122
+          (t
123
+           (aws:init-session)))
79 124
 
80
-    (format *error-output* "~&IN REGION: ~a~%" region)
125
+    (format *error-output* "~&IN REGION: ~a~%WITH PROFILE: ~a~%"
126
+            (aws:session-region aws:*session*)
127
+            profile)
81 128
 
82 129
     (cond ((clon:getopt :long-name "help") (clon:help))
83
-          ((clon:getopt :long-name "info") (stack-info-main (car files)))
84 130
           ((clon:getopt :long-name "watch") (daydreamer.main:watch-stack (car files)))
85 131
           ((clon:getopt :long-name "stacks") (stacks-main))
86
-          ((clon:getopt :long-name "outputs") (stack-outputs-main (car files)))
87
-          ((clon:getopt :long-name "parameters") (stack-parameters-main (car files)))
88 132
           ((clon:getopt :long-name "self-test") (run-tests))
89 133
           ((clon:getopt :long-name "rebuild")
90 134
            (load (compile-file (load-time-value
91 135
                                 (asdf:system-relative-pathname :daydreamer "cli.lisp"))))
92
-           (dump)))))
93
-
136
+           (dump))
137
+          (t
138
+           (let ((info (clon:getopt :long-name "info"))
139
+                 (parameters (clon:getopt :long-name "parameters"))
140
+                 (outputs (clon:getopt :long-name "outputs"))
141
+                 (resources (clon:getopt :long-name "resources")))
142
+             (stack-info-main (car files)
143
+                              info
144
+                              (or info parameters)
145
+                              (or info outputs)
146
+                              resources))))))
... ...
@@ -1,12 +1,20 @@
1 1
 #!/usr/bin/env bash
2
-cd $HOME
2
+
3
+set -eu -o pipefail
4
+
5
+cd "$HOME" 
3 6
 
4 7
 pwd
5
-git clone --depth=1 https://gitlab.com/fiddlerwoaroof/osicat.git ~/quicklisp/local-projects/osicat
6
-git clone --depth=1 https://gitlab.com/fiddlerwoaroof/cffi.git ~/quicklisp/local-projects/cffi
7 8
 
8
-git clone --depth=1 https://github.com/fiddlerwoaroof/fwoar.lisputils.git ~/quicklisp/local-projects/fwoar.lisputils/
9
-git clone --depth=1 https://github.com/fiddlerwoaroof/data-lens.git ~/quicklisp/local-projects/data-lens/
10
-git clone --depth=1 https://github.com/pokepay/aws-sdk-lisp.git ~/quicklisp/local-projects/aws-sdk-lisp && pushd ~/quicklisp/local-projects/aws-sdk-lisp && git checkout 6d1f66e && popd
9
+git clone --depth=1 https://gitlab.com/fiddlerwoaroof/osicat.git "$HOME"/quicklisp/local-projects/osicat
10
+git clone --depth=1 https://gitlab.com/fiddlerwoaroof/cffi.git "$HOME"/quicklisp/local-projects/cffi
11
+
12
+git clone --depth=1 https://github.com/fiddlerwoaroof/fwoar.lisputils.git "$HOME"/quicklisp/local-projects/fwoar.lisputils/
13
+git clone --depth=1 https://github.com/fiddlerwoaroof/data-lens.git "$HOME"/quicklisp/local-projects/data-lens/
14
+git clone --depth=1 https://github.com/fiddlerwoaroof/aws-sdk-lisp.git "$HOME"/quicklisp/local-projects/aws-sdk-lisp
15
+
16
+pushd "$HOME"/quicklisp/local-projects/aws-sdk-lisp
17
+git checkout my-patches
18
+popd
11 19
 
12
-ln -s /root/project/ ~/quicklisp/local-projects/daydreamer
20
+ln -s /root/project/ "$HOME"/quicklisp/local-projects/daydreamer
... ...
@@ -5,42 +5,42 @@
5 5
 (sb-posix:setenv "CC" "clang" 1)
6 6
 
7 7
 (defsystem :daydreamer
8
-    :description ""
9
-    :author "Ed L <gh@elangley.org>"
10
-    :license "MIT"
11
-    :defsystem-depends-on (#:cffi-grovel)
12
-    :depends-on (#:alexandria
13
-                 #:uiop
14
-                 #:serapeum
15
-                 #:fwoar-lisputils
16
-                 (:feature (:not :lispworks)
17
-                           #:net.didierverna.clon)
18
-                 #:cl-base64
19
-                 #:local-time
20
-                 #:osicat
21
-                 #:local-time-duration
22
-                 #:closer-mop
23
-                 #:aws-sdk                 
24
-                 #:aws-sdk/services/cloudformation
25
-                 #:aws-sdk/services/monitoring
26
-                 #:aws-sdk/services/elasticmapreduce
27
-                 #:should-test
28
-                 #:yason
29
-                 #:hunchentoot
30
-                 #:data-lens
31
-                 #:cffi)
32
-    :serial t
33
-    :components ((:file "aws-result")
34
-                 (:file "main")
35
-                 (:file "cli" :if-feature (:not :lispworks)))
8
+  :description ""
9
+  :author "Ed L <gh@elangley.org>"
10
+  :license "MIT"
11
+  :defsystem-depends-on (#:cffi-grovel)
12
+  :depends-on (#:alexandria
13
+               #:uiop
14
+               #:serapeum
15
+               #:fwoar-lisputils
16
+               #:cl-base64
17
+               #:local-time
18
+               #:local-time-duration
19
+               #:closer-mop
20
+               #:aws-sdk                 
21
+               #:aws-sdk/services/cloudformation
22
+               #:aws-sdk/services/monitoring
23
+               #:aws-sdk/services/elasticmapreduce
24
+               #:yason
25
+               #:hunchentoot
26
+               #:data-lens
27
+               #:cffi
28
+               (:feature (:not :lispworks)
29
+                         #:net.didierverna.clon)
30
+               (:feature (:not :lispworks)
31
+                         #:should-test))
32
+  :serial t
33
+  :components ((:file "aws-result")
34
+               (:file "main")
35
+               (:file "cli" :if-feature (:not :lispworks)))
36 36
 
37
-    :entry-point "daydreamer.cli::main"
38
-    #-lispworks 
39
-    :output-files
40
-    #-lispworks
41
-    (cffi-toolchain:static-program-op (o c)
42
-                                      (format t "~&*dpd* ~s~%%" (merge-pathnames "daydreamer"
43
-                                                                                 *default-pathname-defaults*))
44
-                                      (list
45
-                                       (merge-pathnames "daydreamer"
46
-                                                        *default-pathname-defaults*))))
37
+  :entry-point "daydreamer.cli::main"
38
+  #-lispworks 
39
+  :output-files
40
+  #-lispworks
41
+  (cffi-toolchain:static-program-op (o c)
42
+                                    (format t "~&*dpd* ~s~%%" (merge-pathnames "daydreamer"
43
+                                                                               *default-pathname-defaults*))
44
+                                    (list
45
+                                     (merge-pathnames "daydreamer"
46
+                                                      *default-pathname-defaults*))))
... ...
@@ -1,7 +1,7 @@
1 1
 ;; MIT license Edward Langley (c) 2018
2 2
 
3 3
 (defpackage :daydreamer.main
4
-  (:use :cl :fw.lu :alexandria :st :daydreamer.aws-result)
4
+  (:use :cl :fw.lu :alexandria :daydreamer.aws-result)
5 5
   (:export main dump
6 6
            #:stack-parameters
7 7
            #:stack-outputs
... ...
@@ -35,7 +35,7 @@
35 35
 
36 36
 (defun stack-parameters (the-stack)
37 37
   (print-kvs "Parameter"
38
-             (tagged-kv-formatter "PARAMETERS") t
38
+             (tagged-kv-formatter "PARAMETER") t
39 39
              (parameters the-stack)))
40 40
 
41 41
 (defun lt-format (a b &key &allow-other-keys)
... ...
@@ -48,10 +48,11 @@
48 48
 
49 49
 (defun every-five-seconds (cb args &optional (delay-function #'sleep))
50 50
   (loop
51
-     for (continue? . next-args) = (multiple-value-list (apply cb args)) then (multiple-value-list (apply cb next-args))
52
-     while continue?
53
-     do (funcall delay-function 5)))
51
+    for (continue? . next-args) = (multiple-value-list (apply cb args)) then (multiple-value-list (apply cb next-args))
52
+    while continue?
53
+    do (funcall delay-function 5)))
54 54
 
55
+#+(or)
55 56
 (deftest every-five-seconds ()
56 57
   (let ((counter 0)
57 58
         delay)
... ...
@@ -85,6 +86,23 @@
85 86
               counters)
86 87
       (should be = 5 delay))))
87 88
 
89
+(defun resource-block (the-stack)
90
+  (format t "~& RESOURCES ~%============~%")
91
+  (let ((resources (daydreamer.aws-result:extract-list
92
+                    (serapeum:assocdr "StackResources"
93
+                                      (aws/cloudformation:describe-stack-resources
94
+                                       :stack-name (stack-name the-stack))
95
+                                      :test 'equal)
96
+                    'daydreamer.aws-result:extract-stack-resource)))
97
+    (loop for resource in resources
98
+          do (format t "RESOURCE ~a (~a) ~a ~a~:[~;~%~:*~4t~a~]~%"
99
+                     (logical-resource-id resource)
100
+                     (resource-type resource)
101
+                     (resource-status resource)
102
+                     (physical-resource-id resource)
103
+                     (resource-status-reason resource))))
104
+  (format t "~&============~2%"))
105
+
88 106
 (defun parameter-block (the-stack)
89 107
   (format t "~& PARAMETERS ~%============~%")
90 108
   (stack-parameters the-stack)
... ...
@@ -100,6 +118,10 @@
100 118
   ((%stack :initarg :stack :accessor stack)
101 119
    (%old-status :initarg :old-status :accessor old-status :initform nil)))
102 120
 
121
+(defmethod stack-name ((stack-formatter stack-formatter))
122
+  (when (slot-boundp stack-formatter '%stack)
123
+    (stack-status (stack stack-formatter))))
124
+
103 125
 (defmethod stack-status ((stack-formatter stack-formatter))
104 126
   (when (slot-boundp stack-formatter '%stack)
105 127
     (stack-status (stack stack-formatter))))
... ...
@@ -117,7 +139,7 @@
117 139
 
118 140
 (defgeneric refresh (stack-formatter)
119 141
   (:method ((stack daydreamer.aws-result:stack))
120
-    (stack-for-name (stack-name stack))) 
142
+    (stack-for-name (stack-name stack)))
121 143
   (:method ((stack-formatter string))
122 144
     (make-instance 'stack-formatter :stack (stack-for-name stack-formatter)))
123 145
   (:method ((stack-formatter stack-formatter))
... ...
@@ -127,28 +149,34 @@
127 149
 (defmethod old-status ((stack daydreamer.aws-result:stack))
128 150
   nil)
129 151
 
130
-(defun stack-info (the-stack)
152
+(defun stack-info (the-stack status parameters outputs &optional (resources nil))
131 153
   (with-accessors ((old-status old-status)) the-stack
132 154
     (let* ((current-status (stack-status the-stack)))
133 155
       (unless old-status
134
-        (parameter-block the-stack))
156
+        (when parameters
157
+          (parameter-block the-stack)))
135 158
 
136 159
       (unless (equal old-status current-status)
137
-        (format t "~&STATUS ~a~%" current-status))
160
+        (when status
161
+          (format t "~&STATUS ~a~%" current-status)))
162
+
163
+      (when resources
164
+        (terpri)
165
+        (resource-block the-stack))
138 166
 
139 167
       (if (ends-with-subseq "COMPLETE" (symbol-name current-status))
140
-          (output-block the-stack)
168
+          (when outputs
169
+            (output-block the-stack))
141 170
           t))))
142 171
 
143
-(defmacro refreshing (cb)
172
+(defmacro refreshing (cb &rest args)
144 173
   `(lambda (thing)
145 174
      (let ((refreshed-thing (refresh thing)))
146
-       (values (,cb refreshed-thing)
175
+       (values (,cb refreshed-thing ,@args)
147 176
                refreshed-thing))))
148 177
 
149 178
 (defun watch-stack (name)
150 179
   (format t "~&Watching ~s~2%" name)
151
-  (every-five-seconds (refreshing stack-info)
180
+  (every-five-seconds (refreshing stack-info t t t)
152 181
                       (list name))
153 182
   (fresh-line))
154
-
... ...
@@ -3,6 +3,6 @@ export ASDF_OUTPUT_TRANSLATIONS="/:" CC="clang"
3 3
 
4 4
 env
5 5
 
6
-sbcl --no-userinit --disable-debugger --load /root/quicklisp/setup.lisp --load build.lisp
6
+sbcl --no-userinit --disable-debugger --load "$HOME"/quicklisp/setup.lisp --load build.lisp
7 7
 
8 8
 ./daydreamer --self-test